Spring Boot集成redis集群拓扑动态刷新
项目场景:
Spring Boot集成Redis集群,使用lettuce连接Cluster集群实例。
问题描述
redis其中一个节点挂了之后,springboot集成redis集群配置信息没有及时刷新,出现读取操作报错。 
java.lang.IllegalArgumentException: Connection to 127.0.0.1:6379 not allowed. This connection point is not known in the cluster view
exceptionStackTrace
io.lettuce.core.cluster.PooledClusterConnectionProvider.getConnectionAsync(PooledClusterConnectionProvider.java:359)
io.lettuce.core.cluster.ClusterDistributionChannelWriter.write(ClusterDistributionChannelWriter.java:93)
io.lettuce.core.cluster.ClusterCommand.complete(ClusterCommand.java:56)
io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:563)
io.lettuce.core.protocol.CommandHandler.channelRead(CommandHandler.java:516)
原因分析:
lettuce默认是没有开始拓扑更新及读写分离导致的
解决方案:
这里分为几种情况:
- springboot 1.x之前版本默认使用jedis,无需要手动开启刷新
- springboot 2.x默认为Lettuce,需要代码设置开启刷新节点拓扑策略
- springboot 2.3.0开始,支持集群拓扑刷新功能,属性配置开启即可
第一种情况:springboot1.x版本环境
springboot1.x之前版本默认使用jedis,无需手动开启动态刷新。
第二种情况:springboot2.0~2.3版本环境
springboot2.0-2.3版本默认使用lettuce,默认不支持属性配置集群拓扑刷新。使用lettuce,需要增加配置类,需要手动开启刷新。
配置类如下:
package com.test.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.lettuce.core.cluster.ClusterClientOptions;
import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
import lombok.extern.java.Log;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import java.lang.reflect.Method;
import java.time.Duration;@Log
@Configuration
@EnableCaching // 开启缓存支持
public class RedisConfig {@Autowiredprivate RedisProperties redisProperties;@Bean(destroyMethod = "destroy")	//销毁这个bean之前调用这个destroy回调方法释放资源public LettuceConnectionFactory redisConnectionFactory() {// redis单节点if (null == redisProperties.getCluster() || null == redisProperties.getCluster().getNodes()) {RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisProperties.getHost(),redisProperties.getPort());configuration.setPassword(redisProperties.getPassword());	//RedisPassword.of(redisProperties.getPassword())configuration.setDatabase(redisProperties.getDatabase());return new LettuceConnectionFactory(configuration);}// redis集群RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());redisClusterConfiguration.setPassword(redisProperties.getPassword());	//RedisPassword.of(redisProperties.getPassword())redisClusterConfiguration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();genericObjectPoolConfig.setMaxTotal(redisProperties.getLettuce().getPool().getMaxActive());genericObjectPoolConfig.setMaxIdle(redisProperties.getLettuce().getPool().getMaxIdle());genericObjectPoolConfig.setMinIdle(redisProperties.getLettuce().getPool().getMinIdle());genericObjectPoolConfig.setMaxWaitMillis(redisProperties.getLettuce().getPool().getMaxWait().getSeconds());// 支持自适应集群拓扑刷新和动态刷新源ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder().enableAllAdaptiveRefreshTriggers()// 开启自适应刷新.enableAdaptiveRefreshTrigger()// 开启定时刷新.enablePeriodicRefresh(Duration.ofSeconds(5)).build();ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder().topologyRefreshOptions(clusterTopologyRefreshOptions).build();LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(genericObjectPoolConfig)	//如果使用默认配置可以注释genericObjectPoolConfig
//            .readFrom(ReadFrom.SLAVE_PREFERRED)  //读写分离:主写从读模式配置.clientOptions(clusterClientOptions).build();LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration);lettuceConnectionFactory.setShareNativeConnection(false);// 是否允许多个线程操作共用同一个缓存连接,默认 true,false 时每个操作都将开辟新的连接lettuceConnectionFactory.resetConnection();// 重置底层共享连接, 在接下来的访问时初始化return lettuceConnectionFactory;}/*** RedisTemplate配置*/@Beanpublic RedisTemplate<Object, Object> redisTemplate(LettuceConnectionFactory factory) {RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(factory);// 使用注解@Bean返回RedisTemplate的时候,同时配置hashkey和hashValue的序列虎方式// key采用String的序列化方式redisTemplate.setKeySerializer(keySerializer());// value使用jackson序列化方式redisTemplate.setValueSerializer(valueSerializer());// hash的key采用String的序列化方式redisTemplate.setHashKeySerializer(keySerializer());// hash的value使用jackson序列化方式redisTemplate.setHashValueSerializer(valueSerializer());/**必须执行这个函数,初始化RedisTemplate*/// 需要先调用afterPropertiesSet方法,此方法是应该是初始化参数和初始化工作。redisTemplate.afterPropertiesSet();log.info("序列化完成!");return redisTemplate;}@Beanpublic KeyGenerator keyGenerator() {return new KeyGenerator() {@Overridepublic Object generate(Object target, Method method, Object... params) {StringBuffer sb = new StringBuffer();sb.append(target.getClass().getName());sb.append(method.getName());for (Object obj : params) {sb.append(obj.toString());}return sb.toString();}};}/*** key键序列化方式** @return RedisSerializer*/private RedisSerializer<String> keySerializer() {return new StringRedisSerializer();}/*** value值序列化方式** @return*/private Jackson2JsonRedisSerializer valueSerializer() {Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);return jackson2JsonRedisSerializer;}
}
配置文件:
#Redis Configuration
spring.redis.cluster.max-redirects=10
spring.redis.cluster.nodes=127.0.0.1:8001,127.0.0.1:8002
spring.redis.timeout=60000ms
spring.redis.password=
spring.redis.lettuce.pool.max-active=10
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.pool.max-wait=-1ms注意:注入LettuceConnectionFactory后,一定要记得注入RedisTemplate,并 redisTemplate.setConnectionFactory(factory);
apache commons-pool2 包提供了一个通用的对象池技术的实现。可以很方便的基于它来实现自己的对象池,比如 DBCP 和 Jedis 他们的内部对象池的实现就是依赖于 commons-pool2 。
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.8.0</version>
</dependency>
第三种情况:springboot2.3之后版本环境
springboot2.3之后版本默认使用lettuce,默认支持属性配置开启集群拓扑刷新,其解决方案:属性配置开启即可。
spring.redis.lettuce.cluster.refresh.adaptive= true
spring.redis.lettuce.cluster.refresh.period=30000    # 30秒自动刷新一次
关联文章:Spring Boot集成Redis集群报错UnsupportedOperationException-CSDN博客
相关文章:
Spring Boot集成redis集群拓扑动态刷新
项目场景: Spring Boot集成Redis集群,使用lettuce连接Cluster集群实例。 问题描述 redis其中一个节点挂了之后,springboot集成redis集群配置信息没有及时刷新,出现读取操作报错。 java.lang.IllegalArgumentException: Connec…...
COCI2022-2023#1 Neboderi
P9032 [COCI2022-2023#1] Neboderi 题目大意 有一个长度为 n n n的序列 h i h_i hi,你需要从中选择一个长度大于等于 k k k的子区间 [ l , r ] [l,r] [l,r],使得 g ( h l h l 1 ⋯ h r ) g\times (h_lh_{l1}\cdotsh_r) g(hlhl1⋯hr)最小&…...
 
由于找不到d3dx9_43.dll无法继续执行此代码怎么解决?全面解析d3dx9_43.dll
在使用计算机过程中,我们可能会遇到各种各样的问题。其中之一就是d3dx9_43.dll文件丢失的问题。这个问题通常会出现在运行某些应用程序或游戏时,导致程序无法正常启动或运行。那么,如何解决这个问题呢?小编将为您提供一些解决方案…...
 
Linux--网络编程-字节序
进程间的通信: 管道、消息队列、共享内存、信号、信号量。 特点:都依赖于linux内核。 缺陷:无法多机通信。 一、网络编程: 1、地址:基于网络,ip地址端口号。 端口号作用: 一台拥有ip地址的主机…...
 
python实现http/https拦截
python实现http拦截 前言:为什么要使用http拦截一、技术调研二、技术选择三、使用方法前言:为什么要使用http拦截 大多数爬虫玩家会直接选择API请求数据,但是有的网站需要解决扫码登录、Cookie校验、数字签名等,这种方法实现时间长,难度高。需求里面不需要高并发,有没有…...
 
农产品团购配送商城小程序的作用是什么
农产品覆盖稻麦油蛋等多种细分类目,各地区经营商家众多,随着人们生活品质提升,对食物的要求也在提升,绿色无污染无激素的农产品往往受到不少人喜爱,而在销售中,也有不少人选择自建商城线上经营。 通过【雨…...
使用van-dialog二次封装微信小程序模态框
由于微信小程序的wx.showModal不支持富文本内容,无法实现更灵活的展示效果,故需要进行二次封装 实现思路:使用van-dialog以及微信小程序的rich-text实现 代码如下: // index.wxml <van-dialoguse-slottitle"提示"s…...
 
生鲜蔬果同城配送社区团购小程序商城的作用是什么
生鲜蔬果行业作为市场主要支撑之一,从业商家众多的同时消费者也从不缺,尤其对中高城市,生鲜蔬果除了传统线下超市、市场经营外,线上更是受到大量消费者信任,而很多商家也是自建了生鲜蔬果商城多场景生意经营。 那么通…...
 
Unity实现设计模式——状态模式
Unity实现设计模式——状态模式 状态模式最核心的设计思路就是将对象的状态抽象出一个接口,然后根据它的不同状态封装其行为,这样就可以实现状态和行为的绑定,最终实现对象和状态的有效解耦。 在实际开发中一般用到FSM有限状态机的实现&…...
差分数组的应用技巧
前缀和技巧 针对的算法场景是不需要对原始数组进行修改的情况下,频繁查询某个区间的累加和。 差分数组 主要适用场景是频繁对原始数组的某个区间的元素进行增减。 相关题目 1094. 拼车 1109. 航班预订统计 370. 区间加法 # 1094. 拼车 class Solution:def carPool…...
 
斯坦福数据挖掘教程·第三版》读书笔记(英文版)Chapter 10 Mining Social-Network Graphs
来源:《斯坦福数据挖掘教程第三版》对应的公开英文书和PPT。 Chapter 10 Mining Social-Network Graphs The essential characteristics of a social network are: There is a collection of entities that participate in the network. Typically, these entiti…...
DFS:842. 排列数字
给定一个整数 nn,将数字 1∼n1∼n 排成一排,将会有很多种排列方法。 现在,请你按照字典序将所有的排列方法输出。 输入格式 共一行,包含一个整数 nn。 输出格式 按字典序输出所有排列方案,每个方案占一行。 数据…...
 
pytorch之nn.Conv1d详解
自然语言处理中一个句子序列,一维的,所以使用Conv1d...
 
H5生成二维码
H5生成二维码: 1.引入js库,可自行点击链接复制使用 <script type"text/javascript" src"http://static.runoob.com/assets/qrcode/qrcode.min.js"></script>2.加入二维码占位区HTML <div id"qrCode">…...
 
Three.js加载360全景图片/视频
Three.js加载360全景图片/视频 效果 原理 将全景图片/视频作为texture引入到three.js场景中将贴图与球形网格模型融合,将球模型当做成环境容器使用处理视频时需要以dom为载体,加载与控制视频动作每次渲染时更新当前texture,以达到视频播放效…...
 
北大硕士7年嵌入式学习经验分享
阶段 1 大一到大三这个阶段我与大多数学生相同: 学习本专业知识(EE专业),学习嵌入式软件开发需要的计算机课程(汇编原理,计算机组成原理,操作系统,C语言等),…...
 
华为鸿蒙手表开发之动态生成二维码
华为鸿蒙手表开发之动态生成二维码 前言: 最近入职新公司,由于之前的哥们临时离职,走得很突然,所以没有任何交接和文档,临时顶上公司手表应用的上架,更换了新的密钥和key之后重新测试功能和流程ÿ…...
 
2023-09-28 monetdb-databae的概念和作用-分析
摘要: 每个数据库对于db,schema以及user,role都有一套自己的设计, 不同数据库间对于相同名字的东西例如database和schema可以说南辕北辙, 例如mysql中schema其实是database的同义词. 本文分析monetdb的database的概念和作用 database的概念和作用: 和mysql的database完全不同…...
 
2024级199管理类联考之数学基础(上篇)
管理类考试介绍 管理综合200分,时间3小时 数学:75分/25题,是拉开差距的核心模块 问题求解题:15个,5选一条件充分性判断:10个,结合两个条件选择答案 条件一充分,条件二不充分:A条件一不充分,条件二充分:B条件一充分,条…...
 
RFID技术引领汽车零部件加工新时代
RFID技术的兴起引领了汽车零部件加工领域的新时代,作为一种利用无线电频率进行自动识别的技术,RFID技术能够快速、准确地识别物体并获取相关数据,在汽车零部件加工中,RFID技术具有重要的应用价值,可以提高生产效率、降…...
 
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
 
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
 
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
 
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
 
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
