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

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默认是没有开始拓扑更新及读写分离导致的


解决方案:

这里分为几种情况:

  1. springboot 1.x之前版本默认使用jedis,无需要手动开启刷新
  2. springboot 2.x默认为Lettuce,需要代码设置开启刷新节点拓扑策略
  3. 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集群拓扑动态刷新

项目场景&#xff1a; Spring Boot集成Redis集群&#xff0c;使用lettuce连接Cluster集群实例。 问题描述 redis其中一个节点挂了之后&#xff0c;springboot集成redis集群配置信息没有及时刷新&#xff0c;出现读取操作报错。 java.lang.IllegalArgumentException: Connec…...

COCI2022-2023#1 Neboderi

P9032 [COCI2022-2023#1] Neboderi 题目大意 有一个长度为 n n n的序列 h i h_i hi​&#xff0c;你需要从中选择一个长度大于等于 k k k的子区间 [ l , r ] [l,r] [l,r]&#xff0c;使得 g ( h l h l 1 ⋯ h r ) g\times (h_lh_{l1}\cdotsh_r) g(hl​hl1​⋯hr​)最小&…...

由于找不到d3dx9_43.dll无法继续执行此代码怎么解决?全面解析d3dx9_43.dll

在使用计算机过程中&#xff0c;我们可能会遇到各种各样的问题。其中之一就是d3dx9_43.dll文件丢失的问题。这个问题通常会出现在运行某些应用程序或游戏时&#xff0c;导致程序无法正常启动或运行。那么&#xff0c;如何解决这个问题呢&#xff1f;小编将为您提供一些解决方案…...

Linux--网络编程-字节序

进程间的通信&#xff1a; 管道、消息队列、共享内存、信号、信号量。 特点&#xff1a;都依赖于linux内核。 缺陷&#xff1a;无法多机通信。 一、网络编程&#xff1a; 1、地址&#xff1a;基于网络&#xff0c;ip地址端口号。 端口号作用&#xff1a; 一台拥有ip地址的主机…...

python实现http/https拦截

python实现http拦截 前言:为什么要使用http拦截一、技术调研二、技术选择三、使用方法前言:为什么要使用http拦截 大多数爬虫玩家会直接选择API请求数据,但是有的网站需要解决扫码登录、Cookie校验、数字签名等,这种方法实现时间长,难度高。需求里面不需要高并发,有没有…...

农产品团购配送商城小程序的作用是什么

农产品覆盖稻麦油蛋等多种细分类目&#xff0c;各地区经营商家众多&#xff0c;随着人们生活品质提升&#xff0c;对食物的要求也在提升&#xff0c;绿色无污染无激素的农产品往往受到不少人喜爱&#xff0c;而在销售中&#xff0c;也有不少人选择自建商城线上经营。 通过【雨…...

使用van-dialog二次封装微信小程序模态框

由于微信小程序的wx.showModal不支持富文本内容&#xff0c;无法实现更灵活的展示效果&#xff0c;故需要进行二次封装 实现思路&#xff1a;使用van-dialog以及微信小程序的rich-text实现 代码如下&#xff1a; // index.wxml <van-dialoguse-slottitle"提示"s…...

生鲜蔬果同城配送社区团购小程序商城的作用是什么

生鲜蔬果行业作为市场主要支撑之一&#xff0c;从业商家众多的同时消费者也从不缺&#xff0c;尤其对中高城市&#xff0c;生鲜蔬果除了传统线下超市、市场经营外&#xff0c;线上更是受到大量消费者信任&#xff0c;而很多商家也是自建了生鲜蔬果商城多场景生意经营。 那么通…...

Unity实现设计模式——状态模式

Unity实现设计模式——状态模式 状态模式最核心的设计思路就是将对象的状态抽象出一个接口&#xff0c;然后根据它的不同状态封装其行为&#xff0c;这样就可以实现状态和行为的绑定&#xff0c;最终实现对象和状态的有效解耦。 在实际开发中一般用到FSM有限状态机的实现&…...

差分数组的应用技巧

前缀和技巧 针对的算法场景是不需要对原始数组进行修改的情况下&#xff0c;频繁查询某个区间的累加和。 差分数组 主要适用场景是频繁对原始数组的某个区间的元素进行增减。 相关题目 1094. 拼车 1109. 航班预订统计 370. 区间加法 # 1094. 拼车 class Solution:def carPool…...

斯坦福数据挖掘教程·第三版》读书笔记(英文版)Chapter 10 Mining Social-Network Graphs

来源&#xff1a;《斯坦福数据挖掘教程第三版》对应的公开英文书和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&#xff0c;将数字 1∼n1∼n 排成一排&#xff0c;将会有很多种排列方法。 现在&#xff0c;请你按照字典序将所有的排列方法输出。 输入格式 共一行&#xff0c;包含一个整数 nn。 输出格式 按字典序输出所有排列方案&#xff0c;每个方案占一行。 数据…...

pytorch之nn.Conv1d详解

自然语言处理中一个句子序列&#xff0c;一维的&#xff0c;所以使用Conv1d...

H5生成二维码

H5生成二维码&#xff1a; 1.引入js库&#xff0c;可自行点击链接复制使用 <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场景中将贴图与球形网格模型融合&#xff0c;将球模型当做成环境容器使用处理视频时需要以dom为载体&#xff0c;加载与控制视频动作每次渲染时更新当前texture&#xff0c;以达到视频播放效…...

北大硕士7年嵌入式学习经验分享

阶段 1 大一到大三这个阶段我与大多数学生相同&#xff1a; 学习本专业知识&#xff08;EE专业&#xff09;&#xff0c;学习嵌入式软件开发需要的计算机课程&#xff08;汇编原理&#xff0c;计算机组成原理&#xff0c;操作系统&#xff0c;C语言等&#xff09;&#xff0c…...

华为鸿蒙手表开发之动态生成二维码

华为鸿蒙手表开发之动态生成二维码 前言&#xff1a; 最近入职新公司&#xff0c;由于之前的哥们临时离职&#xff0c;走得很突然&#xff0c;所以没有任何交接和文档&#xff0c;临时顶上公司手表应用的上架&#xff0c;更换了新的密钥和key之后重新测试功能和流程&#xff…...

2023-09-28 monetdb-databae的概念和作用-分析

摘要: 每个数据库对于db,schema以及user,role都有一套自己的设计, 不同数据库间对于相同名字的东西例如database和schema可以说南辕北辙, 例如mysql中schema其实是database的同义词. 本文分析monetdb的database的概念和作用 database的概念和作用: 和mysql的database完全不同…...

2024级199管理类联考之数学基础(上篇)

管理类考试介绍 管理综合200分,时间3小时 数学&#xff1a;75分/25题,是拉开差距的核心模块 问题求解题&#xff1a;15个,5选一条件充分性判断&#xff1a;10个,结合两个条件选择答案 条件一充分,条件二不充分&#xff1a;A条件一不充分,条件二充分&#xff1a;B条件一充分,条…...

RFID技术引领汽车零部件加工新时代

RFID技术的兴起引领了汽车零部件加工领域的新时代&#xff0c;作为一种利用无线电频率进行自动识别的技术&#xff0c;RFID技术能够快速、准确地识别物体并获取相关数据&#xff0c;在汽车零部件加工中&#xff0c;RFID技术具有重要的应用价值&#xff0c;可以提高生产效率、降…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...