Redis Cluster在百万QPS下易失稳,因其Gossip协议通信开销随节点数超线性增长,导致带宽和CPU被“互相寒暄”占用;热点Key引发流量倾斜,Slot分片粒度固定加剧负载不均;建议主节点控制在12~24个以内,并采用本地缓存+Proxy预分片+Cluster分层卸压架构。

百万级 QPS 下,直接上 Redis Cluster 往往是错的起点——它不是不能扛,而是容易在 200+ 节点、热点 Key、Gossip 带宽饱和后突然失稳。
为什么 Redis Cluster 在百万 QPS 下会“吵起来”
Redis Cluster 的节点间通信靠 Gossip 协议,每个节点每秒随机发 PING 给若干节点,携带当前已知的集群拓扑(含所有 Slot 映射)。当节点数从 50 扩到 300,单条 PING 消息体积翻倍,消息总量呈超线性增长。你看到的 MOVED 重定向增多、CLUSTER NODES 响应变慢、部分分片 CPU 持续 95%,往往不是业务压力大,而是节点在“互相寒暄”占用了 30%+ 网络带宽和 CPU。
这不是配置问题,是协议设计边界。16384 个 Slot 的分片粒度,在热点商品 ID 或用户 session key 集中时,天然导致流量倾斜——某个主节点扛着 80% 请求,其他节点空转。
- 集群规模建议严格控制在
12~24个主节点以内,再往上扩容收益断崖下跌 - 避免用
user:12345这类连续数字 ID 作为 Key,否则 CRC16 取模后极易扎堆到同一 Slot - 不要依赖客户端自动重试
MOVED,生产环境必须用支持集群拓扑缓存的客户端(如 JedisCluster、Lettuce),且开启refreshPeriod主动轮询而非被动重定向
真正扛住百万 QPS 的三层缓冲结构
纯靠 Redis Cluster 横向堆节点是下策。有效方案是分层卸压:本地缓存挡掉 60%+ 热点读,Proxy 层做请求聚合与预分片,Redis Cluster 只承载最终不可绕过的原子写操作。
例如秒杀场景中:GET stock:1001 不直连 Redis,而是先查 Caffeine 本地缓存;未命中再走 Proxy;Proxy 收到 1000 个相同 stock:1001 请求,合并为 1 次 Lua 脚本调用,返回后广播更新本地缓存。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 本地缓存 TTL 设为
10s左右,避免一致性失控,但足够覆盖大部分重复请求 - Proxy 层必须实现 Key 预分片逻辑(如对
stock:{id}中的id再哈希一次),打散原生 CRC16 的热点倾向 - Redis Cluster 本身只存必要字段:库存值、用户购买标识、订单 token,不做任何业务逻辑计算
Lua 脚本 + Pipeline 是唯一能保原子性的组合
高并发下,GET + DECR + SET 三步必然竞态。必须用 Lua 封装成单次原子执行,且必须搭配 Pipeline 批量提交——否则单个 Lua 调用仍要等 RTT,QPS 上不去。
示例(Jedis):
String script = "local stock = redis.call('GET', KEYS[1]) if tonumber(stock) > 0 then redis.call('DECR', KEYS[1]); return 1 else return 0 end";
List<String> keys = Arrays.asList("stock:1001");
// 注意:这里不是单次 eval,而是 pipeline 包裹
Pipeline p = jedis.pipelined();
p.eval(script, keys, Collections.emptyList());
p.syncAndReturnAll(); // 一批执行,网络开销摊薄
- 脚本内禁止调用
redis.call('KEYS', ...)或redis.call('SCAN', ...),会阻塞整个事件循环 - 脚本长度控制在
1KB以内,过长会导致 cluster bus 消息膨胀,加剧 Gossip 压力 - 所有 Lua 脚本必须提前
EVALSHA注册,避免每次传输完整脚本体
集群故障时最易被忽略的降级开关
当某主节点宕机、从节点升主过程中,CLUSTERDOWN 错误会批量出现。此时若业务代码只是重试或抛异常,整个服务就雪崩了。
必须在客户端埋入可动态开关的降级策略:
- 配置中心下发
redis.cluster.fallback.enabled=true,触发后自动切到只读本地缓存 + 异步写 DB - 对非核心字段(如商品描述、图片 URL)允许
cache miss 后直接回源 DB,不强依赖 Redis - 监控
redis_cluster_down_total指标,超过阈值自动熔断写路径,防止故障扩散
真正的难点从来不在怎么搭集群,而在节点开始“吵架”、Slot 迁移卡住、某个分片 CPU 爆表时,你的系统是否还知道该怎么呼吸。

















