Redis Lua脚本执行不会乱序,因为其单线程模型下EVAL命令会独占主线程、串行执行所有脚本及内部redis.call(),100个并发请求也严格FIFO排队;破坏顺序感知的主因是超时中断、错误未兜底、参数错位或非确定性函数。

Redis Lua脚本在并发下天然按顺序执行,无需额外控制执行顺序——因为整个脚本运行期间,Redis主线程被独占,其他客户端命令全部排队等待。
为什么Lua脚本执行不会乱序?
Redis是单线程事件循环模型,EVAL或EVALSHA触发脚本时,会阻塞主线程直到脚本完全退出。这意味着:
- 没有“并发执行脚本”的概念:同一时刻最多一个Lua脚本在跑
- 脚本内所有
redis.call()调用按代码顺序串行执行,中间无法插入任何外部命令 - 即使100个客户端同时发
EVAL请求,Redis也只会逐个执行,顺序由网络到达+队列调度决定(FIFO)
哪些操作会破坏你对“顺序”的预期?
你以为的“顺序”可能被以下情况干扰:
- 客户端侧未控制并发:多个线程/协程同时调用
EVAL,但没做本地限流或排队,导致大量脚本堆积在Redis队列里,响应时间不可控 - 脚本内部用了
redis.pcall()吞掉错误后继续执行,逻辑分支实际跳过了某些关键步骤,看起来像“乱序生效” - 误把
KEYS和ARGV传错位置,比如KEYS[2]本该是锁key却读成了计数key,结果脚本逻辑错位 - 脚本里调用
redis.call('TIME')或os.time()这类非确定性函数,不同调用时间戳不同,导致条件判断结果不一致
如何验证脚本是否真按预期顺序执行?
最直接的方式是用redis-cli --eval配合简单计数器观察:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
local key = KEYS[1]
local val = tonumber(redis.call('GET', key) or '0')
redis.call('SET', key, val + 1)
return val + 1
然后并发跑:
for i in {1..100}; do redis-cli --eval counter.lua counter & done
最后检查counter值是否等于100——如果不是,说明有脚本因超时被SCRIPT KILL中断,或你启用了lua-time-limit且脚本卡在某处。
真正影响顺序感知的其实是超时与中断
Redis默认限制Lua脚本最长执行5秒(lua-time-limit 5000),超时后脚本会被强制终止,但已执行的redis.call()不会回滚。这会造成:
- 部分写入完成,部分没写,状态撕裂
- 后续请求看到“中间态”,误以为执行顺序异常
- 脚本中未用
redis.pcall()兜底时,一次redis.call()失败就直接退出,后面逻辑全跳过
所以比纠结“顺序”更关键的是:确认脚本是否总能完整跑完,以及失败时是否有明确返回和可观测日志。

















