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 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、总结
吃一堑、长一智,总结如下:
开发+测试环境尽量与线上一致,可提前发现问题;使用新技术需要多多测试再投入生产使用;关键词:
推荐内容
- 全球热讯:[Redis]Spring Boot中Redis T
- 今日热议:卧牛山二月兰绽放,紫色花海吸
- 环球视点!杭州下周雨水连轴转 升温有消
- 实时焦点:网页游戏修改工具软件_网页游
- 环球新消息丨U20亚洲杯:乌兹别克斯坦1-0
- 播报:以案说险:修改绑定银行卡须“验资
- 实时:2023年3月18日河南省焦炭价格最新
- 环球快资讯:三个月时间能考过中级会计师
- 世界观热点:stp用什么软件打开最快_stp
- 天天百事通!苹果手机店门头_苹果手机店
- 天天资讯:延华智能:股东拟减持不超过6.
- 世界微资讯!金道科技:已与公司开展合作
- 焦点速看:意大利能源公司在墨西哥湾发现
- 视讯!南向资金今日净买入22.5亿港元 净
- 天天讯息:中国儿童活动中心网上报名_中
- 【独家】厦门清明扫墓集中开放时间
- 焦点短讯!金丹期元婴期后面是什么_金丹期
- 视讯!龙津药业(002750)3月16日主力资
- 世界速讯:神笔马良手抄报简单又漂亮_神
- 今日精选:福建国庆旅游线路推荐
- 全球新资讯:3月16日晚间重要公告集锦
- 天天观热点:中国版chatGPT来了,未来,
- 世界快播:山东鲁盾聚氨酯制品有限公司
- 天天实时:口苦舌苔厚白吃什么药最好_舌
- 当前消息!361度:2022年年权益持有人应
- 每日热门:安全员证件查询系统官网查询网
- 每日快播:北京至黄山旅游专列月底首发
- 世界新消息丨工资代发是什么意思啊
- 每日观察!脑胶质瘤二级能活多久_脑胶质瘤
- 焦点速看:大专学历即可落户杭州!广深会
- 天天实时:山东将调整优化地方储备粮规模
- 世界最资讯丨消费维权科普进社区、进学校
- 当前要闻:什么叫车损险
- 世界微速讯:研究报告作文五年级500字优
- 观焦点:与其担心3·15 不如抓好365
- 【环球快播报】autocad不能打开此dwg文件
- 天天快消息!上海购物中心排名_上海购物
- 焦点滚动:亮剑第二部为什么不播_亮剑 第
- 全球观速讯丨(微病娇)致最喜欢的你
- 世界热讯:渭南交警:警民同携手 共建文
- 天天视讯!养老资格认证怎么认证 2023年
- 头条焦点:四个火念什么(四个火念什么)
- 世界速递!3月13日国内蚕蛹市场行情
- 焦点快播:虎奔教育官方网站登录_虎奔教育
- 当前头条:今日李沁演花开半夏的时候多少
- 天天热推荐:虹口区教育局官方网站(虹口
- 世界信息:广州天河区兴华街道办事处地址
- 【全球时快讯】cad怎么把直角变圆角(cad
- 天天速讯:舞曲下载到u盘里_如何将舞曲下
- 环球热点评!柔道欧洲公开赛意大利站中国
- 全球快播:关山千万重下一句_关山万千重
- 全球焦点!福建:海上生产“加速度”
- 当前视点!平安基金张晓泉: 不预设赛道
- 简讯:[Golang]Goroutine基础
- 热点聚焦:严正公告
- 环球今头条!小鲫鱼怎么做好吃简单方法_
- 天天精选!逗比人生阿尔法狗攻略_逗比人
- 精选!梅西竟成反向斯特林:右脚抡空左脚
- 热点在线丨荣耀盒子怎么下载当贝市场
- 焦点讯息:犯罪过失损坏交通设施需要负什
- 全球新资讯:3月16日晚间重要公告集锦
- 天天观热点:中国版chatGPT来了,未来,
- 世界快播:山东鲁盾聚氨酯制品有限公司
- 天天实时:口苦舌苔厚白吃什么药最好_舌
- 当前消息!361度:2022年年权益持有人应
- 每日热门:安全员证件查询系统官网查询网
- 每日快播:北京至黄山旅游专列月底首发
- 世界新消息丨工资代发是什么意思啊
- 每日观察!脑胶质瘤二级能活多久_脑胶质瘤
- 焦点速看:大专学历即可落户杭州!广深会
- 天天实时:山东将调整优化地方储备粮规模
- 世界最资讯丨消费维权科普进社区、进学校
- 当前要闻:什么叫车损险
- 世界微速讯:研究报告作文五年级500字优
- 观焦点:与其担心3·15 不如抓好365
- 【环球快播报】autocad不能打开此dwg文件
- 天天快消息!上海购物中心排名_上海购物
- 焦点滚动:亮剑第二部为什么不播_亮剑 第
- 全球观速讯丨(微病娇)致最喜欢的你
- 世界热讯:渭南交警:警民同携手 共建文
- 天天视讯!养老资格认证怎么认证 2023年
- 头条焦点:四个火念什么(四个火念什么)
- 世界速递!3月13日国内蚕蛹市场行情
- 焦点快播:虎奔教育官方网站登录_虎奔教育
- 当前头条:今日李沁演花开半夏的时候多少
- 天天热推荐:虹口区教育局官方网站(虹口
- 世界信息:广州天河区兴华街道办事处地址
- 【全球时快讯】cad怎么把直角变圆角(cad
- 天天速讯:舞曲下载到u盘里_如何将舞曲下
- 环球热点评!柔道欧洲公开赛意大利站中国
- 全球快播:关山千万重下一句_关山万千重
- 全球焦点!福建:海上生产“加速度”
- 当前视点!平安基金张晓泉: 不预设赛道
- 简讯:[Golang]Goroutine基础
- 热点聚焦:严正公告
- 环球今头条!小鲫鱼怎么做好吃简单方法_
- 天天精选!逗比人生阿尔法狗攻略_逗比人
- 精选!梅西竟成反向斯特林:右脚抡空左脚
- 热点在线丨荣耀盒子怎么下载当贝市场
- 焦点讯息:犯罪过失损坏交通设施需要负什
- 视点!新车报讯:现代伊兰特N最新预告图
- 当前讯息:九章算术的作者祖冲之_九章算
- 当前资讯!北川美幸
- 环球今头条!文旅“内卷”?福建的副市长
- 热点!怎样修改照片大小为200k_怎样修改
- 全球热点评!安眠药哪种效果好 知乎_安
- 全球热资讯!连帽卫衣里面穿什么好_卫衣
- 【全球快播报】沈阳地铁二号线线路图图片
- 动态焦点:儿童血红蛋白正常值范围_高铁血
- 今日关注:妇女节表彰大会上,为什么领奖
- 每日热闻!红枣银耳羹的做法视频_红枣银耳
- 世界快资讯:好儿不争娘田地好女不争嫁时
- 当前时讯:今天最新消息 城乡双向经济循
- 当前要闻:阳了应该怎么办-阳性感染者如
- 当前看点!枸骨是否有抗癌的功效_枸骨是什
- 环球要闻:输掉榜首大战!C罗差点又扔队
- 【报资讯】客观的意思有哪些_客观的意思
- 【世界热闻】qq群发怎么发所有人
- 快看点丨梦色糕点师安利_梦色糕点师之希逸
- 世界最资讯丨新媒:中美经贸关系“分手很