
1. 为什么单机 Redis 扛不住了才轮到集群上场先说个我自己的经历。早些年我维护过一套日活几十万的系统Redis 单机 16G 内存主从架构哨兵自动故障转移跑了一年多一直很安稳。直到某个大促前一个月运营活动把热点数据全部塞进缓存内存直接飙到 15G主从同步带宽也跟着吃紧。更麻烦的是一次机房抖动触发了哨兵切换切换那几十秒里缓存击穿直接打到数据库慢查询日志刷了整整三屏。那之后我才真正意识到单机 Redis 的瓶颈从来不只是内存不够了这么简单。它至少有三道坎是绕不过去的容量上限单机内存再大也有限而且内存越大RDB 持久化时的 fork 耗时、主从全量同步的网络开销都跟着涨单机 32G 以上就开始明显吃力。并发压力虽然 Redis 是单线程模型I/O 多路复用扛高并发没问题但所有请求都压在一台机器上网卡、CPU 总有一个先到极限。可用性边界主从哨兵只能解决单点故障后的自动切换但切换期间有短暂不可用而且从节点在故障期间没有分担读流量的能力多数配置下从节点只做备份。这个时候Redis 集群就该上场了。说得直白点Redis Cluster 就是把数据自动打散到多台机器上每台机器只存一部分数据同时通过主从副本保证每一片数据都有冗余再用 Gossip 协议互相感知状态把分片复制故障转移三件事一次性解决。这篇文章我会从原理讲到实战把搭建步骤、故障转移实测、常见的坑和排障链路都过一遍。如果你正准备从单机 Redis 迁移到集群或者正在准备面试、做架构设计调研这篇文章应该能帮你省不少时间。2. 先把三个核心机制搞清楚不然搭建完也是懵的Redis Cluster 本质上是一套去中心化的分布式方案没有中心节点所有节点都保存了完整的集群元数据。这套设计里有三个机制是理解一切后续操作的地基哈希槽、Gossip 协议、重分片。2.1 数据是怎么打散的16384 个哈希槽Redis Cluster 没有用一致性哈希而是用了一个更简单粗暴的模型固定 16384 个哈希槽。每个 key 通过CRC16(key) % 16384计算出一个槽位编号然后集群负责告诉你这个槽位归属于哪个节点。整个映射关系就是两层key - CRC16(key) % 16384 - slot0~16383 slot - 节点通过集群元数据查询所以一条数据在哪个节点上完全由它的 key 决定。你往集群里写一个 keyRedis 客户端会根据集群的 MOVED 重定向响应找到正确的节点。这里有个经典的面试题为什么是 16384 个槽而不是 65536 或者更多原因主要有三个心跳包要尽量小每个节点通过 Gossip 协议广播自己的状态其中要携带所有槽位的位图信息。16384 个槽对应 16384 bit也就是 2KB 的位图传播开销很低。如果改成 65536 个槽位图就是 8KB集群节点多的时候心跳包会明显变大。节点规模上限集群节点数一般不会超过 1000 个16384 个槽位足够分了再多槽位没有实际意义。槽位迁移的粒度槽是数据迁移的最小单位槽越多迁移粒度越细但管理和维护的成本也越高。16384 是在迁移粒度和管理成本之间的一个平衡点。这个设计决定了集群的一个核心特性集群的扩展和收缩本质上是槽位在不同节点间的迁移而不是数据的整体拷贝。2.2 节点之间怎么互相感知Gossip 协议集群里每个节点都会定期向其他节点发送 PING 消息消息里携带自己知道的其他节点状态信息。收到 PING 的节点会回复 PONG。这么一来节点间的状态信息就像八卦一样逐渐传遍整个集群。Gossip 协议带来的好处是去中心化没有 coordinator 单点。但它也有明显的代价状态收敛有延迟。一个节点挂了其他节点可能要过几秒甚至十几秒才能公认它挂了。这个延迟直接决定了故障转移的上限——你没法在毫秒级完成主从切换。每个节点还会维护一个cluster state用cluster_state:ok来表示集群是否健康。注意一个关键机制如果一个节点负责的哈希槽没有可用的从节点副本集群会进入 fail 状态拒绝写入。这是为了保证数据安全宁可不写也不要丢。我在实际运维中遇到过因为主节点挂了、从节点也挂了导致整个集群写入不可用的情况这点后面细说。2.3 主从复制和故障转移怎么配合集群模式下每个主节点可以挂一个或多个从节点。从节点通过REPLICAOF命令绑定主节点主从之间走的就是常规的 Redis 复制机制。但集群模式的故障转移和哨兵模式完全不同哨兵模式Sentinel 节点独立于 Redis 之外监控所有主从节点通过投票选出新主。集群模式从节点自己监控主节点状态。当从节点发现自己的主节点被标记为 FAIL通过 Gossip 协议达成多数共识它会发起选举向其他主节点请求投票。其他主节点会检查这个从节点的数据是否足够新复制偏移量然后决定是否投它一票。整个选举机制用一句话概括从节点想上位得先拿到超过半数主节点的同意票前提是自己的数据不能落后主节点太多。这一套保证了即使部分节点失联集群依然能通过大多数节点达成一致这是分布式系统里典型的 quorum 思路。3. 集群方案选型原生 Cluster、哨兵分片、还是中间件动手搭建之前先花点时间聊聊选型。因为我见过不少团队Redis 集群都搭好了才发现用的方案根本不匹配自己的场景最后要么推倒重来要么将就着用天天提心吊胆。3.1 三种主流方案的对比目前市面上可选的 Redis 集群化方案主要有三大类方案代表实现分片方式故障转移适用场景原生 Redis ClusterRedis 官方哈希槽16384集群内部自动选举大规模、对一致性要求高的场景哨兵 客户端分片Sentinel ShardedJedis / 一致性哈希客户端路由哨兵自动切换中小规模、不想改 Redis 语义的场景代理分片Twemproxy / Codis / Predixy代理层做路由依赖代理或哨兵业务不想感知集群细节客户端无感知3.2 我的选型建议抛开复杂的对比理论直接说结论基于我实际用过和调研过的经验新项目、从零开始、规模会增长无脑选原生 Redis Cluster。它虽然是有损的后面讲 multi-key 操作限制但它是官方方案社区支持最好运维工具最全而且云厂商的托管 Redis 集群基本都是基于这个模型。老项目、迁移成本高、业务大量使用 multi-key 操作可以认真考虑代理分片方案比如 Codis。Codis 用代理层把分片逻辑藏起来业务侧无感知还是像操作单机 Redis 一样。但要注意Codis 已经停止维护了长期来看有风险。集群规模小、主要为了高可用哨兵主从就够了不需要分片。很多团队 8G 内存都没用满就嚷嚷着要集群其实是伪需求。我这里只推荐一种答案如果你没有特别特殊的理由直接用原生 Redis Cluster。理由很简单它是唯一一个把分片、复制、故障转移全部内建在 Redis 自身里的方案没有额外组件没有额外的运维负担而且 Redis 官方从 3.0 开始已经维护了十几年生态最成熟。4. 从零搭建一个三主三从的最小集群这一节进入实操。我会用 Docker 在单机上模拟 6 个节点3 主 3 从方便你本地复现。生产环境多机部署的逻辑完全一样只是把 IP 换掉。4.1 环境准备和节点规划我的测试环境是 macOS装了 Docker Desktop。生产环境建议用 Linux可以直接用redis-cli原生命令操作。节点规划如下节点角色端口容器名redis-1master6381redis-cluster-1redis-2master6382redis-cluster-2redis-3master6383redis-cluster-3redis-4slave6384redis-cluster-4redis-5slave6385redis-cluster-5redis-6slave6386redis-cluster-64.2 编写配置文件并启动容器先准备好每个节点的配置。集群模式需要在redis.conf里开三个关键配置# 开启集群模式 cluster-enabled yes # 节点配置文件保存集群元数据不需要手动创建 cluster-config-file nodes.conf # 节点超时时间单位毫秒 cluster-node-timeout 5000 # 开启 AOF 持久化集群模式建议至少开一个持久化 appendonly yes我用一个脚本批量生成配置并启动容器。注意生产环境必须用固定 IP 或者可解析的主机名不能用容器 ID 相互连接for port in 6381 6382 6383 6384 6385 6386 do mkdir -p /tmp/redis-cluster/${port}/data cat /tmp/redis-cluster/${port}/redis.conf EOF port ${port} cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes appendfilename appendonly.aof EOF docker run -d \ --name redis-cluster-${port} \ --network redis-cluster-net \ -p ${port}:${port} \ -v /tmp/redis-cluster/${port}/data:/data \ -v /tmp/redis-cluster/${port}/redis.conf:/etc/redis.conf \ redis:7.0 \ redis-server /etc/redis.conf done这里有个容易踩的坑Docker 网络模式。如果你用默认的 bridge 网络容器之间通过容器名互相访问没问题但当你用redis-cli --cluster create创建集群时Redis 会自动检测 IP大概率会填成内部网段的 IP。如果这些 IP 在你的宿主机上访问不到集群创建后客户端就连接不上。我的解决方式让所有容器加入同一个自定义 network上面的redis-cluster-net并且创建集群时手动指定容器 IP 或宿主机可访问的 IP。这一步是本地 Docker 测试 Redis 集群最常见的坑。4.3 创建集群先进入任意一个容器docker exec -it redis-cluster-6381 bash然后用redis-cli自带的集群管理工具创建集群redis-cli --cluster create \ 172.18.0.2:6381 \ 172.18.0.3:6382 \ 172.18.0.4:6383 \ 172.18.0.5:6384 \ 172.18.0.6:6385 \ 172.18.0.7:6386 \ --cluster-replicas 1注意--cluster-replicas 1表示每个主节点配一个从节点。执行后redis-cli 会打印一份槽位分配方案确认无误后输入yes。还有一个更简单的办法如果你用的是 Redis 5.0 以上直接用redis-cli --cluster create --cluster-replicas 1后面跟节点列表就能自动完成分配不用先去手动设置主从关系。4.4 验证集群状态集群创建完成后用集群模式连进去看看redis-cli -c -h 127.0.0.1 -p 6381-c表示 cluster mode客户端会自动处理 MOVED 重定向。然后执行127.0.0.1:6381 cluster info cluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_slots_pfail:0 cluster_slots_fail:0 cluster_known_nodes:6 cluster_size:3再写个 key 验证一下127.0.0.1:6381 set name zhang - Redirected to slot [5798] located at 172.18.0.3:6382 OK看到这行重定向输出就说明集群工作正常。keyname的哈希槽算出来落在 6382 这个节点上客户端自动帮我们跳转过去了。至此一个最小可用的三主三从集群就搭好了。整个流程走下来不到十分钟如果你熟悉 Docker可能更快。5. 故障转移实测手动干掉主节点看集群怎么自愈集群搭好之后我习惯先做一次破坏性实验把主节点干掉观察集群的故障转移过程。这一步很重要因为能自动切换的集群才有资格上生产。5.1 准备确认当前主从关系先用集群节点命令看看现在的角色分配redis-cli -h 127.0.0.1 -p 6381 cluster nodes输出类似172.18.0.2:638116381 myself,master - 0 0 0 connected 0-5460 172.18.0.3:638216382 master - 0 172... 0 connected 5461-10922把输出里每个节点的master/slave角色记下来特别是 6381 这个主节点对应的从节点是谁。5.2 实战演示杀掉主节点挑一个主节点比如 6381直接暴力停掉docker stop redis-cluster-6381停掉之后等几秒观察集群状态。用 6382 节点查询redis-cli -h 127.0.0.1 -p 6382 cluster nodes你会看到 6381 的状态变成fail然后它的从节点假设是 6384状态从slave变成master并且槽位全部转移过去。完整过程大概是这样的时间线0-5s6381 失联其他节点通过 Gossip 收到 PFAIL 标记。5sPFAIL 在集群内传播超过半数主节点确认后升级为 FAIL。FAIL 确认后6381 的从节点6384发起了选举。选举通过后6384 晋升为主节点接管 6381 的全部哈希槽并开始接受读写请求。整个过程大概在 10~15 秒左右具体取决于cluster-node-timeout的配置。我在生产环境一般把cluster-node-timeout配成 10 秒故障转移差不多 20 秒内完成。对你没看错就是秒级不是毫秒级。Redis Cluster 不是为超低延迟切换设计的它牺牲了切换速度换取了架构的简单和去中心化。如果切换速度是你的核心诉求比如金融场景要求 RTO 在秒级以内那你可能要上云厂商的多可用区方案或者自己搭一套更复杂的仲裁机制。5.3 一个必须注意的坑脑裂和丢失窗口集群切换期间如果有客户端还在往 6381 写数据而这些数据还没来得及同步到 6384这部分数据会丢失。这就是主从切换的数据丢失窗口。Redis 集群有专门的机制来尽量避免这个问题叫cluster-replica-no-failover或者主从复制时的min-replicas-to-write参数。简单说你可以配置一个主节点必须至少有 N 个从节点在线才接受写入config set min-replicas-to-write 1 config set min-replicas-to-read 0这样当从节点全部失联时主节点会拒绝写入宁可不写也不能丢。当然这牺牲了可用性相当于把AP降级成了CP。怎么取舍取决于你的业务场景。5.4 把节点加回来并重新分配角色杀掉的主节点可以重新启动但它回来之后角色是什么执行cluster nodes看一下docker start redis-cluster-6381如果 6384 已经接管了 6381 的槽位那么 6381 回来后会作为 6384 的从节点加入集群而不是继续当主节点。Redis 集群的机制是一个主节点挂掉后如果它的从节点已经上位旧主节点回来后会自动变成新主节点的从节点重新开始复制数据。这个设计非常优雅免去了手动调整角色的问题。但要注意如果旧主节点回来时数据和新主节点差距太大会触发全量同步耗时取决于数据量。6. 集群模式下的常见坑从 MGET 到连接超时搭建只是开始真正让人头疼的是使用阶段。集群模式对业务代码的入侵比你想象的要大这一节我把高频踩坑场景列出来每一类后面都给排查思路。6.1 multi-key 操作在集群模式下的限制这是 Redis Cluster 对业务影响最大的一点如果多个 key 的哈希槽不在同一个节点上MGET、MSET、SDIFF、SUNION 这类跨 key 操作会直接报错。比如127.0.0.1:6381 mget name age (error) CROSSSLOT Keys in request dont hash to the same slot解决方式有两种用哈希标签hash tag把 key 写成{user:1001}:name、{user:1001}:age的形式。Redis 会只对花括号里的内容计算哈希槽这样两个 key 一定落在同一个槽位跨 key 操作就能用了。业务层自己聚合把 key 按槽位分组分组后并行请求或串行请求然后在客户端拼接结果。哈希标签这个机制好用但不是银弹。如果大量 key 都用了同一个 tag这些 key 会全部堆积在一个节点上形成热点。我在实际项目里见过有人把整个业务的 key 都写成{common}:*结果某个节点内存和 CPU 全部飙红。hash tag 要谨慎使用它其实是用数据分布不均换取功能完整的权衡。6.2 客户端连接报错CROSSSLOT 之外的 lettuc 超时很多人在 Spring Boot 里用 Lettuce 连 Redis 集群然后遇到一个经典报错Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Command timed out after 10 second(s)这个报错在集群模式下尤其容易发生原因通常是没有配置正确的节点地址Lettuce 连接集群需要传入所有种子节点的地址如果只传了一个节点而这个节点挂了Lettuce 就无法感知新的拓扑。集群拓扑刷新设置不当Lettuce 默认在命令执行失败时才重新读取集群拓扑如果集群发生了 failover而你的客户端因为连接池耗尽等原因没触发刷新请求就会一直超时。我的排查思路是三步走先确认集群本身健康redis-cli -c cluster info看cluster_state是不是ok。再看客户端配置确认spring.redis.cluster.nodes配置了多个节点地址不要只配一个。最后看连接池和超时参数Lettuce 虽然基于 Netty连接复用率很高但集群模式下建议调大validateConnection的频率或者开启topologyRefreshOptions让它定期刷新集群拓扑。一个生产可用的 Lettuce 集群配置Spring Boot参考spring: redis: timeout: 5s lettuce: pool: max-active: 16 max-idle: 8 min-idle: 2 cluster: refresh: adaptive: true period: 10sadaptive: true的意思是当 Redis 节点状态发生变化时比如 failoverLettuce 自适应刷新拓扑period: 10s是定期刷新的兜底。6.3 可视化工具连不上集群这是问得最多的问题之一。很多人用 Another Redis Desktop ManagerARDM连集群发现连不上或者只能看到一部分数据。原因在于不是所有Redis 客户端工具都支持集群模式。很多工具默认按单机模式连接连上单个节点后就只能看到落在该节点上的槽位数据其他节点的数据显示不出来。解决方案很直接用支持集群模式的可视化客户端RedisInsight 是官方出的对集群支持最好Another Redis Desktop Manager 新版也支持集群模式需要在连接配置里明确选择 Cluster 类型。命令行验证如果工具连不上先在终端用redis-cli -c连一下确认集群本身是通的再排查工具配置。顺便说一句集群模式下的数据可视化本来就是一件麻烦事。工具只能逐个节点展示槽位分布你没法像单机一样全库浏览。这是分布式架构的固有代价。6.4 数据倾斜和热点 key 问题集群模式没解决的一个经典问题key 分布不均匀。虽然哈希槽的设计让 key 大体均匀分散到各个节点但两种情况会导致数据倾斜key 前缀高度相似比如大量 key 叫user:1001:profile、user:1002:profile……这些 key 被 CRC16 计算后大概率是均匀的但某些特定前缀会让人为制造的哈希标签把大量 key 集中到一个槽位。热点 key比如爆款商品、明星用户访问量集中在一个 key 上而这个 key 只落在某一个节点里。热点 key 的解法通常是加一层本地缓存或者在业务侧做 key 的打散处理在 key 后面加随机后缀再分散到多个节点。但注意打散后读的时候要并发去读多个后缀 key逻辑复杂不少。7. 集群规模化的运维经验监控、扩缩容与数据迁移如果你的集群已经稳定跑了一段时间接下来要面对的就是如何让它长期可持续的问题。这一节聊几个我在运维实践中觉得最有价值的点。7.1 监控指标别只看内存和 CPU这五个才关键单机 Redis 我们习惯看 used_memory、hit_rate、连接数。集群模式多了很多分布式特有的指标我通常盯这五个指标来源报警阈值建议cluster_statecluster info非 ok 立即告警cluster_slots_assignedcluster info不等于 16384 立即告警cluster_known_nodescluster info不等于预期节点数告警cluster_sizecluster info不等于预期主节点数告警节点间网络延迟cluster nodesping/pong 历史超过 100ms 关注如果某个主节点的从节点数量为 0也要告警——前面说过这会导致该节点的槽位在故障时无法切换整个集群可能进入不可写状态。另外RDB 持久化和 AOF 重写的监控要单独做。集群模式下每个节点各自做持久化如果有多个节点同时触发 BGSAVECPU 和磁盘 I/O 可能瞬时拉高。建议给不同节点配置不同的save时间点错峰执行。7.2 扩容从三主三从加一台 Redis扩容的本质是把一部分槽位从现有节点迁移到新节点。具体做法先启动新节点以空节点身份加入集群docker run -d --name redis-cluster-6387 --network redis-cluster-net -p 6387:6387 redis:7.0 redis-server --port 6387 --cluster-enabled yes然后通过redis-cli --cluster add-node把它加进来redis-cli --cluster add-node 172.18.0.8:6387 172.18.0.2:6381注意第二个参数是集群里任意一个现有节点地址第一个参数是新节点地址。此时新节点已经加入集群但它是空的身上没有槽位。执行cluster rebalance让它自动从现有节点匀一些槽位过来redis-cli --cluster rebalance 172.18.0.2:6381这个过程就是reshard。在吞吐量高的集群里做 rebalance迁移数据时可能产生大量网络 I/O对性能有影响。我的经验是扩容操作尽量放在业务低峰期且一次只迁移少量槽位比如每次 500 个观察集群状态稳定后再继续。7.3 缩容和故障节点的移除缩容流程和扩容相反核心命令是--cluster del-noderedis-cli --cluster del-node 172.18.0.2:6381 节点ID但注意del-node 之前必须先把该节点的slot迁走否则 Redis 会拒绝删除。迁移槽位就可以手动执行--cluster reshard重难点在于你得手动指定目标节点和槽位范围不如扩容时 rebalance 自动。如果节点已经挂了没法正常迁移可以直接强制删节点。但挂掉的节点如果是主节点且它还有副本在集群里建议先把副本提升为master手动cluster failover再把挂掉的主节点从集群里移除。顺序反了会导致一连串问题。7.4 跨集群数据迁移别硬来先评估量级热搜词里有把数据从一个 CDH 集群迁移到另一个 CDH 集群这种需求集群数据迁移的思路本质是相通的。Redis 集群迁移有几种典型手段RDB 导入在源集群执行 BGSAVE 拿到 RDB再传到目标节点导入。这是最直接的方式但要求业务能接受短暂停机而且要处理 RDB 版本兼容问题。双写迁移业务层在源和目标同时写切读流量前逐步校验两边数据一致性。这是零停机的方案但工程量最大。redis-cli --cluster import如果源集群也是 Redis可以用官方命令做在线导入。不管哪种方案迁移的关键是先评估数据量级。经验法则总数据量在 10G 以内RDB 导入是最省事的100G 以上必须做双写迁移或者分批次导入否则一次性动作会变成运维事故。8. 调优配置与最佳实践把集群调到不闹心的状态最后分享一组我在生产环境沉淀下来的集群配置每一行都有它的理由。8.1 核心参数推荐# 节点超时时间短了容易误判长了切换慢 cluster-node-timeout 10000 # 每个主节点最少要有1个从节点在线否则拒绝写入 min-replicas-to-write 1 min-replicas-to-read 0 # 集群迁移时禁止写操作避免并发写导致的数据不一致 cluster-allow-replica-migration yes # 异步复制让主节点写操作的延迟不依赖从节点的 ACK repl-diskless-sync yes重点解释cluster-allow-replica-migration yes这个参数。它的作用是允许从节点过剩的主节点把多余的从节点自动迁移给没有从节点的主节点。我刚开始看到这个参数的时候觉得多此一举后来有一次一个主节点挂了发现它的从节点刚好在另一个节点那里闲置正是这个参数让集群自动调整了从节点分配避免了一个主节点无副本的情况。在数据安全第一的生产环境这个开比不开好。8.2 持久化策略集群模式下 AOF 优先单机 Redis 我们常开 RDB AOF 双持久化。集群模式下我建议以 AOF 为主appendfsync everysec。理由很实际RDB 触发 forkfork 期间内存翻倍大节点上尤其危险。集群节点多了以后RDB 文件全量同步会挤占网络带宽AOF 增量同步的流量小得多。但 AOF 也有坑AOF 重写同样要 fork。所以建议给每个节点设置不同的auto-aof-rewrite-percentage和auto-aof-rewrite-min-size错开各节点的重写时间。比如节点 6381auto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 128mb节点 6382auto-aof-rewrite-percentage 110auto-aof-rewrite-min-size 256mb不同节点错峰重写。如果你发现某个时刻所有节点的 CPU 同时升高大概率是 AOF 重写在打架。8.3 key 分布设计的通用规则结合前面讲的哈希槽和 hash tag我总结了一套 key 设计规范直接抄作业就行能用无 tag key 解决就绝不加 tag大多数 key 没有跨槽位操作需求保持原样让数据自然分散。确实需要关联性的 key用业务 ID 做 tag比如用户维度的{user_id}:profile、{user_id}:orders同一个用户的 key 必然落在一起而且不同用户分布在不同节点不会形成热点。严禁把所有 key 都塞进一个 tag等于把集群打回单机热点和数据倾斜立刻会找上门。高频热点 key 做好容量预估比如秒杀商品提前评估它的访问量会不会让单节点负载失衡必要时做本地缓存挡一层。这套规则看起来简单但我在代码评审里见过太多反面教材。有一个团队为了省事把所有用户数据都放在user:*下没有 tag跨 key 操作全部走客户端拆批反而比加 tag 更麻烦。标签不是越少越好也不是越多越好是按业务关联性精细控制。8.4 集群模式下的分布式锁热搜词里有 Redis 分布式锁集群模式下这是个高频需求。标准做法还是 Redlock 算法或者直接用 Redisson 的RLock。Redisson 对集群模式做了适配锁的加锁和解锁逻辑会自动处理槽位问题。使用 Redisson 时有一个容易忽略的细节watchdog 自动续期在高并发下会放大锁的负担导致锁的持有者一直续期不释放。建议根据业务最长执行时间设置leaseTime锁的自动过期时间不要完全依赖默认的 30 秒续期逻辑。另外集群模式下分布式锁有个天生弱点如果 master 加锁成功但在同步到 slave 之前就挂了slave 晋升为 master 后不认这个锁另一个客户端就能拿到同一把锁。Redlock 试图通过大多数节点来规避这个问题但业务上还是要做好幂等兜底。这不是 Redis 的 bug是分布式系统的一致性和可用性权衡。9. 最后再分享一个迁移踩坑经验写这篇文章的时候我正好回想起之前从单机 Redis 迁移到集群的一次真实经历最后借这个机会分享给大家。当时我们有个核心业务Redis 上有大量MULTI事务操作事务里读写了十几个 key。迁移到集群前我知道集群不支持跨节点事务但心存侥幸觉得事务里的 key 应该都能算到同一个槽。上线前两天做全量 key 分析一跑才发现事务里涉及的 key 分布到了三个不同节点。要改业务逻辑已经来不及了最后加班两天把所有事务改成了先查槽位再分批执行的伪事务才勉强保住上线计划。这个经历告诉我三件事也是我想留给你的三条经验迁移到集群前先做 key 级审计写一个脚本把你所有 key 的哈希槽算出来看看有没有跨节点访问的情况。这一步能在前面省掉 80% 的返工。事务和流水线pipeline要提前改造集群模式下管道操作需要按节点分组MULTI/EXEC跨槽位直接不可用这是硬限制不是配置能解决的。测试环境就要用集群很多团队测试环境用单机上生产才发现集群限制这是最贵的坑。从第一天起就用三主三从的 Docker 集群做测试成本极低。Redis 集群不是银弹它是一套用一致性换取容量和并发的交易。理解这笔交易你才能在做架构决策的时候心里有数。希望这篇文章能帮你少踩几个坑。