Redis Lua脚本仅用于减少网络往返和保证原子性,不可替代数据库;应避免重复redis.call()、全量扫描、复杂计算及编解码,严格预热SCRIPT LOAD并容错fallback。

直接把数据库读写压力转给 Redis Lua 脚本,不是优化,是埋雷。Lua 脚本只能帮你「减少往返」和「保证原子性」,但无法替代数据库职责;真正该压给 Redis 的,是那些本就该在缓存层闭环的逻辑。
redis.call() 调用次数就是性能命门
每次 redis.call() 都会触发完整命令生命周期:解析、权限检查、键路由(集群下)、执行、序列化返回——哪怕只是重复读同一个 key 三次,也等于做了三次开销。
- 错误写法:
redis.call('GET', KEYS[1])出现 3 次 → 应改用local val = redis.call('GET', KEYS[1])缓存复用 - 循环里逐个查哈希字段:
for i=1,#ARGV do redis.call('HGET', KEYS[1], ARGV[i]) end→ 改用redis.call('HMGET', KEYS[1], unpack(ARGV)) - 用
GET + INCRBY模拟原子加 → 直接用INCRBY原生命令,它本身就是原子且零额外开销
EVALSHA 不预热 = 白忙活
EVALSHA 只省解析,不省执行。但很多人漏掉两个硬性前提:脚本必须提前 SCRIPT LOAD,且应用层必须缓存 SHA1 值并容错 fallback。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 启动时或首次调用前,用
SCRIPT LOAD发送脚本,拿到 SHA1 并存入本地缓存(如内存字典或 Redis 自身) - 调用
EVALSHA后必须检查返回值是否为NOSCRIPT;遇到就立刻SCRIPT LOAD再重试,不能直接 panic - Redis 集群下,
SCRIPT LOAD必须发到目标 key 所在 slot 的节点,连 proxy 或随机节点 load 无效
哪些操作坚决不该放进 Lua 脚本
以下三类操作 CPU 开销高、风险大、收益低,应第一时间从脚本中剥离,交还客户端或数据库:
-
KEYS或SCAN全量扫描:O(N) 不可中断,一跑就卡死主线程 - 纯计算循环,比如
for i=1,10000 do ... end:Redis 不限制循环次数,只靠lua-time-limit超时中断,极易拖垮服务 - JSON 解析、base64 编解码、正则匹配、
os.date()格式化时间:这些该由客户端做,脚本里只传结构化参数(如毫秒时间戳)
最常被忽略的一点:Lua 脚本不是万能胶。它适合「读-算-写」闭环在缓存层的小粒度逻辑(如限流计数、库存预扣、排行榜更新),但一旦涉及多 key 关联、复杂事务回滚、持久化一致性校验,就必须让渡给数据库。强行塞进 Lua,只会把 Redis 变成慢速数据库,还失去备份与查询能力。

















