ZBLOG

cluseter模式,key被散列在不同的节点上,上述的lua脚本做得到原子吗

在 Redis Cluster 模式下,当 Key 被散列到不同节点时,Lua 脚本的原子性会受到限制。以下是关键分析:


1. Cluster 模式下 Lua 脚本的原子性限制

  • 单节点原子性:Lua 脚本仅在同一个节点上的 Key 上保证原子性(所有涉及的 Key 必须位于同一节点)。
  • 跨节点问题:如果脚本中的多个 Key 被分配到不同节点(即不同的哈希槽),Redis 会直接报错:
    
    CROSSSLOT Keys in request don't hash to the same slot
    

你的示例脚本(仅操作 my_key)如果该 Key 属于单个节点,则仍然保持原子性;但如果涉及多个跨节点的 Key,则会失败。


2. 强制保证多 Key 在同一节点的方法

(1) Hash Tag

使用 {} 强制让多个 Key 落到同一个哈希槽:

-- 示例:保证 key1、key2、key3 在同一节点
EVAL "redis.call('SET', KEYS[1], ARGV[1]); redis.call('EXPIRE', KEYS[1], ARGV[2])" 
     1 
     {user123}.my_key   -- Hash Tag
     "my_value" 
     3600

原理:Redis Cluster 只会计算 {} 内的字符串作为哈希值。

(2) RESTRICTED MODE (Redis >=7.0)

通过 EVAL_RO/EVAL_HA + SCRIPT FLUSH [ASYNC|SYNC] + CLUSTER SETSLOT API,可以更灵活地控制脚本执行范围(需手动管理)。


3. Cluster 下的替代方案

如果必须操作跨节点的 Key,且需要事务一致性:

(1) Redis Modules (如 RediSQL)

通过自定义模块实现分布式事务(但复杂度高)。

(2) Two-Phase Commit (2PC)

应用层模拟两阶段提交:

-- Phase1: Prepare
redis.call('SET', KEYS[1], ARGV[1], 'NX') -- NX表示仅当Key不存在时设置

-- Phase2: Commit/Abort based on other nodes' responses
if all_prepared_successfully then
    redis.call('EXPIRE', KEYS[1], ARGV[2])
else
    redis.call('DEL', KEYS[1]) -- Rollback
end

(3) WAIT + ACK (弱一致性)

写入主节点后等待副本确认:

SET my_key "my_value"
WAIT <numreplicas> <timeout> --等待副本写入完成才继续后续操作(非严格强一致)

4. CAP理论的权衡

  • 强一致性需求:考虑改用 etcd/ZooKeeper。
  • 最终一致性可接受:直接用 Redis Cluster + Hash Tag。

总结

Scenario Atomic? Solution
Single Key in Cluster ✅ Yes Native Lua
Multi-Key in Same Slot ({tag}) ✅ Yes Hash Tag
Multi-Key Across Slots ❌ No Use Redlock, WAIT, or external DB

你的示例脚本若仅操作单个 Key(或使用 Hash Tag),则 Cluster 下仍能保持原子性;否则需选择其他方案。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=23667

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?