lettuce默认不自动更新主节点地址,因其哨兵拓扑刷新机制被禁用;必须显式配置setrefreshperiod、setusedynamicmaster(true),并使用masterslave.connect()创建连接,否则持续连接已下线旧主。

为什么 Lettuce 连哨兵后不自动更新主节点地址?
默认情况下,Lettuce 的哨兵连接(RedisSentinelConfiguration)只在初始化时拉取一次拓扑,故障转移后不会主动刷新主节点地址——这会导致应用持续往已下线的旧主节点发请求,报 NOAUTH、READONLY 或连接拒绝错误。
根本原因在于:Lettuce 默认禁用哨兵拓扑自动刷新,必须显式开启并配好刷新策略。
- 必须设置
setRefreshPeriod(Duration),单位毫秒,建议 5000–10000 - 必须调用
setUseDynamicMaster(true),否则即使刷新也只查哨兵不更新主节点引用 - 若使用
RedisClient+StatefulRedisMasterSlaveConnection,需确保连接是通过MasterSlave.connect(...)创建,而非直接连单个节点
RedisSentinelConfiguration 和 MasterSlave 怎么配才生效?
仅配置哨兵地址不够,Lettuce 要求把哨兵配置和主从发现逻辑分两层组装。常见错误是把哨兵配置直接塞进 RedisURI 或漏掉 MasterSlave 的动态主节点委托。
- 哨兵配置用
RedisSentinelConfiguration,填入哨兵地址列表(如redis://192.168.1.10:26379),**不要填主节点地址** - 创建
RedisURI时用RedisURI.Builder.sentinel(),传入哨兵配置和 **master name**(即哨兵中配置的sentinel monitor <master-name></master-name>名称) - 连接必须走
MasterSlave.connect(client, codec, redisUri),它内部会监听哨兵事件并触发主节点切换 - 避免手动 new
StatefulRedisConnection—— 那样绕过了 MasterSlave 的拓扑管理
拓扑刷新失败时怎么快速定位?
最常见的现象是:哨兵已完成故障转移,但 Lettuce 日志里仍显示连接旧 IP,且无任何哨兵相关日志输出。这不是网络问题,而是刷新机制压根没启动。
- 打开 DEBUG 日志:
logging.level.io.lettuce.core=DEBUG,重点搜Refreshing topology和Discovered new master - 确认是否调用了
setRefreshPeriod:未设置则完全不刷新;设为 0 表示只初始化刷一次 - 检查哨兵 master name 是否拼写错误(区分大小写),错误会导致
No master found for name xxx - 如果用 Spring Boot,注意
spring.redis.sentinel.master必须与哨兵监控名一致,且不能和spring.redis.host同时配置(否则会跳过哨兵模式)
高并发下频繁刷新拓扑会影响性能吗?
不会。Lettuce 的拓扑刷新是异步轮询 + 哨兵 Pub/Sub 事件双驱动,刷新本身不阻塞业务线程,且默认只在检测到主节点变更时才重建连接。
- 刷新周期只是控制“多久查一次哨兵”,实际连接重建只发生在
master address changed事件触发后 - 连接重建有内置防抖:5 秒内重复变更只触发一次重连,避免抖动放大
- 如果哨兵集群本身不稳定(如网络分区),可适当加大
refreshPeriod到 15s,但不要关掉 - 务必关闭
setVerifyMasterAfterFailover(false)(默认 true),否则每次切换后额外发ROLE命令验证,增加延迟
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











