StackExchange.Redis 的 IDatabase.ScriptEvaluate 自动封装 SCRIPT LOAD/EVALSHA 流程,通过 SHA1 计算缓存复用脚本;要求脚本为纯字符串、参数严格使用 RedisKey[]/RedisValue[] 类型、KEYS 必须同槽,出错不抛异常而需检查 RedisResult.IsError。

用 IDatabase.ScriptEvaluate 执行 Lua 脚本最直接
StackExchange.Redis 不支持像 redis-cli 那样先 SCRIPT LOAD 再 EVALSHA 的两步流程,它把脚本加载和执行封装在 ScriptEvaluate 里——每次调用都会自动做 SHA1 计算、缓存和复用。只要脚本内容不变,后续调用走的是 EVALSHA 路径,性能没问题。
注意:脚本必须是纯字符串,不能含 C# 变量插值(比如 $"return {value}"),否则每次生成的 SHA1 都不同,失去缓存意义。
-
ScriptEvaluate返回RedisResult,需手动转换类型(如.AsInt()、.AsString()、.AsBoolean()) - 脚本里用
KEYS[1]和ARGV[1]访问传入的键与参数,C# 端通过keys和values参数传递 - 如果脚本只读,建议加
flags: CommandFlags.DemandMaster显式指定走主节点,避免从节点执行报错(尤其在 Redis Cluster 模式下)
传参时 keys 和 values 类型必须是 RedisKey[] 和 RedisValue[]
很多人卡在这一步:直接传 string[] 或 int 给 values,结果抛出 Invalid cast from 'System.Int32' to 'StackExchange.Redis.RedisValue' 这类异常。
根本原因是 StackExchange.Redis 对参数类型检查严格,不接受隐式转换。哪怕只是传一个整数,也得显式转成 RedisValue:
db.ScriptEvaluate(script,
keys: new RedisKey[] { "mykey" },
values: new RedisValue[] { 123L }); // ✅ 正确:long → RedisValue-
RedisKey和RedisValue是值类型,构造开销小,别用ToString()或new RedisValue("x")造对象 - 批量传参时,
values数组长度不能超过 1024(Redis 协议限制),超了得拆成多次调用 - 空字符串、
null值要小心:RedisValue.Null表示 Redis 的nil,而""是空字符串,语义不同
脚本出错时,RedisResult 的 IsError 为 true,但异常信息藏得深
脚本语法错、运行时报错(比如 KEYS 为空)、或 redis.call() 失败,都不会抛 .NET 异常,而是让 ScriptEvaluate 返回一个带错误状态的 RedisResult。
必须主动检查:result.IsError,再读 result.ToString() 才能看到类似 (error) ERR Error running script (call to f_...): @user_script:3: user_script:3: attempt to compare number with nil 的真实错误。
- 别依赖 try-catch 捕获脚本错误——它不会触发
RedisServerException - 开发期建议在脚本开头加
redis.log(redis.LOG_WARNING, "DEBUG: "..json.encode(ARGV))(需引用redis-json模块)辅助排查参数 - 生产环境禁用
redis.log,避免日志刷爆
Cluster 模式下,所有 KEYS 必须落在同一个哈希槽
这是最容易被忽略的硬约束。Redis Cluster 要求一个命令涉及的所有 key 必须属于同一 slot,否则 ScriptEvaluate 直接报 InvalidOperationException: No connection is available... 或更模糊的 ASK/MOVED 错误。
解决办法只有两个:
- 用
{}包裹 key 名强制哈希对齐,例如"{user}:1001"和"{user}:1002"会进同一个 slot - 脚本里只操作单个 key,或确保传入的
keys数组所有元素都带相同前缀(即相同 hash tag)
没有“跨 slot 脚本”这种东西——Cluster 架构决定了它不可能支持。


















