当前位置: 首页 > news >正文

Redis Cluster 在Spring中遇到的问题

Redis集群配置可能会在运行时更改。可以添加新节点,可以更改特定插槽的主节点。还有可能因为master宕机或网络抖动等原因,引起了主从切换。

无法感知集群槽位变化

SpringBoot2.x 开始默认使用的 Redis 客户端由 Jedis 变成了 Lettuce,但是当 Redis 集群中节点槽位变化之后,Lettuce 将无法继续操作 Redis,原因在于此时 Lettuce 使用的仍然是有问题的连接信息。

实际上,Lettuce 支持 redis 集群拓扑动态刷新,但是默认并没有开启,SpringBoot 在集成 Lettuce 时默认也没有开启。并且在 SpringBoot2.3.0 之前,是没有配置项设置 Lettuce 自动刷新拓扑的。在这次提交中增加了这一配置。使用Jedis便没有这个问题。

官方的描述Lettuce需要刷新节点拓扑视图Lettuce Github Wiki

解决方案

方法一:使用Jedis连接

Spring Boot2.0以下默认使用Jedis,由于jedis通过自身异常反馈来识别重连、刷新服务端的集群信息机制,保证其自动故障恢复,所以Jedis client默认自动支持拓扑刷新,方法一便是使用更换为Jedis客户端。

<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>

方法二:配置LettuceConnectionFactory,设置拓扑刷新策略

文档参考集群特定选项

@Bean
public DefaultClientResources lettuceClientResources() {return DefaultClientResources.create();
}@Bean
public LettuceConnectionFactory lettuceConnectionFactory(RedisProperties redisProperties, ClientResources clientResources) {ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder().enablePeriodicRefresh(Duration.ofSeconds(30)) //按照周期刷新拓扑.enableAllAdaptiveRefreshTriggers() //根据事件刷新拓扑.build();ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()//redis命令超时时间,超时后才会使用新的拓扑信息重新建立连接.timeoutOptions(TimeoutOptions.enabled(Duration.ofSeconds(10))).topologyRefreshOptions(topologyRefreshOptions).build();LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder().clientResources(clientResources).clientOptions(clusterClientOptions).build();RedisClusterConfiguration clusterConfig = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());clusterConfig.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());clusterConfig.setPassword(RedisPassword.of(redisProperties.getPassword()));LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(clusterConfig, clientConfiguration);return lettuceConnectionFactory;
}

方法三:开启自动拓扑刷新

Spring Boot2.3之后可以通过简单的配置变可以打开自动刷新拓扑的功能:

# 定时拓扑刷新(Periodic updates)
spring.redis.lettuce.cluster.refresh.period=60s
# 自适应拓扑刷新(Adaptive updates)
spring.redis.lettuce.cluster.refresh.adaptive=true

健康检查无法自动感知集群恢复

我们都知道Redis Cluster集群模式在主节点宕机后,会自动切换到可用的从节点,集群会再度恢复可用性。

但是如果在例如K8S、注册中心等管理服务中,存活探针用了actuator的health地址,那k8s容器里的服务也一样会down掉,也会导致服务不可用,即使服务层面已经刷新了redis集群的拓扑,服务/actuator/health健康情况依然会是down状态(原因是配置的redis集群nodes的每个node都会检查是否健康,不管这个node是主节点还是从节点),错误如下:

"redis": {"status": "DOWN","details": {"error": "org.springframework.data.redis.RedisConnectionFailureException: Redis connection failed; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 10.0.35.249:6380"}
},

redis cluster模式某节点宕机之后,Spring识别redis集群健康为down是个bug。是由于Spring Data Redis 2.2.8 提交所引起,具体可看这个解释。这个问题在spring boot2.4.x之后被修复。

解决方案

方法一:升级Spring版本到2.4.X

作者有在issue#21514下回应到,不会在2.3.X版本修复这个问题,而是在2.4.X中才会修改

方法二:重写健康检查代码

重写redis集群健康监控的Indicator,可以参考issue#21514下某网友的回答:

// 重新实现RedisReactiveHealthIndicatorprivate Health up(Health.Builder builder, Properties info, ReactiveRedisConnection connection) {if (connection instanceof ReactiveRedisClusterConnection) {List<Map<String, String>> details = getDetails(info);if (details.isEmpty()) {return builder.outOfService().build();} else {return builder.up().withDetail("nodes", details).build();}} else {return builder.up().withDetail("version", info.getProperty("redis_version")).build();}}private List<Map<String, String>> getDetails(Properties info) {return info.keySet().stream().map(String.class::cast).map(k -> k.substring(0, k.lastIndexOf("."))).distinct().sorted().map(node -> Map.of("node", node,"redis_version", info.getProperty(node + ".redis_version"),"role", info.getProperty(node + ".role"),"uptime_in_days", info.getProperty(node + ".uptime_in_days"))).collect(Collectors.toList());}

方法三:关闭Redis健康检查

management.health.redis.enabled=false

文档参考
RedisCluster集群模式下master宕机主从切换期间Lettuce连接Redis无法使用报错Redis command timed out的问题
redis集群拓扑结构自动更新:使用Lettuce连接Cluster集群实例时异常处理
刷新群集拓扑视图
Redis集群调整节点并手动切换主从引发的微服务报错问题
spring boot健康检查无法感知redis故障恢复的问题梳理
Redis集群模式下RedisReactiveHealthIndicator中断

相关文章:

Redis Cluster 在Spring中遇到的问题

Redis集群配置可能会在运行时更改。可以添加新节点&#xff0c;可以更改特定插槽的主节点。还有可能因为master宕机或网络抖动等原因&#xff0c;引起了主从切换。 无法感知集群槽位变化 SpringBoot2.x 开始默认使用的 Redis 客户端由 Jedis 变成了 Lettuce&#xff0c;但是当…...

linux远程桌面管理工具 xrdp

Xrdp 是一个微软远程桌面协议&#xff08;RDP&#xff09;的开源实现&#xff0c;它允许你通过图形界面控制远程系统。通过 RDP&#xff0c;你可以登录远程机器&#xff0c;并且创建一个真实的桌面会话&#xff0c;就像你登录本地机器一样。 如何在Ubuntu 20.04 上安装 Xrdp 服…...

硬件-8-操作系统的历史

操作系统的最强入门科普&#xff08;Unix/Linux篇&#xff09; 操作系统的发展史&#xff08;DOS/Windows篇&#xff09; Mac操作系统进化史 手机操作系统的沉浮往事&#xff08;上&#xff09; 手机操作系统的沉浮往事&#xff08;下&#xff09; 1 操作系统种类 我们天天都…...

self.register_buffer()中的值发生变化

PyTorch中定义模型时&#xff0c;有时候会遇到self.register_buffer(name, Tensor)的操作&#xff0c;该方法的作用是定义一组参数&#xff0c;该组参数的特别之处在于&#xff1a;模型训练时不会更新&#xff08;即调用 optimizer.step() 后该组参数不会变化&#xff0c;只可人…...

[Tools: Pycharm] Bug合集

1. Debug mode&#xff1a;Pycharm不显示变量值&#xff08;Unable to display frame variables&#xff09;&#xff1b;在python console中交互不输出值 选择Gevent compatible&#xff1a;File > Settings > Build, Execution, Deployment > Python Debugger >…...

【JAVASE】循环结构

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈Java &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 循环 1. 循环结构1.1 while 循环1.2 bre…...

NoSQL之Redis配置使用

目录 一、关系数据库与非关系型数据库 1.1.关系型数据库的概述 1.2关系型数据库的优缺点 1.2.1优点 1.2.2缺点 1.3.非关系型数据库的概述 二.关系数据库与非关系型数据库的区别 2.1数据存储方式不同 2.2扩展方式不同 2.3对事务性的支持不同 2.4非关系型数据库产生背景 2…...

Ansible最佳实践之Playbook使用过滤器处理网络地址

写在前面 使用过滤器检查、验证和操作包含网络信息的变量理解不足小伙伴帮忙指正 傍晚时分&#xff0c;你坐在屋檐下&#xff0c;看着天慢慢地黑下去&#xff0c;心里寂寞而凄凉&#xff0c;感到自己的生命被剥夺了。当时我是个年轻人&#xff0c;但我害怕这样生活下去&#xf…...

测试常见前端bug

目录 协作 测试方法 标签&#xff1a;标签 内容/ref/ 判断 arr&&arr.length 交互 样式不生效&#xff1a;devtools查找&#xff0c;编译前的标签&#xff0c;运行时不一定存在 可交互的需要提示 hover样式 没有交互逻辑&#xff0c;就不要设置交互 无法交互…...

【Python数据分析】Python常用内置函数(一)

&#x1f389;欢迎来到Python专栏~Python常用内置函数&#xff08;一&#xff09; ☆* o(≧▽≦)o *☆嗨~我是小夏与酒&#x1f379; ✨博客主页&#xff1a;小夏与酒的博客 &#x1f388;该系列文章专栏&#xff1a;Python学习专栏 文章作者技术和水平有限&#xff0c;如果文…...

OpenCV图像处理-图像分割-MeanShift

MeanShift 1. 基本概念2.代码示例 1. 基本概念 MeanShift严格说来并不是用来对图像进行分割的&#xff0c;而是在色彩层面的平滑滤波。它会中和色彩分布相近的颜色&#xff0c;平滑色彩细节&#xff0c;侵蚀掉面积较小的的颜色区域&#xff0c;它以图像上任意一点P为圆心&…...

【Rust 基础篇】Rust Trait 实现:灵活的接口抽象

导言 Rust是一种以安全性和高效性著称的系统级编程语言&#xff0c;其设计哲学是在不损失性能的前提下&#xff0c;保障代码的内存安全和线程安全。为了实现这一目标&#xff0c;Rust引入了"所有权系统"、"借用检查器"等特性&#xff0c;有效地避免了常见…...

【嵌入式Linux项目】基于Linux的全志H616开发板智能家居项目(语音控制、人脸识别、安卓APP和PC端QT客户端远程操控)有视频功能展示

目录 一、功能需求 二、开发环境 1、硬件&#xff1a; 2、软件&#xff1a; 3、引脚分配&#xff1a; 三、关键点 1、设计模式之工厂模式 2、wiringPi库下的相关硬件操作函数调用 3、语音模块的串口通信 4、线程 5、摄像头的实时监控和拍照功能 6、人脸识别 四、编…...

ElasticSearch基础篇-条件查询与映射

ElasticSearch基础篇二 条件查询 GET http://10.192.193.98:9200/shopping/_search?qtitle:小米手机q:代表查询条件 响应结果 {"took": 772,"timed_out": false,"_shards": {"total": 1,"successful": 1,"skipped…...

大模型部署框架 FastLLM 实现细节解析

0x0. 前言 接着 大模型部署框架 FastLLM 简要解析 这篇文章首先梳理了一下FastLLM的调用链和关键的数据结构&#xff0c;然后解析了 FastLLM 的一些实现细节和CPU/GPU后端实现采用的优化技巧。 0x1. 调用链和数据结构解析 以chatglm-6b的支持为例&#xff0c;函数入口在 htt…...

Flutter ios真机调试连接断开后应用闪退

使用ios真机调试的时候&#xff0c;能正常打开应用&#xff0c;但是当数据线断开连接的时候&#xff0c;应用就会关闭&#xff0c;重新打开就会闪退。 原因是flutter默认在开发过程中使用debug模式编译 只需要将debug选择为release 重新编译就行。...

序列化,反序列化之实例

别怕&#xff0c;我一直陪着你 一.知识1.魔术方法 二.实例1.绕过__wakeup, private2.php://filter, data://, __tostring3. 一.知识 1.魔术方法 __construct() 当一个对象创建时自动调用 __destruct() 当对象被销毁时自动调用 (php绝大多数情况下会自动调用销毁对象) __sleep…...

2022年全国职业院校技能大赛(高职组)“软件测试”赛项竞赛任务书

2022年全国职业院校技能大赛&#xff08;高职组&#xff09; “软件测试”赛项竞赛任务书 2022年7月 一、竞赛时间、内容及成绩组成 &#xff08;一&#xff09;竞赛时间 本阶段竞赛时间共为8小时&#xff0c;参赛选手自行安排任务进度&#xff0c;休息、饮水、如厕等不设专…...

第18节:R语言分析:临床安全性数据的数据分析

临床安全性数据的数据分析 背景 医疗器械临床试验中收集的数据的主要组成部分是关于患者安全的。 不良事件被定义为“受试者、使用者或其他人的任何不良医疗事件、非预期疾病或伤害,或不良临床体征(包括异常实验室发现),无论是否与研究医疗器械相关”。 收集并用于此数据…...

36.悬浮板

悬浮板 html部分 <div class"container"><div class"square"></div> </div>css部分 *{margin: 0;padding: 0; } body{background-color: #111;height: 100vh;overflow: hidden;display: flex;justify-content: center;align-it…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制

使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下&#xff0c;限制某个 IP 的访问频率是非常重要的&#xff0c;可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案&#xff0c;使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

windows系统MySQL安装文档

概览&#xff1a;本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容&#xff0c;为学习者提供全面的操作指导。关键要点包括&#xff1a; 解压 &#xff1a;下载完成后解压压缩包&#xff0c;得到MySQL 8.…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...

数据结构:递归的种类(Types of Recursion)

目录 尾递归&#xff08;Tail Recursion&#xff09; 什么是 Loop&#xff08;循环&#xff09;&#xff1f; 复杂度分析 头递归&#xff08;Head Recursion&#xff09; 树形递归&#xff08;Tree Recursion&#xff09; 线性递归&#xff08;Linear Recursion&#xff09;…...

2.3 物理层设备

在这个视频中&#xff0c;我们要学习工作在物理层的两种网络设备&#xff0c;分别是中继器和集线器。首先来看中继器。在计算机网络中两个节点之间&#xff0c;需要通过物理传输媒体或者说物理传输介质进行连接。像同轴电缆、双绞线就是典型的传输介质&#xff0c;假设A节点要给…...