【热闻】[Redis]Spring Boot中Redis Template集群配置
1、问题背景
在一个Spring boot项目中,需要使用redis作为缓存,于是将使用spring-boot-starter-data-redis,具体依赖如下:
org.springframework.boot spring-boot-starter-data-redis 2.0.4.RELEASE 在测试环境中,功能测试,压力测试,都没有发现问题,原因是测试环境中redis自行搭建,没有设置密码,但是上线后,Redis使用的是A***的Pass服务的集群,并设置密码,使用过程中发现如下问题:
redis负载高;redis异常,错误信息:com.lambdaworks.redis.RedisException: java.lang.IllegalArgumentException: Connection to XXX.XX.XXX.XXX:15000 not allowed. This connection point is not known in the cluster viewjava.lang.IllegalArgumentException: Connection to XXX.XX.XXX.XXX:15000 not allowed. This connection point is not known in the cluster viewConnection to XXX.XX.XXX.XXX:15000 not allowed. This connection point is not known in the cluster view2、问题分析+解决方法
2.1、redis负载过高问题
2.1.1、问题原因
原本打算看一下是否是代码逻辑问题导致redis负载过高,于是登录redis服务器使用monitor命令观察命令执行的频率,发现每执行一次命令都执行一次Auth password命令,说明连接池未正确使用导致执行一次命令创建一次连接,导致负载高 ,并且代码执行效率低 。
(资料图片仅供参考)
2.1.2、解决方法
然后对比了使用JedisCluster的项目没有此类问题,因此怀疑是spring-boot-starter-data-redis的RedisTemplate的问题,查看源码后发现spring-data-redis的驱动包在某个版本之后替换为 Lettuce,在启用集群后jedis的连接池无效。错误配置如下:
# 错误配置# Redis配置spring.redis.cluster.nodes=127.0.0.1:6379### 连接超时时间(毫秒)spring.redis.timeout=60000spring.redis.password=xxxxxxx# 连接池最大连接数(使用负值表示没有限制)spring.redis.jedis.pool.max-active=8##连接池最大阻塞等待时间,若使用负值表示没有限制spring.redis.jedis.pool.max-wait=-1##连接池中的最大空闲连接spring.redis.jedis.pool.max-idle=8# 连接池中的最小空闲连接spring.redis.jedis.pool.min-idle=0需要改成正确的配置,修改之后无此现象,具体配置如下:
单机版:
# 单机版# Redis配置spring.redis.host=127.0.0.1spring.redis.port=6379### 连接超时时间(毫秒)spring.redis.timeout=60000spring.redis.password=xxxxxxx# 连接池最大连接数(使用负值表示没有限制)spring.redis.jedis.pool.max-active=8##连接池最大阻塞等待时间,若使用负值表示没有限制spring.redis.jedis.pool.max-wait=-1##连接池中的最大空闲连接spring.redis.jedis.pool.max-idle=8# 连接池中的最小空闲连接spring.redis.jedis.pool.min-idle=0集群版:
#集群版 # Redis配置spring.redis.cluster.nodes=127.0.0.1:6379### 连接超时时间(毫秒)spring.redis.timeout=60000spring.redis.password=xxxxxxx# 连接池最大连接数(使用负值表示没有限制)spring.redis.lettuce.pool.max-active=8##连接池最大阻塞等待时间,若使用负值表示没有限制spring.redis.lettuce.pool.max-wait=-1##连接池中的最大空闲连接spring.redis.lettuce.pool.max-idle=8# 连接池中的最小空闲连接spring.redis.lettuce.pool.min-idle=0注意:启用集群版,需要额外添加如下依赖
org.apache.commons commons-pool2 2.8.0 2.2、redis异常 Connection to XXX.XX.XXX.XXX:15000 not allowed 问题
2.2.1、问题原因
网上搜索了一下,发现项目github上已有此问题的反馈以及解决办法github.com/lettuce-io/…,原因是由于Lettuce其中有个配置项validateClusterNodeMembership 默认是true导致;
2.2.2、解决办法
由于spring boot未能直接通过配置文件直接修改此配置,因此需要自定义Redis配置,具体代码如下: MylettuceConnectionFactory.java
package com.quison.test.config;import io.lettuce.core.AbstractRedisClient;import io.lettuce.core.cluster.ClusterClientOptions;import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;import io.lettuce.core.cluster.RedisClusterClient;import org.springframework.beans.DirectFieldAccessor;import org.springframework.data.redis.connection.RedisClusterConfiguration;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 java.util.concurrent.TimeUnit;public class MyLettuceConnectionFactory extends LettuceConnectionFactory { public MyLettuceConnectionFactory() { } public MyLettuceConnectionFactory(RedisClusterConfiguration redisClusterConfiguration, LettuceClientConfiguration lettuceClientConfiguration) { super(redisClusterConfiguration, lettuceClientConfiguration); } @Override public void afterPropertiesSet() { super.afterPropertiesSet(); DirectFieldAccessor accessor = new DirectFieldAccessor(this); AbstractRedisClient client = (AbstractRedisClient) accessor.getPropertyValue("client"); if(client instanceof RedisClusterClient){ RedisClusterClient clusterClient = (RedisClusterClient) client; ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder() .enablePeriodicRefresh(10, TimeUnit.MINUTES) .enableAllAdaptiveRefreshTriggers() .build(); ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder() // 注意此配置项设置为false .validateClusterNodeMembership(false) .topologyRefreshOptions(topologyRefreshOptions) .build(); clusterClient.setOptions(clusterClientOptions); } }}由于配置后,连接池也需要自行设置,因此Redis的配置文件修改为如下设置 RedisConfig.java
package com.quison.test.config;import org.apache.commons.pool2.impl.GenericObjectPoolConfig;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.boot.autoconfigure.data.redis.RedisProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Primary;import org.springframework.data.redis.connection.*;import org.springframework.data.redis.connection.lettuce.DefaultLettucePool;import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.serializer.RedisSerializer;import org.springframework.data.redis.serializer.StringRedisSerializer;import java.time.Duration;import java.util.Arrays;import java.util.HashSet;import java.util.Set;@Configurationpublic class RedisConfig { @Value("${spring.redis.cluster.nodes}") private String clusterNodes; @Value("${spring.redis.password}") private String password; @Value("${spring.redis.lettuce.pool.max-idle}") private Integer maxIdle; @Value("${spring.redis.lettuce.pool.max-active}") private Integer maxActive; @Value("${spring.redis.cluster.max-redirects}") private Integer maxRedirects; @Bean public RedisConnectionFactory myRedisConnectionFactory() { RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(); String[] serverArray = clusterNodes.split(","); Set nodes = new HashSet(); for (String ipPort : serverArray) { String[] ipAndPort = ipPort.split(":"); nodes.add(new RedisNode(ipAndPort[0].trim(), Integer.valueOf(ipAndPort[1]))); } redisClusterConfiguration.setPassword(RedisPassword.of(password)); redisClusterConfiguration.setClusterNodes(nodes); redisClusterConfiguration.setMaxRedirects(maxRedirects); GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig(); genericObjectPoolConfig.setMaxIdle(maxIdle); genericObjectPoolConfig.setMinIdle(8); genericObjectPoolConfig.setMaxTotal(maxActive); genericObjectPoolConfig.setMaxWaitMillis(10000); LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder() .commandTimeout(Duration.ofMillis(10000)) .poolConfig(genericObjectPoolConfig) .build(); return new MyLettuceConnectionFactory(redisClusterConfiguration, clientConfig); } /** * redis模板,存储关键字是字符串,值是Jdk序列化 * * @param myRedisConnectionFactory * @return * @Description: */ @Bean @ConditionalOnMissingBean(name = "redisTemplate") @Primary public RedisTemplate, ?> redisTemplate(RedisConnectionFactory myRedisConnectionFactory) { RedisTemplate, ?> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(myRedisConnectionFactory); //key序列化方式;但是如果方法上有Long等非String类型的话,会报类型转换错误; RedisSerializer redisSerializer = new StringRedisSerializer(); redisTemplate.setKeySerializer(redisSerializer); redisTemplate.setHashKeySerializer(redisSerializer); //默认使用JdkSerializationRedisSerializer序列化方式;会出现乱码,改成StringRedisSerializer StringRedisSerializer stringSerializer = new StringRedisSerializer(); redisTemplate.setKeySerializer(stringSerializer); redisTemplate.setValueSerializer(stringSerializer); redisTemplate.setHashKeySerializer(stringSerializer); redisTemplate.setHashValueSerializer(stringSerializer); return redisTemplate; }} 3、总结
吃一堑、长一智,总结如下:
开发+测试环境尽量与线上一致,可提前发现问题;使用新技术需要多多测试再投入生产使用;标签:
精彩推送
焦点日报:硅片价格上调,TCL中环10%涨停,光伏赛道回暖反弹,风来了!
3月6日,TCL中环(002129 SZ)10%涨停,成交额突破50亿元,是前一个交易日的5倍。到底发生了什么事?3...
新闻快讯
X 关闭
X 关闭
新闻快讯
- 【热闻】[Redis]Spring Boot中Redis Template集群配置
- 今日水准仪测标高计算公式怎么来的_水准仪测标高计算公式 热门看点
- 鲁珀特之泪怎样在家作_鲁珀特之泪 今日讯
- 孕酮低不能吃什么水果蔬菜_孕酮低不能吃什么水果
- 美国俄亥俄州一夜总会发生枪击事件 致2死4伤
- 宝宝感冒怎么办最快最有效_宝宝感冒怎么办
- 武昌工学院如何_武昌工学院怎样
- 焦点消息!马桶c为啥自杀(马桶c和夏天吵架录音)
- 腐叶土_关于腐叶土介绍_环球播报
- 2023年第一季度最值得关注的三款suv
- 次级债券是什么意思|天天微动态
- Mysteel周报:西南一周产经——川渝公布经济数据 西南价格再陷低洼-环球快消息
- 汽车平衡杆的作用是什么_汽车平衡杆的作用-世界热闻
- 环球热议:国乒比赛结果和最新赛程!陈梦等爆冷出局,马龙将和小小胖争名额
- 【热闻】演员王雷个人资料图片_演员王雷个人资料
- 成都2023年美团春季校招报名入口
- 永创智能: 独立董事关于第四届董事会第二十六次会议相关事项的独立意见
- 国电南自: 国电南自关于诉讼进展的公告-每日热闻
- 商务部:第133届广交会定于4月15日至5月5日分三期在广州举办
- 4强对阵出炉!国乒2大世界冠军晋级,樊振东3:0,半决赛对阵日本 环球热推荐
- 广东电视体育频道直播高清_广东电视体育频道直播
- 振华新材(688707):3月16日北向资金增持3.88万股
- 中国科学家发现两种新矿物 环球速递
- 艺体女神赵敬楠,退役成大学校花,27岁颜值高,完全不愁工作
- 久远银海2022年度拟10派1元-最新资讯
- 世界今头条!用尽我的一切奔向你歌曲下载_用尽我的一切奔向你mp3下载
- 夹丝玻璃厚度多少合适_夹丝玻璃厚度
- 全球今亮点!康普化学2022年订单大幅增加 营收利润实现大幅增长
- 橄榄陨石对人体的功效_橄榄陨石 环球快消息
- 光大信用卡终审怎么查
- 中甲开赛待定,广州队或宣布解散,球队至今未恢复训练-信息
- 世界热点!大连某海鲜加工厂涉嫌违法添加非食用物质问题,公安机关开展刑事调查
- 全球报道:甘肃设百余个“新就业形态劳动者驿站”维护职工权益
- 新能源汽车订阅收费不止 网友调侃以后刹车功能都得包月 世界播报
- 故宫“月令承应戏”将有望复现舞台
- 【速看料】隧蜂的生活习性(隧蜂)
- 全球热头条丨电池ETF:融资净偿还456.59万元,融资余额1.04亿元(03-14)
- 天天热推荐:宝宝暴龙什么性格好_宝宝暴龙
- 全球快消息!一件十分可气的事,我国再次遭到土耳其背刺!
- 环球即时看!科陆卖身,美的笑纳
- 山东雷诺服饰有限公司 焦点信息
- 环球观天下!山东雅士客建筑科技有限公司
- 《逃出白垩纪》定档 史前地球濒死逃生|视焦点讯
- 全球动态:川宁生物主营产品涨价净利增2.7倍 募投2亿增强研发实力布局合成生物
- 世界速看:艾美疫苗(06660.HK)股价异动 未知悉原因
- 广州西关在哪个位置_广州西关在哪里
- 所罗门群岛面积(所罗门群岛美女)
- 新加坡金管局:新加坡银行系统对硅谷银行的风险敞口不大 初创企业目前受到的影响有限
- 上海造老银元价格(2023年03月13日) 每日焦点
- 疼痛是病 忍痛不成徒“伤心”