Redis Cluster环境下Lua脚本跨键访问非本地键报错求助
解决Redis Cluster中Lua脚本访问非本地key的报错问题
错误原因分析
你遇到的Lua script attempted to access a non local key in a cluster node错误,是Redis Cluster对Lua脚本的核心限制导致的:
- Redis Cluster的Lua脚本只能在单个节点上执行,脚本中所有需要访问的key必须提前通过
KEYS数组传入。 - Cluster会提前校验
KEYS数组中的所有key是否都属于当前节点的哈希槽(slot),如果脚本里动态生成key(比如你用第一个HGET的结果作为第二个key),Cluster无法提前确认这个key的位置,也无法保证它在当前节点,所以直接拒绝执行。
可行解决方案
方案1:客户端分步执行(最推荐)
既然你的需求是两次HGET的链式调用,完全可以把逻辑放到客户端来做,避开Cluster的脚本限制:
# 第一步:获取key-B(即value-A) KEY_B=$(./bin/redis-cli -c -h 192.168.33.203 -p 6000 HGET 0C559F3FEF368A8B53DE69C267423F0E '1') # 第二步:用key-B获取最终的value-B ./bin/redis-cli -c -h 192.168.33.203 -p 6000 HGET "$KEY_B" '1'
这种方式虽然是两次Redis请求,但逻辑简单、易维护,完全符合Redis Cluster的运行规则。
方案2:调整key设计,确保两个key在同一哈希槽(仅适用于可提前规划key的场景)
如果一定要用Lua脚本,你需要让KEYS[1](即0C559F3FEF368A8B53DE69C267423F0E)和动态获取的f3(key-B)属于同一个哈希槽。
实现方式是给两个key添加相同的hash tag,比如把key设计成{user:0C559F3FEF368A8B53DE69C267423F0E}和{user:xxx},这样Redis会根据{}内部的内容计算哈希槽,确保它们落在同一节点。
然后修改脚本,把两个key都传入KEYS数组(但这里的问题是你无法提前知道key-B,所以这个方案仅适用于你能提前确定key-B的场景):
-- 修改后的脚本(假设key-B已知) local f4=redis.call('HGET',KEYS[2],'1') ; return f4;
调用命令时传入两个key:
./bin/redis-cli -c -h 192.168.33.203 -p 6000 --eval ./x-userid-tag.lua {user:0C559F3FEF368A8B53DE69C267423F0E} {user:已知的key-B}
方案3:客户端先查询key-B的节点,再发送脚本(不推荐)
你可以先通过CLUSTER KEYSLOT命令获取key-B的哈希槽,再通过CLUSTER NODES找到对应节点,最后把脚本发送到该节点执行。但这种方式逻辑复杂,需要处理节点拓扑变化,维护成本很高,一般不推荐。
总结
最适合你的场景是方案1,客户端分步执行既简单又能避开Cluster的脚本限制,完全满足你的需求。
内容的提问来源于stack exchange,提问作者here




