解决Redisson在Kubernetes中连接旧Redis主节点的问题
问题背景
在Kubernetes集群中部署了Redis哨兵模式,版本为7.0.12。Java微服务使用Redisson客户端连接Redis集群,Redisson版本为3.17.5。当Redis发生主备切换后,Redisson仍然连接到旧的主节点IP,导致以下报错信息:
Unable to unfreeze entry: [freeSubscribeConnectionsAmount=0, freeSubscribeConnectionsCounter=value:133527:queue:0, freeConnectionsAmount=0, freeConnectionsCounter=value:267154:queue:0, freezeReason=SYSTEM, client=[addr=redis://0.0.0.0:6379], nodeType=MASTER, firstFail=0]
解决方案
升级Redisson版本
经过排查和测试,发现将Redisson版本从3.17.5升级到3.32.0可以解决问题。新版本的Redisson能够正确处理Redis主备切换,并自动更新连接到新的主节点。
进一步升级遇到的问题
为了确保使用最新的稳定版本,尝试将Redisson升级到3.44.0。然而,在启动应用时遇到了新的错误:
Factory method 'getRedissonClient' threw exception; nested exception is java.lang.NoClassDefFoundError: io/netty/channel/unix/DomainSocketAddress
分析与解决
该错误是由于Netty库版本不兼容引起的。io.netty.channel.unix.DomainSocketAddress
类是在Netty 4.1.58.Final及以上版本中引入的。因此,需要确保项目的依赖项中包含正确的Netty版本。
模拟主备切换
为了验证Redisson在主备切换时的行为,可以手动触发Redis主备切换并观察Redisson的响应。以下是模拟主备切换的步骤:
关闭当前主节点: 在Redis主节点的Pod中执行以下命令以关闭Redis服务:
kubectl exec -it <redis-master-pod-name> -- redis-cli shutdown
手动触发主备切换: 如果需要手动触发主备切换,可以在哨兵Pod中执行以下命令:
kubectl exec -it <redis-sentinel-pod-name> -- redis-cli -p <sentinel-port> sentinel failover <master-name>
其中<sentinel-port>
是哨兵监听的端口(默认为26379),<master-name>
是Redis主节点的名称。
kubectl exec -it <redis-sentinel-pod-name> -- redis-cli -p <sentinel-port> sentinel get-master-addr-by-name <master-name>
该命令将返回新的主节点的IP地址和端口。
总结
本次问题的根本原因在于Redisson版本过低,无法正确处理Redis主备切换。升级Redisson版本后,虽然遇到了新的依赖问题,但通过调整Netty版本得以解决。建议在选择第三方库时,尽量使用最新稳定版本以避免潜在的兼容性问题。通过模拟主备切换,可以更好地验证Redisson在实际环境中的表现。