我已阅读INCR文档here,但我无法理解为什么速率限制器2有竞争条件。
此外,文档中的the key will be leaked until we'll see the same IP address again
是什么意思?
有人可以帮忙解释一下吗?非常感谢你!
答案 0 :(得分:3)
您正在谈论以下代码,它在多线程环境中存在两个问题。
1. FUNCTION LIMIT_API_CALL(ip):
2. current = GET(ip)
3. IF current != NULL AND current > 10 THEN
4. ERROR "too many requests per second"
5. ELSE
6. value = INCR(ip)
7. IF value == 1 THEN
8. EXPIRE(ip,1)
9. END
10. PERFORM_API_CALL()
11.END
密钥将被泄露,直到我们再次看到相同的IP地址
如果客户端死亡,例如在执行LINE 8
之前,客户端被终止或机器已关闭。然后,密钥ip
将不会设置到期。如果我们再也看不到这个ip
,那么这个密钥将永远存在于Redis数据库中,并且会被泄露。
速率限制器2具有竞争条件
假设数据库中不存在密钥ip
。如果有10
个客户端,例如20
个客户端,请同时执行LINE 2
。所有这些都将获得NULL current
,它们都会进入ELSE
子句。最后,所有这些客户端都将执行LINE 10
,并且API将被调用超过10
次。
此解决方案失败,因为这是LINE 2
和LINE 3
之间的时间窗口。
正确的解决方案
value = INCR(ip)
IF value == 1 THEN
EXPIRE(ip, 1)
END
IF value <= 10 THEN
return true
ELSE
return false
END
将上述代码包装到Lua
脚本中,以确保它以原子方式运行。如果此脚本返回true
,请执行API调用。否则,什么也不做。