天天精选![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服务的集群,并设置密码,使用过程中发现如下问题:
【资料图】
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 view
2、问题分析+解决方法
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、总结
吃一堑、长一智,总结如下:
开发+测试环境尽量与线上一致,可提前发现问题;使用新技术需要多多测试再投入生产使用;关键词:
上一篇:“五小”创新有我在|“晾衣杆”改造,吊顶空间布线不再“爬上爬下”
下一篇:最后一页
- 广州科技活动周进入预热 明日正式启动300多场主题活动接踵而来
- 深化重点领域信用建设 广州正式出台新型监管机制实施方案
- 女童不慎掉入20米深井 18岁小姨三次下井成功营救
- 西安3个区域12月28日起每日开展全员核酸 官方提倡民众居家健身
- 浙江乐清一核酸检测结果异常人员 复采复检为阴性
- 浙江本轮疫情报告确诊病例490例 提倡“双节”非必要不出省
- 西安警方通报6起涉疫违法案件
- 西安新一轮核酸筛查日检测能力达160万管
- 西安市累计报告本土确诊病例811例
- 重庆曝光4起违反中央八项规定精神典型问题 警示党员干部清新过节
-
让农民工不再忧“薪” 湖南祁阳高效根治欠薪
中新网永州12月28日电 (刘志军 周盛波)“感谢你们,没有你们不辞辛苦、多次讨要,我们肯定拿不着钱,这个年肯定过不好。”27日,农民
-
浙江缙云九旬老党员20多年义务为乡村老人理发
中新网丽水12月28日电(范宇斌 蒋依笑)在浙江省丽水市缙云县七里乡大园村周坎头自然村,今年90岁的陶岳贵在年近古稀时拾起剃刀,20多年
-
疫情下的边城东兴:停摆的城 夜行的人
(抗击新冠肺炎)疫情下的边城东兴:停摆的城 夜行的人 中新社广西东兴12月28日电 题:疫情下的边城东兴:停摆的城 夜行的人
-
长江流域生态管护员:我与长江的十年之约
中新网江西彭泽12月28日电 (袁昕 记者 王昊阳)“这是我今天第三次巡查了。”穿着新制服的长江流域生态管护员吴成年站立船头,在
-
吉林查干湖冬捕启幕 头鱼拍出2999999元
中新网松原12月28日电 (石洪宇 谭伟旗 薛栋栋)中国查干湖第二十届冰雪渔猎文化旅游节28日开幕,数万名游客现场直击鱼跃湖面的盛况。
-
甘肃中药炮制师研习古法30载:掌心留痕,翻烂资料书
中新网兰州12月28日电 (张婧)从事中药饮片加工技艺30年的张良,右手掌心有一条老疤痕,“20年前跟着老师傅学习中药材性状鉴别,传统方
-
广东启用涉疫风险人员排查12320专号
中新网广州12月28日电 (记者 蔡敏婕)广东省28日正式启用涉疫风险人员排查12320专号。即日起,涉疫风险人员来(返)粤前可在“粤省事”
-
武汉协和医院开设互联网儿童医学中心
中新网武汉12月28日电 (聂文闻 彭锦弦 陈有为)记者28日从华中科技大学附属协和医院(以下简称“武汉协和医院”)获悉,该院在湖北省首
-
四川:力争三年完成638个历史遗留矿山生态修复
中新网成都12月28日电 (杨予頔)28日,四川省自然资源厅发布消息称,近日,四川省自然资源厅印发了《四川省历史遗留矿山生态修复三年行
-
不同养老模式共同推进 提升老年福祉 让老人享受“温暖夕阳”
我为群众办实事 | 不同养老模式共同推进 提升老年福祉 让老人享受“温暖夕阳” 央视网消息:近期,各地在“我为群众办实事”实
X 关闭
西安新增本土确诊病例150例 详情发布
广东最低气温跌至-6℃现冰挂 部分道路及海上交通受影响
“2022科学跨年系列活动”启动 提高公众对科学类流言“免疫力”
珠科院多举措助力大湾区抗旱防咸保供水
只为那片美丽的云顶 河北一“守峰人”海拔2000米驻守12载
X 关闭
“五小”创新有我在|“晾衣杆”改造,吊顶空间布线不再“爬上爬下”
加速线上布局,注重文化与社会责任,国产服装品牌这样扩大影响力! 环球新动态
学生画出一幅幅春天的画卷|全球快看
南网科技(688248)3月16日主力资金净卖出5021.55万元
【天天聚看点】夏洛克吧_夏洛克同人bl