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下某网友的回答:

// 重新实现RedisReactiveHealthIndicator

private 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中断

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大数据学习教程:Linux高级教程(下)

四、大数据集群服务器搭建 1. 新增Linux服务器 1.1、克隆虚拟机 学习环境中&#xff0c;一般使用VMware虚拟机克隆Linux系统&#xff0c;用来进行集群服务器的搭建。 VMware支持两种类型的克隆&#xff1a;完整克隆、链接克隆 完整克隆是和原始虚拟机完全独立的一个复制&…

GCC版本升高到11.3后编译之前同样的C++代码出现的若干错误

目录 1 gtest-death-test.cc:1301:24: error: ‘dummy’ may be used uninitialized 2 error: ‘void* memcpy(void*, const void*, size_t)’ copying an object of non-trivial type ‘Eigen::internal::Packet4c’ 3 error: comparison is always true due to limited ra…

恒运资本:满仓的含义?

满仓&#xff0c;望文生义&#xff0c;便是财经领域中的一个术语。它指的是出资者将一切可用资金悉数用于购买股票、基金或其他金融资产。满仓的意义是出资者对某种出资产品充满决心&#xff0c;并乐意将自己的大部分资金投入其中&#xff0c;以希望取得更高的报答。但是&#…

【Android Framework系列】第9章 AMS之Hook实现登录页跳转

1 前言 前面章节我们学习了【Android Framework系列】第5章 AMS启动流程和【Android Framework系列】第6章 AMS原理之Launcher启动流程&#xff0c;大概了解了AMS的原理及启动流程&#xff0c;这一章节我们通过反射和动态代理对不同Android版本下的AMS进行Hook&#xff0c;实现…

亿发软件:专业医疗器械GSP管理系统解决方案,智能化药械规范经营

如今医疗器械市场得到进一步发展&#xff0c;为了确保市场上医疗器械管理效率与品质保障&#xff0c;直击医疗器械行业管理困境&#xff0c;推出医疗器械GSP管理软件&#xff01;专业医疗器械GSP软件全面满足医疗器械企业的应用要求&#xff0c;打造管理解决方案。1、信息传输和…

2023-08-02 LeetCode每日一题(翻转卡片游戏)

2023-08-02每日一题 一、题目编号 822. 翻转卡片游戏二、题目链接 点击跳转到题目位置 三、题目描述 在桌子上有 N 张卡片&#xff0c;每张卡片的正面和背面都写着一个正数&#xff08;正面与背面上的数有可能不一样&#xff09;。 我们可以先翻转任意张卡片&#xff0c;…

云上 Index:看「简墨」如何为云原生打造全新索引

拓数派首款数据计算引擎 PieCloudDB Database 是一款全新的云原生虚拟数仓。为了提升用户使用体验&#xff0c;提高查询效率&#xff0c;在实现存算分离的同时&#xff0c;PieCloudDB 设计与打造了全新的存储引擎「简墨」等模块&#xff0c;并针对云场景和分析型场景设计了高效…

ELD透明屏在智能家居中有哪些优点展示?

ELD透明屏是一种新型的显示技术&#xff0c;它能够在不需要背光的情况下显示图像和文字。 ELD透明屏的原理是利用电致发光效应&#xff0c;通过在透明基板上涂覆一层特殊的发光材料&#xff0c;当电流通过时&#xff0c;发光材料会发出光线&#xff0c;从而实现显示效果。 ELD…

零碎小知识点汇总——记录工作中遇到的问题——基础积累

1.npm install安装包时&#xff0c;常用的-S -D有什么区别&#xff1f; 参考链接&#xff1a;https://blog.csdn.net/sunyctf/article/details/127667543 主要的区别就是依赖配置写入package.json文件的位置不同而已 npm install有一个别名&#xff1a;npm i -S:写入dependen…

Qt 中引入ffmpeg 动态库

1、前期准备 在qt引入ffmpeg动态库的时候&#xff0c;需要准备ffmpeg的动态库和头文件。 2、打开qt项目 在qt项目的.pro文件中添加以下几行代码 INCLUDEPATH $$PWD/thirtLib/ffmpeg4.2/include win32: LIBS -L$$PWD/thirtLib/ffmpeg4.2/lib/ -lavcodec -lavdevice -lavf…

Java的代理模式

java有三种代理模式 静态代理 jdk动态代理 cglib实现动态代理 代理模式的定义&#xff1a; 为其他对象提供一种代理以控制对这个对象的访问。在某些情况下&#xff0c;一个对象不适合或者不能直接引用另一个对象&#xff0c;而代理对象可以在客户端和目标对象之间起到中介的…

TCP三次握手与四次断开

TCP三次握手机制 三次握手是指建立一个TCP连接时&#xff0c;需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。 1、客户端发送建立TCP连接的请求报文&#xff0c;其…

小研究 - 基于解析树的 Java Web 灰盒模糊测试(二)

由于 Java Web 应用业务场景复杂, 且对输入数据的结构有效性要求较高, 现有的测试方法和工具在测试Java Web 时存在测试用例的有效率较低的问题. 为了解决上述问题, 本文提出了基于解析树的 Java Web 应用灰盒模糊测试方法. 首先为 Java Web 应用程序的输入数据包进行语法建模创…

《零基础入门学习Python》第077讲:Tkinter 模块:标准对话框

Tkinter 为了提供了三种标准对话框模块&#xff0c;它们分别是&#xff1a; messageboxfiledialogcolorchooser 注&#xff1a;这三个模块原来是独立的&#xff0c;分别是 tkMessageBox、tkFileDialog 和 tkColorChooser&#xff0c;需要导入才能使用。在 Python3 之后&#…

HCIP OSPF链路状态类型总结

OSPF的LSA OSPF是典型的链路状态路由协议&#xff0c;使用LAS&#xff08;链路状态通告&#xff09;来承载链路状态信息。LSA是OSPF的一个核心内容&#xff0c;如果没有LSA&#xff0c;OSPF 是无法描述网络的拓扑结构及网段信息的&#xff0c;也无法传递路由信息&#xff0c;更…

2023年信息系统项目管理师-粗略了解整体主要知识脉络

1. 五大过程组 2.十大知识领域 3. 十大知识领域与五大过程组的关系 4. 十大知识领域的关系图 5. 十大知识域与五大过程组的记忆方法 6. 仅开展一次或仅在项目预定义的时候开展 7.需要定期开展的过程

【方法】PDF可以转换成Word文档吗?如何操作?

很多人喜欢在工作中使用PDF&#xff0c;因为PDF格式可以准确地保留文档的原始格式&#xff0c;比如字体、图像、布局和颜色等。 但如果编辑文档的话&#xff0c;PDF还是没有Word文档方便。那可以将PDF转换成Word格式&#xff0c;再来编辑吗&#xff1f;如何操作呢&#xff1f;…

网络安全进阶学习第十一课——MySQL手工注入(2)

文章目录 一、UA注入1、原理2、靶场演示&#xff1a;1&#xff09;一旦页面出现如下现状&#xff0c;就可以使用UA注入2&#xff09;BP抓包3&#xff09;修改User-Agent 二、referer注入1、原理2、靶场演示&#xff1a;1&#xff09;使用BP抓包2&#xff09;修改Referer 三、DN…

Express中间件

1.创建最基本的中间件 const express require(express); const send require(send);const app express()const mw function (req, res, next) {console.log(middleware);// 一定要调用next() 把流转关系交给下一个中间件或路由next() }app.listen(80, () > {console.l…

CRM系统如何进行公海池线索分配自动化?

在销售过程中&#xff0c;线索分配是一个非常重要的环节。传统的线索分配方式往往是由销售主管手动进行&#xff0c;不仅效率低下&#xff0c;还存在着不公平、不灵活的问题。因此&#xff0c;许多企业通过CRM来实现公海池线索分配自动化。 1、基于规则的分配 CRM可以让用户设…