Java面试之Redis集群模式对比(哨兵/切片)

Redis哨兵模式仅实现主从故障转移,不解决容量与并发瓶颈;Cluster模式则提供数据分片、多主写入及自动故障转移,适用于大数据量、高QPS或需水平扩展场景。

Redis 哨兵模式 vs Cluster 模式:核心差异在哪

哨兵(Sentinel)和 Cluster 都是 Redis 的高可用方案,但解决的问题完全不同——Sentinel 只管「主从故障转移」,不解决容量和并发瓶颈;Cluster 是真正意义上的分布式方案,自带数据分片、多主写入和自动故障转移。

如果你的业务读写都在单节点扛得住,只是怕主库挂了,用 Sentinel 就够了;一旦数据量超 10GB、QPS 过万、或者需要水平扩展,就必须上 Cluster,否则加从库也扛不住写压力。

哨兵模式下常见连不上、切不成功的问题

哨兵本身不代理请求,客户端必须自己实现重定向逻辑。很多 Java 应用用 JedisLettuce 连哨兵时出问题,本质是配置或连接方式错了。

  • JedisSentinelPool 初始化时必须传全哨兵地址(至少 3 个),漏一个可能导致发现主节点失败
  • 哨兵配置里 sentinel monitor mymaster 127.0.0.1 6379 2 的法定票数(2)不能大于哨兵总数一半,否则无法触发 failover
  • 客户端缓存了旧主节点地址?Jedis 默认不自动刷新,得靠 JedisSentinelPool 的定时轮询,而 LettuceRedisSentinelClientConfiguration 支持更灵敏的监听机制
  • 网络分区时,哨兵可能误判主节点下线,建议把 down-after-milliseconds 设为 ≥ 30000,避免抖动误切

Cluster 模式 Java 客户端怎么选和配

Java 连 Redis Cluster 不能像单节点那样直连任意一个节点——客户端必须能解析 MOVED / ASK 重定向,并维护 slot 到节点的映射缓存。

  • Lettuce 是目前最推荐的选择:RedisClusterClient 自动完成拓扑发现、重试、重定向和连接池管理;JedisJedisCluster 虽然也能用,但异常处理弱、不支持响应式、连接泄漏风险更高
  • 初始化时只需提供一个可连通的集群节点(如 redis://10.0.1.10:7001),Lettuce 会自动获取全部节点信息;但首次建连耗时略长,别在高频接口里 new client
  • 务必关闭 autoReconnect = true(默认开启),否则网络抖动时大量重建连接可能打满 socket;改用 timeoutOptions 控制超时更可控
  • 注意 hash-tag:带 {...} 的 key(如 user:{1001}:profile)会被路由到同一 slot,否则多 key 操作(MGET)可能跨节点失败

Cluster 模式下哪些操作会直接报错

Cluster 不支持所有单机命令,Java 客户端调用时不会提前校验,而是发过去才返回错误,容易在线上突然炸开。

ERR This instance has cluster support disabled
ER

R CROSSSLOT Keys in request don't hash to the same slot ERR EXECABORT Transaction discarded because of previous errors ERR MOVED 12345 10.0.1.11:7002

这些错误对应的真实场景:

  • CROSSSLOT:一次请求含多个 key(如 MSET k1 v1 k2 v2),且没用 {} 对齐 slot → 改成单 key 分批,或确保 key 共享相同 hash tag
  • MOVED:客户端 slot 缓存过期或错乱 → Lettuce 默认自动重试并刷新拓扑,但若自定义了 ClusterTopologyRefreshOptions 关闭了自动刷新,就会卡住
  • EXECABORT:事务中某条命令语法错(如 INCR 用在 string 上),后续 EXEC 直接失败 → Java 里别依赖事务的原子性兜底,优先用 Lua 脚本
  • 没有 KEYSFLUSHALLSCAN 全局扫描命令的支持 → 真要扫,得遍历所有 master 节点分别执行 SCAN

Cluster 的 slot 分片是硬约束,不是“尽量均匀”,一旦 key 设计不合理,冷热不均、数据倾斜、迁移卡住都是常态。上线前务必用 redis-cli --cluster check 验证分片分布,而不是只看节点数量。