[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 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 Template集群配置
- 企业裁员银行关闭 硅谷进入“凛冬”
- 亚光股份股价飙升10.01% 市值46.17亿元-今日讯
- 每日头条!童年人物介绍及性格特点_童年人物介绍
- 今日快看!小事记|北京西长安中骏世界城开业 福州数字内容产业园31%股权挂牌
- 世界快报:光怪陆离一般形容什么_光怪陆离用法
- 厄瓜多尔突发6.8级地震 至少14人遇难
- 女生经常化妆,皮肤会变差是真的吗?听专业人员讲出“实情”-全球短讯
- 武汉市东西湖举办土地推介会,1652亩优质地块集中亮相
- 全球看点:冲田三叶为什么死了_冲田三叶
- 多边形的内角和公式-焦点关注
- 单相电表怎么接线_单相电表|天天观察
- 天天即时:拯救者新机配置直接发,还有大尺寸平板
- 长安忆歌词赏析_长安忆歌词
- 全筑股份被苏州吴江区法院列为被执行人|每日消息
- 今年如果你是重资产运营,请赶紧打开这条内容! 环球滚动
- 3月17日基金净值:易方达科创板50ETF联接A最新净值0.7933,涨2.19%|全球即时看
- 半导体:美国走日本的路让日本无路可走,中国走美国的路让美国走头无路
- 嵌在老战士体内72年的弹片取出来了,致敬英雄!
- 重压下彰显经营韧性,屈臣氏持续盈利的秘诀是什么?_天天看热讯
- ChatGPT Plus 订阅现已在印度推出:支持最新 GPT-4_全球新消息
- 遥望科技(002291)3月17日13点0分触及涨停板
- CATL Ramps Up Expansion in Europe with New Deal Targeting Supply 10GWh Battery Energy
- 常茂生物发盈喜 预期年度净利约7000万至9000万元 全球速看料
- 罗贯中_说一说罗贯中的简介
- 美国财长耶伦:在硅谷银行倒闭危机后 美国银行业依然稳健-热消息
- 世界微速讯:陕科大牵手泾河谋发展
- 当前速读:逃跑吧少年新角色碧羽技能介绍_蛤蟆力的角色介绍
- 北京首钢开售对阵新疆男篮门票:经通知比赛如期举行 快消息
- 环球时讯:长沙高新消防开展“严纪律、强作风、促养成、保稳定” 队列会操评比赛
- 两市股指早盘弱势震荡,创业板指下跌近1%
- 天奇股份:3月15日融资买入351.29万元,融资融券余额1.27亿元_每日资讯
- 蓝晶 ID.6 CROZZ 全新数字高尔夫GTI推出一汽-大众领先上海车展 天天快消息
- 天天快消息!我愿化身一座石桥_我愿化身一座石桥
- 新鲜的柠檬泡水喝有什么功效_柠檬泡水喝有什么功效-世界观天下
- 观热点:南美足协公布2026年世预赛赛程 首回合巴阿大战定于今年11月
- 前沿热点:记者:保利尼奥归队参与海港合练,陈彬彬髌韧带断裂需半年康复
- 全球今热点:碧玺怎么辨别真假_如何辨别蜂胶真假以及优劣
- 山东高瓴家具有限公司 环球即时
- 天天日报丨京瓷打印机官方网站_京瓷打印机售后电话
- 美媒:美国硅谷银行倒闭前悄悄裁员超100人
- 世界观察:新朋股份:3月14日融资买入920.87万元,融资融券余额1.58亿元
- 红痘印一般多久会消失_痘印一般多久会消失
- 女高怪谈4声音_女高怪谈4_环球快看点
- 每日看点!不乐无语_关于不乐无语的介绍
- Metaverse似乎是颠覆数字世界的下一件大事
- 上海建工为17家子公司合计提供16.64亿元的担保
- 当前简讯:京西之地不仅有闻名的潭柘寺和妙峰山,还有个令人感叹的“举人村”
- 三峡水利董秘回复:公司2022年年度报告拟于2023年4月20日在上海证券交易所网站披露 环球速读
- 环球快看点丨河南尉氏县水坡镇发展产业种植见成效:莴笋迎丰收 村民乐开花
- 扣税工资的计算公式_扣税工资怎么计算
- 天天速讯:为什么腊八蒜是绿的?
- 供销结算合同范本(热门40篇)
- 谷歌和微软韩国分公司已经开始裁员 提供遣散费和补偿金-天天快播
X 关闭
最新资讯
- 送老人什么生日礼物好呢_送老人什么生日礼物好
- 《“机器人+”应用行动实施方案》将在一定程度上缓解人口总数下降带来的影响 | 中国观察
- 全球新动态:招商信诺终身年金保险A款(互联网专属)真的好吗?优缺点是啥?
- GUVNL浮动500兆瓦风力投标与绿鞋选项
- 天天滚动:热苏斯伤愈归队!在对阵富勒姆的比赛中回到了阿森纳的替补席
- 今日热搜:九子夺嫡的胜出者雍正,为何独独对废太子胤礽礼遇有加?
- 天天微头条丨毛利率计算公式_分子有理化计算公式
- 忌安香是什么意思_忌安香的意思
- 古墓丽影8攻略第二关_古墓丽影8攻略
- 世界观速讯丨「纵观」皮带秤定量给料机给我们带来的思考
- 今日精选:蒙太奇自行车是哪国的_蒙太奇自行车官网
- 微笑的星
- 欧盟欢迎沙特和伊朗宣布恢复外交关系
- 5级地震严不严重_5级地震严重程度
- 房产资讯:CharlieLuxtonDesign翻新并扩建科茨沃尔德平房 环球聚焦
- 小S公开大胆挑衅,汪小菲罕见沉默!他已戒掉情绪,开始疯狂计划_微头条
- 名字速配
- 怒气冲冲_怒气冲冲的意思_今亮点
- 无限斯特拉托斯第二季_无限娱乐吧
- 青岛博士整形医院_青岛博士整形
- 紫外荧光油墨_关于紫外荧光油墨介绍
- 百事通!哪位航海家发现了好望角?_好望角是哪国航海家谁的船队命名的
- 天天视点!“和平统一救台湾”:新党元老王建煊躬身入局
- 荒野乱斗国际服什么时候更新_荒野乱斗国际服
- 2019春晚小品全集版_2019春晚小品全集
- 京东集团:2022全年收入10462亿元,同比增9.9%
- 让闲置房屋变增收“活水”!“622+1”模式正式入驻息烽县 天天新要闻
- “为漂亮买单,更要为健康买单”——女性成体育消费市场新主力
- 刷牙的时候牙齿出血是什么原因_牙齿出血是什么原因
- 世界gdp排名2021最新排名,前20国家名单一览-天天短讯
- 快消息!小米13飓风黄现货:12+512G卖4999元 比iPhone 14黄色128G还便宜
- 余额宝转入服务怎么抢购_余额宝最新消息
- 天天观察:京东集团2022年净收入首次突破1万亿元,归母净利润104亿元
- 再次对决!辽宁盼主场完成复仇,山东迎来超级外援,想赢不容易|每日热讯
- 建安区先进制造业开发区举办纪念“三八”妇女节暨廉洁家风故事宣讲活动 当前关注
- 环球今日讯!衣服吊牌内容是谁提供_衣服吊牌内容
- 焦点热文:营养师报考条件2022最新规定_化验员资格证怎么考
- 全球热讯:春夜宴_对于春夜宴简单介绍
- 全球观热点:明朝万户是多大的官_明朝万户
- 世界最新:网友突击式检查世界各地大熊猫具体详细内容是什么
- 颈动脉的斑块,我要拿你怎么办?颈动脉斑块出现之后应该怎么做
- p2p下载器怎么避免垃圾软件_p2p下载器怎么卸载 全球热资讯
- 香港航天科技(01725)为Aspace引入机构投资者 持股降至51%-环球热资讯
- 全球观热点:广州租车自驾价格 广州租车自驾价格
- 【当前独家】麦当劳香骨鸡腿做法_麦当劳香骨鸡盒
- 环球热推荐:Mysteel日报:合肥冷轧及镀锌板卷价格暂稳
- 什么是小冰河期 小冰河期出现的原因是什么 独家
- 克莱:我们进攻可以但防守不好 想扭转局势就得改善一些东西 世界观察
- 肉类的营养价值-世界快讯
- 济宁居住登记在哪里办理(网上+现场)|环球今亮点
X 关闭