redis 报错”Please use EVAL instead of EVALSHA for debugging”

某个项目需求需要调试下 lua 代码,调试完成后,启动其他项目发现报错,项目一直在提示”Please use EVAL instead of EVALSHA for debugging”; 开始以为运维配置做了升级,运维回复最近并没有变更配置; 全局搜了下使用的 client 包发现没有这个你 error, 后转向 google, 终于有了两条可怜巴巴的结果,一看就是 redis 源码,一个位于https://download.redis.io/redis-stable/src/eval.c 另一条位于 https://github.com/pmem/pmem-redis/blob/master/src/scripting.c ( 因为版本不同,路径也不相同) 到此,问题基本定位,是 redis 服务器返回的错误,看来只能翻阅源码来解决这个问题;去 github 下载了源码;然后开始后续的求医问药模式; void evalShaCommand(client c) { if (sdslen(c->argv[1]->ptr) != 40) { / We know that a match is not possible if the provided SHA is * not the right length. So we return an error ASAP, this way * evalGenericCommand() can be implemented without string length * sanity check */ addReply(c, shared.noscripterr); return; } if (!(c->flags & CLIENT_LUA_DEBUG)) evalGenericCommand(c,1); else { addReplyError(c,“Please use EVAL instead of EVALSHA for debugging”); return; } }

代码只出现在这个位置,灵码给出的解释如下: 这个函数定义了一个名为 evalShaCommand 的函数,它没有返回值(void 类型)。该函数接收一个类型为 client 的指针参数 c,表示客户端连接对象。检查输入SHA的长度: if (sdslen(c->argv[1]->ptr) != 40) { /* … */ }

函数首先检查客户端请求中的第二个参数(c->argv[1])的字符串长度(通过 sdslen 函数计算)。如果长度不等于 40 字节,说明提供的SHA(可能是脚本的SHA1校验和)不是正确的长度,不可能与已存储脚本匹配。在这种情况下,函数执行以下操作: 发送一个预定义的错误回复给客户端(通过 addReply 函数),内容存储在全局变量 shared.noscripterr 中。 直接返回,结束函数执行,不继续处理此次请求。 这样做可以尽早返回错误,避免在 evalGenericCommand 中进行不必要的字符串长度检查。 判断是否处于调试模式:函数检查 client 对象 c 的标志位(flags)是否包含 CLIENT_LUA_DEBUG 标志。如果未设置此标志(即不在调试模式下),则调用 evalGenericCommand 函数处理请求,传入参数 c 和整数 1。 如果 CLIENT_LUA_DEBUG 标志被设置(客户端正处于调试模式),函数执行以下操作: 向客户端发送一个错误消息(通过 addReplyError 函数),提示用户在调试时应使用 EVAL 命令而非 EVALSHA。 返回,结束函数执行。 总结来说,evalShaCommand 函数处理客户端对 EVALSHA 命令的请求。它首先检查提供的SHA字符串长度是否为40字节,若不符合则立即返回错误。然后根据客户端是否处于调试模式来决定执行相应的操作:非调试模式下调用 evalGenericCommand 继续处理请求;调试模式下则向客户端发送错误提示,建议使用 EVAL 命令。

大模型给的提示是以为我们处于调试模式,原因基本定位; 昨天调试代码的时候使用了redis –ldb-sync-mode –eval ./a.lua 可能是服务器不支持 lua的 ldb 调试,异常退出后就一直 处于这个 debug 模式; 那么下一步就是想法让 redis server 关闭这个 debug 模式; 为此我们看看 c->flags & CLIENT_LUA_DEBUG 是那里赋值的; 全局搜索对应变量后,找到了这行 ,真是欣喜若狂啊 ; void ldbDisable(client *c) { c->flags &= ~(CLIENT_LUA_DEBUG|CLIENT_LUA_DEBUG_SYNC); }

接下来想到的是看看哪个 command 调用了这个函数; 再次定位到命令位于 void scriptCommand(client *c) {} // 这个函数中的如下部分

    if (!strcasecmp(c->argv[2]->ptr,"no")) {
        ldbDisable(c);
        addReply(c,shared.ok);
    } 

这个时候我想起了 redis-cli –help 本以为 这个 help 里面包含对应的关闭提示,结果试了半天还是失败; 于是再次请教大模型 if (c->argc == 3 && !strcasecmp(c->argv[1]->ptr,“debug”)) { if (clientHasPendingReplies©) { addReplyError(c,“SCRIPT DEBUG must be called outside a pipeline”); return; } if (!strcasecmp(c->argv[2]->ptr,“no”)) { ldbDisable©; addReply(c,shared.ok); } else if (!strcasecmp(c->argv[2]->ptr,“yes”)) { ldbEnable©; addReply(c,shared.ok); } else if (!strcasecmp(c->argv[2]->ptr,“sync”)) { ldbEnable©; addReply(c,shared.ok); c->flags |= CLIENT_LUA_DEBUG_SYNC; } else { addReplyError(c,“Use SCRIPT DEBUG yes/sync/no”); } }

这是 redis-cli 源码的一部分 , 根据代码帮我解决一个问题,输入redis-cli 后面跟什么参数才能关闭 ldb 的 debug 模式 就是让 ldbDisable© 执行

大模型给出了回复: 要通过 redis-cli 命令行工具关闭 ldb 的 debug 模式(即执行 ldbDisable©),您需要按照以下格式输入命令: redis-cli script debug no 这里,script debug 是命令主体,表示您要对 Lua 脚本调试功能进行操作。紧跟其后的参数 no 表示您希望关闭(disable)调试模式。根据源码中的逻辑判断,当接收到这样的命令时,程序会执行 ldbDisable© 函数,关闭调试,并向客户端回复一个确认信息(addReply(c, shared.ok)) 果然,在我执行完命令后,成功收到了服务端的响应 ok 此时再次运行本地项目,已经没有报错了; 通过这个问题的解决让我对 redis 又多了一些了解,使用不熟悉的命令尽量在本地多运行调试,使用前尽量了解后遗症; 同时也感受到了大模型功能的强大; 致敬中国的大模型,相信有一天一定能超过国外的这些模型; 在此,也感谢一下某个go 技术群中的大佬提供的思路和文档; https://redis.io/docs/latest/develop/interact/programmability/lua-debugging/ 当脚本自然终止时,调试会话将结束并以正常的非调试模式返回,在此同步模式下,在调试会话期间将无法访问 Redis 服务器,因此请谨慎使用。写的脚本不正常退出 会搞得云服务也没法访问(应该)抓紧重启将影响降到最小;

本文链接:参与评论 »

--EOF--

提醒:本文最后更新于 148 天前,文中所描述的信息可能已发生改变,请谨慎使用。

Comments