RedisCluster集群模式下master宕机主从切换期间Lettuce连接Redis无法使用报错Redis command timed out的问题

news2025/1/13 3:22:22

背景

springboot使用redisTemplate访问redis cluster(三主三从),底层是Lettuce,当其中一个master挂掉后,slave正常升为master,程序报错 Redis commond timed out after 6 seconds。

解决

  1. 手动连接集群,正常读写,确定为应用程序的问题

  1. 查看应用程序的redis 集群配置,没有问题

  1. 查看网上的解决办法,发现是Lettuce的问题

转载:验证了方案二,把lettuce换成jedis,切换正常

最新一次线上生产环境下Redis集群服务器某一个主节点发生故障,Cluster节点下的从节点快速进行迁移升级为主节点,节点迁移时间大概为15秒,这15秒期间Redis服务不可用,程序无法读写Redis数据,报错java.lang.RuntimeException: org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.dao.QueryTimeoutException: Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Command timed out after 1 minute(s),但是15秒过后服务依旧无法使用,大概持续了6分钟,而在业务高峰期间这6分钟也会造成很大的用户感知,为何要持续这么久Redis才能恢复,成为了未知的谜团!

联合运维和云厂商做了很多测试,发现凡是使用jedis客户端的服务都可以在15秒主从切换后恢复,而使用lettuce作为redis客户端的服务则无法恢复使用,一直抛超时的异常,做了实验发现,使用lettuce作为客户端的服务,在15秒主从切换后一直要等待redis服务的宕机节点拉起成功后才可以恢复,而这时间大概持续了2分钟,从网上搜了很多答案发现也有一些遇到了同样问题的情况发生。Lettuce的节点切换15秒是来源于 cluster-node-timeout这个配置的默认时间,这个是时间节点宕机发现时间,也就是Redis群集节点不可用的最长时间,因为RedisCluster是无中心设计,节点探测的时间设置太小会因为网络抖动造成的节点下线,时间太长又无法快速处理节点切换,这个可以具体了解Cluster集群主从切换的原理。相关阅读https://www.cnblogs.com/kaleidoscope/p/9636264.html

因为所有微服务使用SpringBoot2.1.7版本SpringBoot2.X版本开始Redis默认的连接池都是采用的Lettuce,之前的文章也有介绍过Lettuce连接池的使用,为了避免后续出现硬件故障,导致服务连接Redis一段时间不可用的情况,所以也就急需要解决节点宕机的恢复时间问题。

经过大量的调研和实验最后发现有关,官方的描述是https://github.com/lettuce-io/lettuce-core/wiki/Redis-Cluster#user-content-refreshing-the-cluster-topology-view, Lettuce需要刷新节点拓扑视图,

大致意思是,Redis集群配置在运行期间可能会改变,可以添加新的节点,为特定插槽的主节点可以发生改变,Lettuce处理Moved和Ask永久重定向,但是由于命令重定向,你必须刷新节点拓扑视图,拓扑是绑定到RedisClusterClient的示例,所有由一个RedisClusterClient实例创建的节点连接共享相同的节点拓扑视图,视图可以采用以下三种方式更新

1、Either by calling RedisClusterClient.reloadPartitions

通过调用RedisClusterClient.reloadPartitions

2、Periodic updates in the background based on an interval

后台基于时间间隔的周期刷新

3、Adaptive updates in the background based on persistent disconnects and MOVED/ASKredirections

后台基于持续的断开和移动/重定向的自适应更新

By default, commands follow -ASK and -MOVED redirects up to 5 times until the command execution is considered to be failed. Background topology updating starts with the first connection obtained through RedisClusterClient.

默认的 命令跟随ASK 和移MOVED 命令执行重定向到5次,直到被认为是失败了,后台拓扑更新始于第一次RedisClusterClient链接

相关阅读 https://github.com/lettuce-io/lettuce-core/wiki/Client-options#periodic-cluster-topology-refresh

所以说在RedisCluster集群模式下可以通过 3种方式去刷新节点拓扑视图去解决节点重新识别的问题,

第一种方式是通过RedisClusterClient,SpringBoot通过Sprint Redis Data构建Redis时,没有显式构建RedisClusterClient,所以只能通过其他两种方式

https://github.com/lettuce-io/lettuce-core/wiki/Client-Options

这里描述了很多特殊场景下设置的客户端选项,可以视自身情况去设置调整

    @Autowired	private RedisProperties redisProperties; 	@Bean	public GenericObjectPoolConfig<?> genericObjectPoolConfig(Pool properties) {		GenericObjectPoolConfig<?> config = new GenericObjectPoolConfig<>();		config.setMaxTotal(properties.getMaxActive());		config.setMaxIdle(properties.getMaxIdle());		config.setMinIdle(properties.getMinIdle());		if (properties.getTimeBetweenEvictionRuns() !=null) {			config.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRuns().toMillis());		}		if (properties.getMaxWait() !=null) {			config.setMaxWaitMillis(properties.getMaxWait().toMillis());		}		return config;	}		@Bean(destroyMethod ="destroy")	public LettuceConnectionFactory lettuceConnectionFactory() {			    //开启 自适应集群拓扑刷新和周期拓扑刷新	    ClusterTopologyRefreshOptions clusterTopologyRefreshOptions =  ClusterTopologyRefreshOptions.builder()	    		// 开启全部自适应刷新	            .enableAllAdaptiveRefreshTriggers() // 开启自适应刷新,自适应刷新不开启,Redis集群变更时将会导致连接异常	            // 自适应刷新超时时间(默认30秒)	            .adaptiveRefreshTriggersTimeout(Duration.ofSeconds(30)) //默认关闭开启后时间为30秒	    		// 开周期刷新 	    		.enablePeriodicRefresh(Duration.ofSeconds(20))  // 默认关闭开启后时间为60秒 ClusterTopologyRefreshOptions.DEFAULT_REFRESH_PERIOD 60  .enablePeriodicRefresh(Duration.ofSeconds(2)) = .enablePeriodicRefresh().refreshPeriod(Duration.ofSeconds(2))	            .build();			    // https://github.com/lettuce-io/lettuce-core/wiki/Client-Options	    ClientOptions clientOptions = ClusterClientOptions.builder()	            .topologyRefreshOptions(clusterTopologyRefreshOptions)	            .build(); 	    LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()				.poolConfig(genericObjectPoolConfig(redisProperties.getLettuce().getPool()))				//.readFrom(ReadFrom.MASTER_PREFERRED)				.clientOptions(clientOptions)				.commandTimeout(redisProperties.getTimeout()) //默认RedisURI.DEFAULT_TIMEOUT 60				.build();	    		List<String> clusterNodes = redisProperties.getCluster().getNodes();		Set<RedisNode> nodes = new HashSet<RedisNode>();		clusterNodes.forEach(address -> nodes.add(new RedisNode(address.split(":")[0].trim(), Integer.valueOf(address.split(":")[1]))));				RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();		clusterConfiguration.setClusterNodes(nodes);		clusterConfiguration.setPassword(RedisPassword.of(redisProperties.getPassword()));		clusterConfiguration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());				LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(clusterConfiguration, clientConfig);		// lettuceConnectionFactory.setShareNativeConnection(false); //是否允许多个线程操作共用同一个缓存连接,默认true,false时每个操作都将开辟新的连接		// lettuceConnectionFactory.resetConnection(); // 重置底层共享连接, 在接下来的访问时初始化		return lettuceConnectionFactory;	}

开启自适应刷新并设定刷新频率

可以看到设定前,周期刷新和拓扑刷新都是false

调整后周期刷新和拓扑刷新都是true

enablePeriodicRefresh意思就是开启并设定周期刷新时间

开关的开启后的控制实际是RedisClusterClient.activateTopologyRefreshIfNeeded在这个方法内完成的,如果开关开启则会创建一个ScheduledFuture 根据你设置的节点刷新事件定期的去调用,当RedisClusterClient初始化后,定时器会周期性的执行,

如果 定时器执行通过,则RedisClusterClient.doLoadPartitions会返回loadedPartitions,如果半截Return掉,则不再返回新的节点信息。

相关阅读https://github.com/lettuce-io/lettuce-core/issues/240

相关阅读https://blog.csdn.net/weixin_42182797/article/details/95210437#_1

当然,如果你想就此放弃lettuce转用jedis也是可以的 Spring Boot2.X版本,只要在pom.xml里,调整一下依赖包的引用

 <dependency>       <groupId>org.springframework.boot</groupId>       <artifactId>spring-boot-starter-data-redis</artifactId>            <exclusions>                <exclusion>                    <groupId>io.lettuce</groupId>                    <artifactId>lettuce-core</artifactId>                </exclusion>            </exclusions> </dependency>         <dependency>        <groupId>redis.clients</groupId>        <artifactId>jedis</artifactId> </dependency>

配置上lettuce换成jedis的,既可以完成底层对jedis的替换

spring:  redis:    database: 0                  #Redis 索引(0~15,默认为0)    timeout: 1000                #Redis 连接的超时时间    password:                    #Redis 密码,如果没有就默认不配置此参数    cluster:                     #Redis 集群配置      max-redirects: 5           #Redis 命令执行时最多转发次数      nodes: 192.168.56.15:7000,192.168.56.15:7001,192.168.56.16:7002,192.168.56.16:7003,192.168.56.17:7004,192.168.56.17:7005  #Redis 集群地址    jedis:      pool:        max-active: 20        max-wait: -1        min-idle: 0        max-idle: 10#使用 lettuce 连接池#    lettuce:                     #      pool:#        max-active: 20           #连接池最大连接数(使用负值表示没有限制)#        max-wait: -1             #连接池最大阻塞等待时间(使用负值表示没有限制)#        min-idle: 0              #连接池中的最大空闲连接#        max-idle: 10             #连接池中的最小空闲连接

因为jedis的节点信息,没有搞的那么复杂

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/400381.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【三维几何学习】网格上低分辨率的分割结果到高分辨率的投影与可视化

网格上低分辨率的分割结果到高分辨率的投影与可视化引言一、到高分辨率的投影1.1 准确率1.2 主要代码1.3 投影核心代码二、可视化代码引言 三角网格的结构特性决定了其仅用少量三角形即可表示一个完整的3D模型。增加其分辨率可以展示更多模型的形状细节。对于网格分割来说&…

可复用测试用例描述要素

测试用例的输入、操作、预期结果和评估标准、前提条件是测试用例不可少的要素&#xff0c;但对于可复用测试用例而言&#xff0c;这是不够的。本文在文献规定的测试用例要素基础上&#xff0c;增加了新的内容。从而从多个角度完整地对可复用测试用例进行了描述&#xff0c;为可…

从0开始学IntelliJ Plugin开发:一、配置环境

前言 作为一个javaer&#xff0c;相信大家平时开发都多多少少使用了一些idea的插件&#xff0c;那么在享受插件便利的同时&#xff0c;有没有好奇插件是如何开发的 笔者怀着这份好奇开始了idea插件开发学习之路&#xff0c;同时把学习的心得体会整理成系列文章作为学习笔记供…

探访人工智能领跑者:纷享销客携手30+TOP高科技企业走进旷视科技

拥有全球规模领先的计算机视觉研究院&#xff1b; 揽获28项世界顶级AI竞赛冠军&#xff1b; 世界级人工智能公司&#xff1b; 没错&#xff0c;它就是人工智能行业的务实者和领跑者&#xff0c;旷视科技。 3月3日&#xff0c;北京软件和信息服务业协会联合纷享销客&#xff0c;…

macOS 13.3 Beta 3 (22E5236f)With OpenCore 0.9.1开发版 and winPE双引导分区原版镜像

原文地址&#xff1a;http://www.imacosx.cn/112494.html&#xff08;转载请注明出处&#xff09;镜像特点完全由黑果魏叔官方制作&#xff0c;针对各种机型进行默认配置&#xff0c;让黑苹果安装不再困难。系统镜像设置为双引导分区&#xff0c;全面去除clover引导分区&#x…

ViT:Transformer在CV领域的开山之作

ViT引发的变革 Transformer最开始是作为自然语言处理&#xff08;英语&#xff1a; Natural Language Processing &#xff0c;缩写作 NLP&#xff09;领域的模型框架&#xff0c;在该领域其可谓大放异彩&#xff0c;然而自始至终都有人在不断尝试将Transformer应用到视觉领域…

快速入门深度学习1(用时1h)

速通《动手学深度学习》1写在最前面0.内容与结构1.深度学习简介1.1 问题引入1.2 思路&#xff1a;逆向思考1.3 跳过1.4 特点1.5 小结2.预备知识&#xff08;MXNet版本&#xff0c;学错了。。。。&#xff09;2.1 获取和运行本书的代码2.2 数据操作2.2.1 略过2.2.2 小结2.3 自动…

c/c++开发,无可避免的模板编程实践(篇九)-c++11的新顺序容器

一、std::array数组容器 1.1 数组的适配器-std::array std::array 是封装固定大小数组的容器&#xff0c;是c11标准库新引入的顺序容器&#xff0c;定义于头文件 <array>。 template <class T,std::size_t N > struct array; 此容器是一个聚合类型&#xff0c;其…

ChatPDF解放双手帮你解读PDF文档

一、先介绍一下吧 chatPDF是一个解读pdf文档的AI模型&#xff0c;然后封装出来的工具。如论文、合同、文书、书籍等&#xff0c;只要是PDF都能搞定&#xff0c;可支持120页【2023.3.9】的文件。据说之前支持200页&#xff0c;反正在变 最新爆火的ChatPDF&#xff0c;短短5天就…

nginx 主动健康检查搭建详解(nginx_upstream_check_module)

版本信息 nginx: 1.21 1.下载nginx_upstream_check_module模块 nginx_upstream_check_module-master.zip wget https://codeload.github.com/yaoweibin/nginx_upstream_check_module/zip/master 解压到 2. 安装nginx 略 3. 补丁安装 由于我这边安装nginx版本为nginx1.21…

你是使用什么工具调试 golang 程序的?

写过 C/C 的都是到&#xff0c;调试程序的时候通常使用 gdb 工具来进行调试&#xff0c;用起来可爽了&#xff0c;那么 gdb 是否也适合 golang 程序的调试的 我个人到是通常使用 dlv 来进行 golang 程序的调试&#xff0c;分享一波 dlv 是什么&#xff0c;全称 Delve Delve …

KiCad 编译

KiCad 编译 因为最新项目需要&#xff0c;所以看了一下KiCad的编译&#xff0c;这里介绍的是64位电脑的编译&#xff0c;32位小伙伴请绕道官网看教程呦。 您可以在KiCad内查看基本的编译教程。 我这里也是参考的官网编译教程进行的编译&#xff0c;接下来让我们一起看看吧。…

论文 | 期刊 | 专业名词解释

文章目录1. EI2. IEEE Xplore3. CN期刊3.2 CN期刊后面的数字代表什么3. SCI3.1 影响因子先立个帖子&#xff0c;后续用到的话随时更新1. EI 工程索引(EI)是由美国工程信息公司(Engineering information Inc.)编辑出版&#xff0c;历史上最悠久的一部大型综合性检索工具。 《工…

03 SWMM快速入门案例的设施参数设置与批量设置

文章目录1 雨量计1.1 雨量计基础设置1.2 雨量计数据来源2 汇水区2.1 参数讲解2.2 设置结果3 检查井3.1 参数讲解3.2 批量设置4 管道4.1 参数讲解4.2 设置结果5 出水口上一篇博客中我们已经完成了各类设施的绘制&#xff0c;本节对他们的参数进行设置1 雨量计 1.1 雨量计基础设…

第一章 C语言:数据存储

一、大小端存储大端存储&#xff1a;数据的低位字节存储在高地址小端存储&#xff1a;数据的低位字节存储在低地址不同编译器有不同的存储方式int a 10; char* p (char*)&a; printf("%x\n", *p); // a ---> 0000000a //0000 0000 0000 0000 0000 0…

教学场景应用视频试看预览功能

html5播放器视频预览功能效果 - 视频预览代码示例预播放一小段时间的视频内容&#xff0c;比如3分钟&#xff0c;然后引导用户付费观看或注册会员观看完整视频。原理&#xff1a;视频播放结束&#xff0c;执行s2j_onPlayOver()函数&#xff0c;显示提示信息或对话框&#xff0c…

Altium Designer(AD)软件使用记录03-AD软件中各层定义

Altium Designer(AD)软件使用记录03-AD软件中各层定义 重点&#xff1a; 1、常用的信号层&#xff1a;顶层&#xff0c;底层层&#xff0c;中间正片层&#xff0c;中间负片层 2、机械1层作为板框层&#xff0c;机械13层作为3D防止层&#xff0c;其他的机械层很少用 3、顶层阻焊…

AVL树详解+模拟实现

1&#xff1a;概念当数据有序&#xff0c;二叉搜索树将趋近于单叉树&#xff0c;查找元素相当于在顺序表中查找元素&#xff0c;效率低下&#xff0c;两位俄罗斯数学家G.M.Adelson-Velskii和E.M.Landis创建了AVL树。特性如下&#xff1a; 左右子树高度差的绝对值不超过1左右子树…

Django/Vue实现在线考试系统-06-开发环境搭建-Visual Studio Code安装

1.0 VS Code下载和安装 Visual Studio Code,简称 VS Code,是由微软公司开发的 IDE 工具。与微软其他 IDE(如 Visual Studio)不同的是,Visual Studio Code 是跨平台的,可以安装在 Windows、Linux 和 macOS平台上运行。不仅如此, Visual Studio Code 没有限定只能开发特定…

Revit中如何添加一个新的管道直径

有些时候项目当中会遇到一些管径比较小的管道&#xff0c;但是在直径中又没有适合的&#xff0c;怎么办?很简单&#xff0c;跟紧以下几个步理就可以了。 首先&#xff0c;我们拿一个管段为“铁&#xff0c;铸铁30”的为例子&#xff0c;如图1所示&#xff0c;系统中这管段是没…