先用redis-cli --latency排除网络延迟,再通过INFO commandstats对比cmdstat_eval/cmdstat_evalsha的usec_per_call(>5ms才可疑);若lua-time-limit触发需查Redis日志(SLOWLOG不记录中断脚本),且SLOWLOG中command字段仅截取前128字节、无上下文,应加注释fingerprint或传trace参数便于定位。

怎么确认是 Lua 脚本拖慢了 Redis?
别急着改脚本,先排除干扰项。Redis 是单线程模型,一个慢 Lua 会卡住所有请求,但真正瓶颈未必在脚本本身。
先运行 redis-cli --latency 看网络延迟是否异常;再用 INFO commandstats 查 cmdstat_eval 和 cmdstat_evalsha 的 calls、usec_per_call,如果平均耗时远超其他命令(比如 >5ms),才说明 Lua 是问题源。
注意:如果 lua-time-limit 被触发,脚本会被静默中断,SLOWLOG GET 不会记录它——此时必须查 Redis 日志(loglevel verbose)找 script execution time exceeded lua-time-limit 这类提示。
为什么 SLOWLOG 里看不到完整脚本?
SLOWLOG GET 返回的 command 字段只保留前 128 字节,且不标记是否被中断。你看到的可能是截断的 EVAL "return redis.call("GET", KEYS[1])",根本没法还原逻辑。
- 在脚本第一行加注释,例如
-- fingerprint:inventory_deduct_v3,Redis 会原样记入command字段(只要没被截断) - 避免直接用
EVALSHA,它只显示EVALSHA abcdef123456...,毫无上下文;改用SCRIPT LOAD+ 手动维护 SHA1 → 脚本名映射表 - 调用时把标识塞进
ARGV,比如传"trace=order_cancel_202607",确保它出现在日志里可检索
脚本内部哪些写法会让性能断崖式下跌?
核心问题是 redis.call() 开销远高于纯 Lua 计算。每次调用都走完整命令链路:解析、校验、路由(集群下)、执行——哪怕只是重复读同一个 key。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 把
redis.call('GET', KEYS[1])写三次?改成local val = redis.call('GET', KEYS[1])复用 - 循环里逐个
HGET?换成redis.call('HMGET', KEYS[1], unpack(ARGV))一次拿完 - 用
GET+SET模拟INCRBY?直接用原生命令,原子且高效 - 在脚本里做 JSON 解析、正则匹配、大数组排序?这些该由客户端干,Lua 只负责轻量逻辑
实测经验:redis.call() 超过 5 次,耗时就明显上扬;3 次以内较安全。
高频脚本必须用 EVALSHA 吗?
必须。每次 EVAL 都要传输整个脚本文本、做 SHA1 计算、序列化反序列化——对高频场景(如限流器、计数器),这部分开销可能超过逻辑本身。
正确流程:
- 启动时用
SCRIPT LOAD加载脚本,拿到 SHA1 - 后续全部用
EVALSHA <sha1> <keys> <args> - 服务重启后 SHA1 失效,需捕获
NOSCRIPT错误并自动重载
Redis 8.2+ 支持 SCRIPT FINGERPRINT 辅助调试,但生产环境仍得靠人工维护 SHA1 映射表——这是最容易被跳过的环节,一出错就退化成全量 EVAL,性能直接打骨折。

















