Redis如何利用Lua进行复杂的列表截取

秋磊同学_2873

秋磊同学_2873

2026-04-07

386人浏览

原创

redis中lrange无法条件过滤时,应使用eval执行lua脚本遍历处理:先用redis.call('lrange')获取列表,再在lua中条件筛选、限长保护、安全返回;禁用客户端过滤和频繁redis.call调用,大列表需预分类或分页处理。

redis如何利用lua进行复杂的列表截取

用 LUA 在 Redis 里截取列表,LRANGE 不够用时怎么办

Redis 原生 LRANGE 只能按索引范围取值,没法做条件过滤、去重、转换或分页跳过已读项。这时候必须上 EVAL 或 EVALSHA 执行 Lua 脚本——但别直接拼字符串,得靠 Lua 自己遍历处理。

常见错误是把整个列表 LRANGE 出来再在客户端过滤,既浪费带宽又丢掉原子性;或者在 Lua 里用 table.remove 频繁删中间元素,性能崩得飞快。

  • 优先用 redis.call('LRANGE', KEYS[1], 0, -1) 拿全量,再用 Lua 做逻辑(小列表安全)
  • 大列表(>5k 元素)必须加限长:先 redis.call('LLEN', KEYS[1]) 判断,超阈值就报错或降级
  • 避免在循环里反复调 redis.call,比如逐个 LINDEX 查——Lua 和 Redis 交互是同步阻塞的,一次脚本里最多 1–2 次外部调用

EVAL 脚本里怎么安全地“按内容截取”列表

比如要从 msg:queue 里取出所有 status="pending" 的消息 ID,且只取前 10 条——这没法靠原生命令链实现,必须 Lua 遍历 + 条件收集。

关键点在于:Lua 表是内存结构,不能直接当 Redis 列表用;所有写操作(如 LPOP)必须显式调用 redis.call,且只能发生在脚本末尾集中处理,否则破坏原子性。

  • 用 for i = 1, #list do 遍历 redis.call('LRANGE') 返回的 table,别用 ipairs(可能含 nil)
  • 匹配后存到 Lua 局部 table(如 result = {}),最后用 return result 输出,不要试图 redis.call('LPUSH', ...) 写回新 key
  • 如果需要“截取并删除原列表中已选元素”,必须两阶段:先收集索引,再倒序 LREM(正序删会偏移后续位置)
eval "local list = redis.call('LRANGE', KEYS[1], 0, -1); local res = {}; for i, v in ipairs(list) do if string.match(v, 'pending') then table.insert(res, v) end; if #res >= tonumber(ARGV[1]) then break end end; return res" 1 msg:queue 10

为什么 LUA 脚本里不能用 string.split 或 json.decode

Redis 内置 Lua 环境极度精简:只有基础库(string, table, math, struct),没有 lpeg、没有 cjson、没有 split 函数。所有 JSON 解析、字符串切分都得手写。

典型翻车场景:想从 "{id:1,status:pending}" 里抽 status,结果用 string.gmatch 写错模式,或没处理转义字符,脚本直接报 Lua ERR error running script。

  • 简单 KV 用 string.match(v, 'status:(%w+)') 足够,别碰复杂 JSON
  • 真要解析 JSON,请提前在客户端序列化成扁平字段(如 "id=1&status=pending"),再用 string.match 提取
  • 所有 string.match 必须加空检查:if val then ... end,否则 nil 传给 table.insert 会静默失败

性能临界点在哪?什么情况下该放弃 LUA 改用客户端处理

单次 Lua 脚本执行超过 5ms 就该警惕;超过 100ms 基本等于堵死 Redis 主线程。不是脚本逻辑慢,而是数据量导致的内存遍历开销不可控。

一个 LRANGE 返回 10 万条字符串,哪怕 Lua 只做 if v == ARGV[1] then ...,光内存拷贝和遍历就吃掉几十毫秒——这比网络传输还重。

  • 列表长度 > 1k 且需复杂条件时,优先考虑在写入端预分类(如用不同 key 存 pending/processing/done)
  • 如果必须运行时过滤,把条件下沉到业务层:用 SCAN + 游标分批拉,在客户端聚合,牺牲一点原子性换响应稳定
  • 永远检查 redis.call('LLEN', KEYS[1]) 结果,大于 500 就拒绝执行,返回明确错误(如 ERR list too large)而不是让脚本卡住

最常被忽略的是脚本缓存和复用:EVALSHA 比 EVAL 快 30% 以上,但得自己维护 SHA1 映射;另外,别在脚本里硬编码 key 名,用 KEYS[1] 传参,否则无法复用。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

2023.08.07

2135

5

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.23

3282

1

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

2023.10.13

1096

3

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

2025.09.10

3759

7

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.02

6399

3

scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.18

989

5

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.25

2960

5

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.03

1758

5

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

2704

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.9万人学习