4
一旦到达限流的次数,redis不再执行incrby
一旦到达限流的次数,redis不再执行incrby
pr中代码冗余redis.call("INCRBY", KEYS[1], 1)
是为了减少条件判断的嵌套和增加可读性。
另附减少冗余代码redis.call("INCRBY", KEYS[1], 1)
的版本:
local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local current = tonumber(redis.call("get", KEYS[1]) or "0")
if current +1 <= limit then
redis.call("INCRBY", KEYS[1], 1)
if current == 0 then
redis.call("expire", KEYS[1], window)
return 1
elseif current+1 < limit then
return 1
else
return 2
end
else
return 0
end
PR里代码跟我原来代码作用完全相同呀
并且过了limit加和不加效果一样的
作用相同,但过了limit加和不加效果是不一样的,这会影响QPS。代码lua脚本总是执行incrby进行递增,incrby属于写操作;而PR中lua脚本在超过了limit之后,就不再执行incrby了,仅执行的是get,get属于读操作。这样就减少了写redis的写操作,提升了性能。
另附:两者benchmark测试
redis get vs incr redis get的qps redis incr的qps可见,一般情况下 ,读命令get 的qps高于 写命令incr
代码中lua vs 本次pr中的lua加载脚本
注:下面截图中 key_old 为代码中的key,key_new 为本次pr代码中的key
每秒最大允许100请求对比 每秒最大允许1000请求 对比 每秒最大允许10000请求 对比综上:减少了redis写操作,提升了qps。 注:在benchmark测试中,出现过极少量的写操作qps高于读操作的qps情况,属于测试的正常误差范围。
两脚本1.lua (代码中lua脚本)
local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local current = redis.call("INCRBY", KEYS[1], 1)
if current == 1 then
redis.call("expire", KEYS[1], window)
return 1
elseif current < limit then
return 1
elseif current == limit then
return 2
else
return 0
end
2.lua (本次PR中lua脚本)
local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local current = tonumber(redis.call("get", KEYS[1]) or "0")
if current == 0 then
redis.call("INCRBY", KEYS[1], 1)
redis.call("expire", KEYS[1], window)
return 1
elseif current+1 < limit then
redis.call("INCRBY", KEYS[1], 1)
return 1
elseif current +1 == limit then
redis.call("INCRBY", KEYS[1], 1)
return 2
else
return 0
end
非常感谢你的详细的测试,不过我仔细看了数据,我的观点如下:
这两种写法平分秋色,我也有些纠结。我的观点如下:
性能差异不大的情况下,简单更重要哈
@tylitianrui 这个PR我先不合哈