【技术背景】
Redis 升级配置时,出现以下2种报错:
第一种报错如下:
org.springframework.data.redis.RedisSystemException: Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: CLUSTERDOWN The cluster is down
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:54)
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:52)
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:41)
at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44)
at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:42)
at org.springframework.data.redis.connection.lettuce.LettuceConnection.convertLettuceAccessException(LettuceConnection.java:270)
at org.springframework.data.redis.connection.lettuce.LettuceStringCommands.convertLettuceAccessException(LettuceStringCommands.java:799)
at org.springframework.data.redis.connection.lettuce.LettuceStringCommands.get(LettuceStringCommands.java:68)
at org.springframework.data.redis.connection.DefaultedRedisConnection.get(DefaultedRedisConnection.java:260)
at org.springframework.data.redis.core.DefaultValueOperations$1.inRedis(DefaultValueOperations.java:57)
at org.springframework.data.redis.core.AbstractOperations$ValueDeserializingRedisCallback.doInRedis(AbstractOperations.java:60)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:228)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:188)
第二种报错如下:
org.springframework.dao.QueryTimeoutException: Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Command timed out after 2 second(s)
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:70)
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:41)
at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44)
at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:42)
at org.springframework.data.redis.connection.lettuce.LettuceConnection.convertLettuceAccessException(LettuceConnection.java:270)
at org.springframework.data.redis.connection.lettuce.LettuceStringCommands.convertLettuceAccessException(LettuceStringCommands.java:799)
at org.springframework.data.redis.connection.lettuce.LettuceStringCommands.get(LettuceStringCommands.java:68)
at org.springframework.data.redis.connection.DefaultedRedisConnection.get(DefaultedRedisConnection.java:260)
at org.springframework.data.redis.connection.DefaultStringRedisConnection.get(DefaultStringRedisConnection.java:398)
at org.springframework.data.redis.core.DefaultValueOperations$1.inRedis(DefaultValueOperations.java:57)
at org.springframework.data.redis.core.AbstractOperations$ValueDeserializingRedisCallback.doInRedis(AbstractOperations.java:60)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:228)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:188)
at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:96)
at org.springframework.data.redis.core.DefaultValueOperations.get(DefaultValueOperations.java:53)
【原因猜测】
-
第一种报错是因为 Redis 在主从切换时,Redis 选举过程中出现短暂的不可用。
-
第二种报错是因为 Redis Client 向下线的节点继续发送请求,引起的连接超时。
【解决方案】
经过查询各种资料及本地调试,最终总结出来以下的解决方案。
-
针对第一种报错,在 Redis 集群的从节点下执行命令:cluster failover,即可把从节点提升为主节点,然后再下线从节点即可。
-
针对第二种报错,Redis Client 需要定期刷新客户端的连接信息。对于已经下线节点及时从节点列表中剔除,不让流量继续打到下线的节点。这个需要修改客户端源码。
【操作步骤】
第一步:Redis 从库下线,升级配置,并重启。
第二步:在所有的从库下执行 cluster failover 命令,把从库变成主库,把主库降为从库。
第三步:等待 60s,待所有微服务节点列表都从新的主节点查询后。
第四步:把新的 Redis 从库下线,升级配置,并重启。
此时,升级完成。
【Redis Client 刷新源码】
@Bean("lettuceRedisConnectionFactory")
public RedisConnectionFactory redisConnectionFactory() {
...
// 配置用于开启自适应刷新和定时刷新。如自适应刷新不开启,Redis集群变更时将会导致连接异常
ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
// 开启刷新
.enablePeriodicRefresh(true)
// 30s 重新拉取节点列表
.enablePeriodicRefresh(Duration.ofSeconds(30))
// 自适应刷新超时时间(默认30秒)
.adaptiveRefreshTriggersTimeout(Duration.ofSeconds(30))
// 开启自适应刷新
.enableAllAdaptiveRefreshTriggers()
.build();
ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
.topologyRefreshOptions(clusterTopologyRefreshOptions) // 拓扑刷新
.disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)
.socketOptions(SocketOptions.builder().keepAlive(true).build())
.build();
// 连接池
LettucePoolingClientConfiguration lettucePoolingClientConfiguration = LettucePoolingClientConfiguration.builder().commandTimeout(Duration.ofMillis(readTimeout))
.poolConfig(genericObjectPoolConfig())
.clientOptions(clusterClientOptions)
.build();
...
}
【总结】
1、接入各种中间件之前,必须对其进行高可用的调研及压测,在宕机场景下也能尽快恢复。
2、线上操作各种中间件之前,最好能在测试环境进行预演。
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » Redis无感升级配置
发表评论 取消回复