优化 Redis 中 ZRANGEBYSCORE 命令的执行时间。
2016-4-12 1:2:42
收藏:0
阅读:101
评论:1
我正在使用 Redis 排序集实现队列系统。我的 Lua 脚本如下:
local moveElement = function(source, dest , score, destscore)
local element = redis.pcall('ZRANGEBYSCORE', source, '-inf',score, 'WITHSCORES' , 'LIMIT' , '0' , '1')
if element ~= false and #element ~= 0 then
redis.call('ZADD' , dest , destscore , element[1])
redis.call('ZREM' , source , element[1])
end
end
local temp = moveElement(KEYS[2], KEYS[1] , ARGV[2])
local temp = moveElement(KEYS[3], KEYS[1] , ARGV[2])
local score= redis.call('ZRANGEBYSCORE', KEYS[1], '-inf',ARGV[1], 'WITHSCORES' , 'LIMIT' , '0' , '10')
if score ~= false and #score ~= 0 then
local i = 1
while i<=#score do
redis.call('ZREM', KEYS[1] , score[i])
redis.call('ZREM', KEYS[2] , score[i])
redis.call('ZADD', KEYS[3], ARGV[1] , score[i])
i=i+2
end
end
return score
这个 Lua 脚本在排序集中有 6K 个成员时需要 24 秒时间。
SLOWLOG GET 10
1) 1) (integer) 5937
2) (integer) 1385993558
3) (integer) 24446
4) 1) "EVAL"
2) "local moveElement = function(source, dest , score, destscore) local element = redis.pcall('ZRANGEBYSCORE', sourc... (937 more bytes)"
我的代码逻辑是:
我使用以下参数调用此脚本。
- [键数]
- foo1 排序集名称,具有 6k 个成员。
- foo2 排序集名称。
- foo3 排序集。其中从 foo1 到 foo2 的成员被移动。
- 当前时间戳。
- 当前时间戳 - 6 分钟。
有没有优化所需时间的方法?通过缓存 Lua 脚本或其他方式?
由于我总是从较低分数向较高分数获取值,使用 ZRANGE 取代 ZRANGEBYSCORE 会有帮助吗?
更多细节:
我正在尝试实现某种类型的队列系统。逻辑如下:
- foo1 包含成员,其分数是它们需要触发的时间戳。
- 每当需要在将来触发事件时,它会在 foo1 中放置,其得分为计划时间。
- 我的脚本从 foo1 中读取当前时间戳小于等于的所有成员(一个接一个),并将它们移动到 foo3。这是一次次完成的,并移动元素。此元素分配给某个工作者。 (已隐藏)
- 如果工作者完成了工作。它会从 foo3 中删除成员。
- 如果在 x 秒超时后成员未被删除 foo3。脚本会将其移回 foo1。以便它可以重新分配给其他工作者。
点赞
评论区的留言会收到邮件通知哦~
推荐文章
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
你发布的代码存在一些问题。以下代码为 Lua 代码(请不要发布带引号的字符串,会使代码难以阅读):
local moveElement = function(source, dest , score, destscore) local element = redis.pcall( 'ZRANGEBYSCORE', source, '-inf', score, 'WITHSCORES' , 'LIMIT' , '0' , '1' ) if element ~= false and #element ~= 0 then redis.call('ZADD' , dest , destscore , element[1] ) redis.call('ZREM' , source , element[1]) end end local temp = moveElement(KEYS[2], KEYS[1] , ARGV[2]) local temp = moveElement(KEYS[3], KEYS[1] , ARGV[2]) local score= redis.call( 'ZRANGEBYSCORE', KEYS[1], '-inf', ARGV[1], 'WITHSCORES' , 'LIMIT' , '0' , '10' ) if score ~= false and #score ~= 0 then local i = 1 while i<=#score do redis.call('ZREM', KEYS[1] , score[i]) redis.call('ZREM', KEYS[2] , score[i]) redis.call('ZADD', KEYS[3], ARGV[1] , score[i]) i=i+2 end end return score首先,在第 5 行,
element永远不会是false。我猜你想捕获一个错误,但在这种情况下,它将是一个带有err字段的表。对于后面的score也是同样的情况。接下来,你声明了两个本地变量
temp,但后面却没有使用它们。你的
while循环可以用for更好地表达:for i=1,#score,2 do redis.call('ZREM', KEYS[1] , score[i]) redis.call('ZREM', KEYS[2] , score[i]) redis.call('ZADD', KEYS[3], ARGV[1] , score[i]) end为什么在
moveElement中使用WITHSCORES?你没有使用它。除此之外,你能否更清晰地解释你想要实现什么,这样我才能帮你更进一步。此类操作肯定不应该需要 24 秒才能完成(除非你在运行过时的机器)。
编辑
这里有一个简化版本的脚本,结合了你之前告诉我内容:
local now = ARGV[1] local timed_out = ARGV[2] local pending_jobs = KEYS[1] local running_jobs = KEYS[2] local jobs local not_empty = function(x) return (type(x) == "table") and (not x.err) and (#x ~= 0) end -- 检查是否有任务超时 -- 如果是,则获取一条最早的任务并重新排队 jobs = redis.pcall( 'ZRANGEBYSCORE', timed_out, '-inf', timed_out, 'LIMIT', '0', '1' ) if not_empty(jobs) then redis.call('ZADD', pending_jobs, now, jobs[1]) redis.call('ZREM', running_jobs, jobs[1]) end -- 检查是否有任务需要执行 -- 如果是,则获取 10 条最早的任务并执行 jobs = redis.pcall( 'ZRANGEBYSCORE', KEYS[1], '-inf', ARGV[1], 'LIMIT', '0', '10' ) if not_empty(jobs) then for i=1,#jobs do redis.call('ZREM', pending_jobs, jobs[i]) redis.call('ZADD', running_jobs, now, jobs[i]) end end return jobs从这个脚本可以看出,它不应该需要长达 24 秒的时间。因此:
除非你能提供具有此问题的数据
.rdb,否则帮不了你更多。