资讯详情

资讯详情

Redis切片集群全解:16384个槽位背后的原理与运维实战

1. 切片集群到底解决了什么问题先聊一个我早期踩过的坑。某天线上一个 Redis 实例内存报警我看了一眼监控used_memory 已经逼近 30GB这个实例还承担着大量读写。当时的第一反应是加内存于是把机器从 32G 升到 64G结果不到两个月又满了。后来复盘才发现业务缓存 key 的增速远超预期单机内存再翻一倍也只是把问题往后推。真正要命的是这台机器 CPU 在高峰期也冲到 80% 以上就算内存无限大单线程的 Redis 处理能力也扛不住。这时候最合理的做法不是继续纵向扩容而是把数据分散到多台机器上让多台机器一起分摊读写压力——这就是切片集群的核心价值。在 Redis 官方给出的高可用方案里主从复制加哨兵解决的是“一个节点挂了业务还能继续”的问题但它没有解决“单节点的数据和压力太大”的问题。切片集群正好补上这块短板它把完整的 key 空间按照某种规则切分成多个分片每个分片由一个独立的 Redis 实例负责客户端根据 key 的哈希结果把请求路由到对应分片。每个分片的数据量变小了单实例的 CPU 和内存压力也变小了整体容量和处理能力可以水平扩展。Redis 切片集群主要有三种落地方式客户端分片、代理分片、官方 Redis Cluster。客户端分片就是在业务代码里自己算哈希把 key 映射到不同 Redis 实例这个方案最灵活但维护成本高一旦节点变化所有客户端都要改。代理分片比如 Twemproxy、Codis是在客户端和 Redis 之间加一层代理客户端无感知但代理本身会成为瓶颈也需要额外维护。官方 Redis Cluster 从 Redis 3.0 开始提供把分片逻辑、节点通信、故障转移内置到 Redis 本身是当前生产环境最主流的选型。如果你刚接触这个问题我建议直接聚焦官方 Redis Cluster。下面的内容全部围绕它展开包括槽位分配原理、节点通信机制、数据迁移流程、集群部署步骤、常见故障排查以及我在实际维护中积累的一些经验教训。文章会涉及一些配置项和命令但重点会放在“为什么这样做”上理解了原理很多问题不用背命令也能自己排查。2. 切片集群的核心设计16384 个槽位2.1 为什么是 16384 而不是更多Redis Cluster 采用虚拟槽分区整个 key 空间被划分为 16384 个哈希槽每个 master 节点负责其中一部分槽位。写入一个 key 时Redis 先对 key 计算 CRC16 校验和然后对 16384 取模得到这个 key 所属的槽位再根据槽位分配关系定位到具体节点。这个设计比一致性哈希更直观运维上也更可控。一致性哈希需要处理虚拟节点、数据倾斜、节点增减时的哈希环调整而槽位方案就是一张静态的表每个节点管哪些槽一目了然。槽位数量为什么选 16384官方给出的解释是CRC16 算法输出的值是 16 位理论上范围是 0 到 65535选择 16384 是权衡后的结果。从实际角度理解16384 这个数在集群规模不大时足够用而且它带来了两个好处。第一节点间心跳消息里用 bitmap 表示槽位分配信息16384 个槽位只需要 2KB16384 / 8 2048 字节如果换成 65536 个槽位bitmap 就要 8KB心跳消息变大网络开销成倍增加节点数量多时会很明显。第二槽位数量过大或者过小都不好太小会导致数据分布粒度粗某些热点 key 集中在一个槽里时难以打散太大则会让元数据膨胀迁移和同步也会变慢。对于绝大多数业务几千个分片节点已经很少见16384 个槽位绰绰有余。2.2 槽位和数据如何映射具体计算过程是这样的客户端或者任意一个集群节点收到 key 后先用哈希函数算出槽位然后查询槽位和节点的对应关系。这个对应关系不是靠中心化存储而是每个节点都保存一份完整的槽位映射表同时通过 gossip 协议互相同步。哈希计算有一个特殊规则需要记住如果 key 中包含花括号{}那么 Redis 只对花括号内的部分做哈希花括号外的内容不参与计算。这个设计叫 hash tag目的是让某些 key 强制分配到同一个槽位从而支持在同一个节点上执行 multi-key 操作。举个例子key1 {user:1001}:profile key2 {user:1001}:orders这两个 key 都只对user:1001做 CRC16计算结果一定相同所以它们一定会落在同一个槽位也就一定在同一台节点上。这样你就可以放心使用MGET或者 Lua 脚本同时操作这两个 key而不需要担心跨节点访问报错。但 hash tag 也是一把双刃剑。如果你把大量业务 key 都打上同一个 tag比如都用{user:1001}那这些 key 全挤在一个槽位里数据倾斜会非常严重。我一个朋友曾经把所有用户的订单 key 都设计成{user:id}:order的形式单看每个用户的数据确实落在一起高性能没问题但某个大用户的 key 数量非常多直接导致那个槽位所在节点的内存和 CPU 飙高。后来只能通过手动迁移槽位暂时缓解治标不治本。所以使用 hash tag 前一定要评估单个 tag 下的 key 数量上限。另外还有一个细节计算槽位用的是 CRC16不是 MurmurHash也不是别的哈希函数。CRC16 在 Redis 里的实现是对 0x1021 多项式的一个查表算法速度很快分布也足够均匀。如果你自己实现客户端一定要严格按照 Redis 官方文档中的 CRC16 实现来写否则槽位算不对路由就会出错。网上有不少客户端库已经实现了这套逻辑不建议自己从头造轮子除非你想研究协议。3. 节点的通信与故障转移机制3.1 心跳消息里到底传了什么Redis Cluster 的节点之间是通过 gossip 协议通信的没有中心节点。每个节点会定期向其他节点发送 PING 消息也会主动 PONG 回应别人的 PING。这里的核心点是心跳消息里不只是“我还活着”这个信息还携带了本节点已知的其他节点状态、槽位分配信息、以及集群的 epoch 等元数据。我最早以为集群通信很简单直到有一次排查一个“节点状态不一致”的问题才仔细研究了消息格式。每条 gossip 消息会带上发送节点认为的“集群全貌”它知道哪些节点在线、哪些节点被标记为 FAIL、每个节点的槽位范围是什么。因为每个节点都是通过不断交换信息来逐步收敛出同一个视图所以在一个节点刚刚发生故障时不同节点对故障的感知可能有先后差异这是正常的最终会在几个心跳周期内达成一致。心跳间隔由cluster-node-timeout控制。这个参数默认值是 15000 毫秒即 15 秒。如果节点 A 在超过cluster-node-timeout时间内没有收到节点 B 的任何消息A 就会认为 B 可能挂了开始标记 PFAILpossible fail主观下线。注意这里的关键词是“主观”因为 A 的消息可能只是网络延迟或丢包B 其实还活着。为了避免误判A 会把这个判断通过 gossip 消息传播给其他节点如果集群中超过一半的 master 节点都认为 B 已经 PFAILB 才会被标记为 FAIL客观下线此时才触发故障转移。3.2 从节点晋升的完整流程一个 master 节点被标记为 FAIL 后它的从节点会自动发起选举争取把自己提升为新的 master。这个选举过程类似于 Raft 算法的选举但不是完全照搬Redis Cluster 有自己的实现方式。具体流程是每个从节点会检查自己复制的 master 是否处于 FAIL 状态如果是它会先延迟一段时间这个延迟时间和从节点自身的复制偏移量有关复制越完整延迟越短然后向集群中所有 master 节点发送投票请求。收到请求的 master 会判断这个从节点是否有资格参选以及自己在这个选举周期内是否已经投过票。每个 master 在一个选举周期内只有一张票所以最终得票超过半数的从节点胜出成为新的 master。这里有个常见误区不是所有从节点都可以参选只有数据足够新的从节点才有资格。如果从节点与旧 master 的复制延迟过大它的数据可能不完整直接被选举也没用因为会丢很多数据。Redis Cluster 在选举时要求从节点的复制偏移量要满足一定条件具体可以看源码逻辑但运维层面你只需要知道让从节点尽可能跟上主节点是保障故障切换不丢数据的根本。还有一个运维上的点故障转移并不是秒级完成的。从发现故障到标记 FAIL到从节点发起选举再到选举成功并完成槽位接管整个过程通常在 15 秒到 30 秒之间。如果业务不能接受这么长的中断你需要考虑在客户端做本地缓存降级或者提前在架构层面做多集群容灾。我见过不少团队上线了 Cluster 就以为高可用万无一失结果故障发生时发现业务已经报错十几秒才意识到“高可用”不等于“零感知”。3.3 为什么要避免“脑裂”脑裂是分布式系统老生常谈的问题。在 Redis Cluster 中如果一个 master 节点网络异常被其他节点标记为 FAIL但它的进程还活着照样接收客户端请求而此时从节点已经升级为新的 master。如果旧 master 之后网络恢复就会形成两个节点同时对外提供同一份槽位服务的情况这就是脑裂。为了防止脑裂导致数据不可恢复Redis 提供了两个关键配置min-replicas-to-write和min-replicas-max-lag。前者表示一个 master 至少要有多少个健康从节点才允许写入后者表示从节点复制延迟的最大秒数。如果从节点数量不足或者延迟过大master 会拒绝写入。举个例子你设置min-replicas-to-write 1、min-replicas-max-lag 10意思是master 在写入前会检查自己至少有一个从节点连接正常且复制延迟不超过 10 秒。当网络分区发生时旧 master 与所有从节点断开它无法满足“至少有一个从节点”的条件就会拒绝写入这样就不会产生“旧 master 写入了一堆新数据但新 master 没有这些数据网络恢复后冲突无法解决”的问题。这个配置需要根据业务容忍度来调整。如果业务可以接受少量数据丢失你可以把min-replicas-to-write设为 0让旧 master 继续写入等恢复后再合并如果业务对数据一致性要求很高就设置成 1 或 2。我的建议是默认至少设置为 1尤其是金融、交易类业务宁可短暂不可用也不要让脑裂污染数据。4. 一次完整的集群搭建实操4.1 规划节点结构搭建 Redis Cluster 前先规划好节点角色和端口。以最简的 3 主 3 从为例6 个 Redis 实例跑在同一台机器上只是为了演示生产环境建议至少 6 台物理机或虚拟机主从尽量不要部署在同一台物理服务器上否则物理机宕机主从一起挂集群高可用就名存实亡。端口我习惯用 7000 到 7005其中 7000、7001、7002 为主节点端口7003、7004、7005 为对应从节点端口。注意 Cluster 模式还有一个总线端口默认是 Redis 端口加 10000比如 7000 的总线端口是 17000。这个端口用于节点间 gossip 通信防火墙一定要放行。每台机器上准备一个 redis.conf核心配置如下port 7000 daemonize yes protected-mode no dir /data/redis-cluster/7000 cluster-enabled yes cluster-config-file nodes-7000.conf cluster-node-timeout 15000 appendonly yes最关键的是cluster-enabled yes这代表以 Cluster 模式启动。cluster-config-file是节点自己保存集群元数据的文件不需要手动创建启动后会自动生成。如果这个文件丢失节点会认为自己不在集群中需要重新加入。所以我建议把节点数据目录和配置文件分离避免误删。4.2 启动实例并创建集群6 个实例配置好之后分别启动redis-server /path/to/redis-7000.conf redis-server /path/to/redis-7001.conf redis-server /path/to/redis-7002.conf redis-server /path/to/redis-7003.conf redis-server /path/to/redis-7004.conf redis-server /path/to/redis-7005.conf启动后可以先验证一下进程redis-cli -p 7000 ping返回 PONG 说明正常。接下来使用 redis-cli 的集群管理命令创建集群redis-cli --cluster create 192.168.1.10:7000 192.168.1.11:7001 192.168.1.12:7002 \ --cluster-replicas 1这里只填写了 3 个主节点地址--cluster-replicas 1表示每个主节点配 1 个从节点。但注意这个命令只靠 3 个地址没法自动分配从节点它要求你同时提供 6 个节点地址然后根据地址顺序自动分配主从关系。正确写法是redis-cli --cluster create 192.168.1.10:7000 192.168.1.11:7001 192.168.1.12:7002 \ 192.168.1.10:7003 192.168.1.11:7004 192.168.1.12:7005 \ --cluster-replicas 1执行后redis-cli 会展示一个分配方案比如主节点 7000 的从节点是 7004主节点 7001 的从节点是 7005主节点 7002 的从节点是 7003并询问你确认。输入 yes 后集群开始初始化每个主节点会分到 5461 个槽位16384 / 3 ≈ 5461从节点开始同步主节点数据。这个命令执行完毕你就拥有了一个 3 主 3 从的切片集群。验证集群状态redis-cli -p 7000 cluster info redis-cli -p 7000 cluster nodescluster info里看cluster_state:ok代表集群健康。cluster nodes会列出所有节点的 ID、角色、槽位范围以及主从对应关系。4.3 槽位分配不均怎么办有时候创建集群时并没有均匀分配槽位或者你想手动画分槽位可以使用reshard命令。比如把 100 个槽位从节点 A 迁移到节点 Bredis-cli -p 7000 --cluster reshard 192.168.1.10:7000这个命令是交互式的它会问你要迁移多少个槽位接收槽位的节点 ID 是哪个要从哪些节点迁出槽位如果不想交互也可以直接用--cluster-from和--cluster-to指定redis-cli -p 7000 --cluster reshard 192.168.1.10:7000 \ --cluster-from 源节点ID --cluster-to 目标节点ID \ --cluster-slots 100 --cluster-yes执行迁移时Redis 会先把源节点上对应槽位的 key 逐个复制到目标节点复制完成后在源节点删除这些 key再把槽位的归属关系切换为目标节点。这个过程对客户端是缓慢感知的因为迁移期间访问这些 key 时会返回 ASK 重定向客户端需要跟随重定向到目标节点访问。这里有个实战经验迁移槽位时如果源节点内存很大迁移过程中的 key 复制会占用大量网络带宽和 CPU建议在业务低峰期操作并且可以控制迁移速率。Redis 6.2 之后支持了cluster-allow-replica-migration等相关参数但最直接的方式还是分批手动迁移不要一次迁几千个槽位。5. 客户端如何与切片集群交互5.1 MOVED 与 ASK 重定向Redis Cluster 的客户端要能正确处理两种重定向MOVED 和 ASK。MOVED 发生在客户端请求的 key 所在槽位不在当前节点管辖范围内。比如你连接 7000 节点执行GET foo7000 节点算完槽位后发现自己不管这个槽位就返回错误(error) MOVED 1234 192.168.1.12:7002意思是你要找的槽位 1234 在 192.168.1.12:7002 上请去那里访问。一个聪明的客户端会缓存这个槽位信息下次直接访问正确节点不会每次都走一次重定向。ASK 发生在槽位正在迁移的过程中。当源节点准备把槽位 1234 迁移到目标节点时如果客户端访问源节点上属于这个槽位的 key源节点发现这个 key 已经被迁移走了就返回 ASK 重定向。和 MOVED 的区别是ASK 只是针对当前 key 的一次性重定向客户端不应该缓存“槽位 1234 在目标节点上”这个信息因为迁移还没完成后续 key 可能还在源节点上。我早期用命令行工具 redis-cli 测试时因为 redis-cli 默认不会自动处理 MOVED经常以为自己连错了节点。其实redis-cli -c开启集群模式后就会自动跟随重定向redis-cli -c -p 7000使用集群模式时执行跨槽位多 key 命令才会报错因为它要求所有 key 必须哈希到同一个槽位。5.2 客户端库选型的几个坑生产环境我强烈建议使用官方推荐的客户端库比如 Java 的 Lettuce 或 JedisCluster、Go 的 go-redis。不同客户端对集群的适配程度差异很大下面说几个关键点。第一连接池策略。有些客户端默认每个节点一个连接池有些默认共享连接池再通过路由选择节点。如果你的业务热点 key 非常集中共享连接池可能导致单个节点连接数过高而其他节点连接空闲。我踩过一次 go-redis 的坑默认的 ClusterClient 在每次命令时都会计算节点热点 key 全部打到同一个节点连接池上限设得不够导致排队阻塞。后来调整了连接池大小同时用 hash tag 把热点打散问题才缓解。第二重定向处理。合格客户端必须在收到 MOVED 后更新本地槽位缓存收到 ASK 后重新路由当前命令。如果你自己写客户端一定要实现这两套逻辑特别是 ASK 的处理很多初级实现会把 ASK 当成 MOVED 处理导致迁移期间数据访问异常。第三跨槽位事务与 Lua。官方 Cluster 不支持跨槽位的 multi-key 操作除非所有 key 落在同一个槽位。Lua 脚本也一样脚本中涉及的 key 必须属于同一节点否则会报 CROSSSLOT 错误。这是设计限制不是 bug业务建模阶段就要避免对多个用户的数据做聚合操作。5.3 直连模式与代理模式的选择现在的 Redis 客户端大体有两种集群接入模式直连模式和代理模式。直连模式下客户端直接与每个节点通信性能最高但客户端要维护槽位映射节点故障和迁移时也要处理重定向。代理模式例如 Redis Enterprise 的 proxy或者第三方工具客户端连接代理代理转发请求客户端无需感知集群内部变化但多一层网络转发延迟略高。如果业务读多写少且对延迟极其敏感我建议直连。如果团队里有很多业务线共用一套集群又不想每个业务都处理集群细节代理模式更省心。Redis 6 以后官方对代理模式没有原生支持但 codis 等旧方案依然有存量使用。我的态度是新项目一律官方 Cluster 直连代理只在历史包袱大的场景使用。6. 扩容、缩容与数据迁移实战6.1 新增主节点并迁移槽位假设现在集群 3 个主节点内存使用率都到了 70%需要扩容到 4 个主节点。步骤分两步加入新节点迁移部分槽位过去。第一步准备一台新机器启动一个 Cluster 模式的 Redis 实例端口 7006。然后用以下命令把它加入集群redis-cli -p 7000 --cluster add-node 192.168.1.13:7006 192.168.1.10:7000第一个地址是新节点第二个地址是集群中任意一个现有节点。执行后新节点会以 master 身份加入集群但此时它不拥有任何槽位需要手动迁移。第二步查看新节点 IDredis-cli -p 7000 cluster nodes | grep 7006拿到 ID 后执行 reshard把一部分槽位从旧的某个或某几个主节点迁到新节点。目标槽位数量可以根据新机器内存规划比如现在总槽位 16384要 4 个主节点均分每个节点应该有 4096 个槽位那么新节点需要接收大概 4096 个槽位源节点可以选旧的 3 个主节点每个迁出约 1365 个。迁移过程耗时取决于迁移的 key 数量和单个 key 大小。如果一个大 key 是几十 MB迁移时会整块复制阻塞时间较长。我建议在迁移前用redis-cli --cluster rebalance自动平衡它比手动 reshard 更智能但要注意 rebalance 可能会在多个节点之间同时产生迁移流量最好在低峰期执行。6.2 添加从节点增强可用性只加主节点不加从节点集群在数据高可用上仍然有风险新主节点一旦宕机它负责的槽位就没有从节点接管客户端访问这些槽位时会直接失败。所以每加一个主节点至少要加一个从节点。添加从节点的方法redis-cli -p 7000 --cluster add-node 192.168.1.13:7007 192.168.1.10:7000 --cluster-slave --cluster-master-id 新主节点ID这个命令把 7007 节点作为指定主节点的从节点加入集群。加入后从节点开始全量同步主节点数据同步期间不要急于对外提供服务等同步完成再观察集群状态。从节点数量也不是越多越好。每个从节点都在复制主节点的全量数据多一个从节点就多一份内存和带宽消耗。一般 1 到 2 个从节点足够再加更多只是浪费资源。如果担心跨机房容灾可以优先考虑主从分布在不同机房或不同可用区而不是在一个机房堆多个从节点。6.3 缩容时千万注意的顺序缩容比扩容更容易出问题。我见过有人直接停掉一个 master 节点结果它负责的槽位变成无人管辖集群返回 CLUSTERDOWN所有相关 key 不可用。正确做法是先把该节点负责的槽位全部迁移出去确认槽位为 0再从集群中移除节点。移除节点的命令redis-cli -p 7000 --cluster del-node 192.168.1.10:7000 节点ID这个命令会检查节点是否还有槽位如果有会拒绝移除。所以顺序一定是先 reshard 迁走所有槽位再执行 del-node。如果是从节点没有槽位可以直接 del-node但最好先确认没有复制偏移量落后过多否则数据丢失会影响主节点的故障切换能力。缩容还有一个小坑如果集群里有多个 master 节点共享某些备份数据或者哨兵监控缩容后要同步更新监控平台、客户端配置、DNS 解析避免健康检查误报。7. 生产环境常见问题排查实录7.1 集群状态变成 FAIL 的排查思路当cluster_state不是 ok 而是 fail 时最常见的原因是某个 master 节点及其所有从节点同时不可用导致有一部分槽位没有可用节点。此时整个集群会拒绝所有读写请求返回 CLUSTDOWN 错误。这个行为是故意设计的目的是避免读到不一致的数据但很多业务方在第一次碰到时会惊出一身冷汗。排查步骤我一般按以下顺序先看cluster nodes找出哪个节点是 FAIL 或 PFAIL。登录对应机器看 Redis 日志和系统日志确认是进程崩溃、宕机还是网络分区。如果只是网络抖动导致误判通常不需要人工干预等cluster-node-timeout过了之后节点会重新加入状态自动恢复。如果是进程挂了尽快启动进程让它重新加入集群。如果是从节点挂了也要尽快恢复否则主节点一旦再挂就会触发 FAIL 状态。如果是多机房部署还要重点检查机房之间的网络质量。我曾经遇到一个集群频繁出现节点 PFAIL 然后又自动恢复的情况最后发现是交换机端口丢包率偏高导致心跳消息丢失严重。这类问题单纯看 Redis 日志很难定位需要结合网络监控和心跳超时统计来判断。7.2 数据倾斜和热点问题的应对切片集群虽然让整体数据分布更均匀但热点 key 依然存在。比如某活动的爆款商品、某个大 V 的粉丝列表访问量可能是普通 key 的上百倍。这些 key 无论落在哪个槽位都会让对应节点压力巨大。处理手段通常有三种第一热点 key 加随机后缀。比如原本 key 是product:123你可以拆成product:123:0、product:123:1到product:123:9这 10 个 key分别存到不同槽位读取时随机取一个。这个方案需要在业务代码里做逻辑拆分适合 value 可以冗余的场景。第二本地缓存兜底。在应用服务器上加一层热点 key 的本地缓存比如 Caffeine 或 Go 的 freecache过期时间设置足够短几秒钟到十几秒。对于热点极高的 key这个方案能显著降低 Redis 压力。第三hash tag 慎用。有些团队为了让某些 key 能批量操作把所有相关信息都打上同一个 tag结果反而制造了热点。如果确实需要 hash tag尽量把 tag 的粒度控制在单个用户或单个业务域内并确保每个 tag 下的 key 总量不会过大。7.3 慢查询和阻塞操作的影响范围Cluster 模式下一个节点的慢查询不会直接拖垮其他节点但如果慢查询发生在 master 上它的从节点复制也会受到影响。比如你在 master 上执行KEYS *这个命令会阻塞 Redis 单线程事件循环相当长时间期间所有命令都排队。从节点同样在执行复制的命令流主节点阻塞会直接导致复制延迟增加一旦延迟超过cluster-node-timeout可能触发从节点发起选举造成不必要的故障切换。所以在我维护的集群里KEYS命令是禁止上生产的一律用SCAN代替。SMEMBERS如果集合很大也应改成SSCAN分批取。HGETALL同理大 hash 要警惕。还有一种隐蔽的阻塞操作是DEL一个大 key比如一个 value 有几百万个元素的集合删除时会连续释放内存导致阻塞。这时候建议用UNLINK它就是为这件事设计的异步删除命令Redis 会先把 key 从命名空间摘除再在后台线程逐步释放内存。7.4 集群节点时间不同步的问题很多人忽略这一点集群节点之间要求时钟尽量同步否则心跳超时判断和选举投票会出问题。如果某个节点系统时间和别的节点差了几十秒它的 PING 消息携带的时间戳会让其他节点误判。特别是故障转移时从节点等待延迟和投票窗口依赖于时间时钟偏移严重时可能导致选举超时或重复投票。生产环境必须配置 NTP 或 chrony 时间同步。这不是可选项是必选项。我见过一个集群因为某台云主机时间漂移了 5 分钟每次主节点故障切换都会失败最后排查半天才发现是时间问题。7.5 常见问题速查表现象可能原因解决思路写入报 CLUSTERDOWN某槽位无可用 master恢复故障节点或迁移槽位报 MOVED 错误客户端未自动跟随重定向开启客户端集群模式或更换客户端报 ASK 错误槽位迁移中客户端应临时重定向勿缓存执行多 key 命令报 CROSSSLOTkey 不在同一槽位使用 hash tag 或拆分命令某节点内存明显偏高hash tag 使用不当调整 tag 粒度或单独拆分故障切换后数据丢失从节点复制延迟过大检查主从复制限制写入条件集群状态反复 PFAIL网络丢包或时间不同步检查网络质量和系统时钟主从切换后旧主自动重新加入网络分区恢复确认脑裂配置防丢数据8. 我的一些运维习惯建议最后聊几个实操层面的习惯覆盖你真正把集群跑起来之后会遇到的日常场景。第一个习惯把监控做细。切片集群的监控不能只看used_memory和cpu要按节点维度看。每个主节点的内存、命中率、慢查询数、复制延迟、连接数都建议独立监控和告警。因为集群的瓶颈往往不是整个集群而是某个特定节点。我遇到过的情况是整体集群 CPU 不到 10%但某个主节点已经接近 100%因为热点 key 全部打在那里。如果只做了集群聚合监控这个问题会被掩盖。第二个习惯定期演练故障切换。不要等到真的宕机了才看从节点能不能晋升。找一台低峰期机器手动redis-cli -p 7000 debug sleep 30模拟主节点阻塞或者直接kill掉主节点进程观察集群多久恢复、客户端是否报错、数据有没有丢失。演练一次至少能发现监控盲区和客户端配置问题。第三个习惯内存碎片和过期 key 的治理。Cluster 模式下每个节点是独立的 Redis 实例碎片率、过期 key 扫描也都是各节点独立的。你可以通过redis-cli --cluster info查看每个节点的内存状况定期用scan配合OBJECT idle找出长期未访问的 key和业务方确认是否可清理。不要指望一个节点清理内存其他节点会自动均衡Redis Cluster 没有自动均衡数据的后台任务。第四个习惯配置变更要滚动执行。Cluster 节点多如果改maxmemory-policy、cluster-node-timeout这类参数逐个节点修改并重启避免一次性把整个集群重启。重启一个节点后等集群状态稳定再重启下一个。千万别同时重启多个主节点否则可能触发多槽位同时无主集群直接进入 DOWN 状态。第五个习惯客户端重试机制必须有。节点故障切换期间客户端可能连到一个正在选举的节点或者收到暂时性的连接错误。成熟的客户端库都有重试策略但要确认重试不会把雪球滚大。建议设置合理的重试次数和退避时间比如最多重试 3 次退避 100ms 起步。同时重试时不要盲目把请求发给所有节点先依赖槽位缓存让 MOVED/ASK 逻辑来引导路由。我实际跑切片集群这几年最大的感受是Redis Cluster 本身是一个相当成熟、稳定的组件大部分线上事故并不是组件 bug而是使用方对槽位迁移、故障切换、热 key 分布理解不够或者操作顺序错误。把原理吃透把演练常态化这个架构可以支撑大多数中大规模业务。如果你正准备上切片集群先从 3 主 3 从开始不要一上来就搞几十个节点。先把扩容、迁移、故障切换跑一遍确认客户端行为符合预期再逐步扩大规模。这样踩坑成本最低也能让你对集群的脾气摸得更清楚。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →