spring redis cluster Lettuce 拓扑刷新
一、背景
最近项目中 3主3从 redis集群出现单节点宕机,造成master迁移,但是发现应用无法正常连接redis,使用的是Lettuce连接方式。
二、原因分析
分析了代码,发现默认Lettuce是不会刷新拓扑io.lettuce.core.cluster.models.partitions.Partitions#slotCache,最终造成槽点查找节点依旧找到老的节点,自然访问不了了。
槽点计算
io.lettuce.core.cluster.SlotHash#getSlot(java.lang.String)
io.lettuce.core.cluster.SlotHash#getSlot(byte[])
/*** Calculate the slot from the given key.** @param key the key* @return slot*/public static int getSlot(ByteBuffer key) {int limit = key.limit();int position = key.position();int start = indexOf(key, SUBKEY_START);if (start != -1) {int end = indexOf(key, start + 1, SUBKEY_END);if (end != -1 && end != start + 1) {key.position(start + 1).limit(end);}}try {if (key.hasArray()) {return CRC16.crc16(key.array(), key.position(), key.limit() - key.position()) % SLOT_COUNT;}return CRC16.crc16(key) % SLOT_COUNT;} finally {key.position(position).limit(limit);}}
根据槽点查找节点
redis集群总共16384个槽点。
返回的节点对象类似:
RedisClusterNodeSnapshot [uri=RedisURI [host=‘127.0.0.1’, port=7004], nodeId=‘93e0fa29f8639a2e11015736532a0d186f0ab8e9’, connected=true, slaveOf=‘null’, pingSentTimestamp=0, pongReceivedTimestamp=1569735410781, configEpoch=9, flags=[MASTER], slot count=5461]
/*** Retrieve a {@link RedisClusterNode} by its slot number. This method does not distinguish between masters and slaves.** @param slot the slot* @return RedisClusterNode or {@literal null}*/public RedisClusterNode getPartitionBySlot(int slot) {return slotCache[slot];}
三、修改
1、分析步骤
是否启动拓扑刷新的逻辑源码
private void activateTopologyRefreshIfNeeded() {if (getOptions() instanceof ClusterClientOptions) {ClusterClientOptions options = (ClusterClientOptions) getOptions();ClusterTopologyRefreshOptions topologyRefreshOptions = options.getTopologyRefreshOptions();if (!topologyRefreshOptions.isPeriodicRefreshEnabled() || clusterTopologyRefreshActivated.get()) {return;}if (clusterTopologyRefreshActivated.compareAndSet(false, true)) {ScheduledFuture<?> scheduledFuture = genericWorkerPool.scheduleAtFixedRate(clusterTopologyRefreshScheduler,options.getRefreshPeriod().toNanos(), options.getRefreshPeriod().toNanos(), TimeUnit.NANOSECONDS);clusterTopologyRefreshFuture.set(scheduledFuture);}}}
刷新拓扑的逻辑源码
/*** Update the partition cache. Updates are necessary after the partition details have changed.*/public void updateCache() {synchronized (partitions) {if (partitions.isEmpty()) {this.slotCache = EMPTY;this.nodeReadView = Collections.emptyList();return;}RedisClusterNode[] slotCache = new RedisClusterNode[SlotHash.SLOT_COUNT];List<RedisClusterNode> readView = new ArrayList<>(partitions.size());for (RedisClusterNode partition : partitions) {readView.add(partition);for (Integer integer : partition.getSlots()) {slotCache[integer.intValue()] = partition;}}this.slotCache = slotCache;this.nodeReadView = Collections.unmodifiableCollection(readView);}}
spring boot redisConnectionFactory生成源码,里面预留了钩子,可以注入自定的逻辑。
@Bean@ConditionalOnMissingBean(RedisConnectionFactory.class)public LettuceConnectionFactory redisConnectionFactory(ClientResources clientResources) throws UnknownHostException {LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(clientResources, this.properties.getLettuce().getPool());return createLettuceConnectionFactory(clientConfig);}// 最终执行到这private void customize(LettuceClientConfiguration.LettuceClientConfigurationBuilder builder) {// customizer 补充逻辑,刷新拓扑的设置就通过这里执行for (LettuceClientConfigurationBuilderCustomizer customizer : this.builderCustomizers) {customizer.customize(builder);}}
所以只要在预留的LettuceClientConfigurationBuilderCustomizer中追加刷新拓扑逻辑即可。
2、修改步骤
新增MyLettuceClientConfigurationBuilderCustomizer bean接口
package com.migu.clipcloud.core.cache.redis;import io.lettuce.core.cluster.ClusterClientOptions;
import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
import org.springframework.boot.autoconfigure.data.redis.LettuceClientConfigurationBuilderCustomizer;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.stereotype.Component;import java.time.Duration;/*** @Auther: csp* @Description: 处理Lettuce 集群拓扑刷新* @Date: Created in 2019/9/28 下午12:02* @Modified By:*/
@Component
public class MyLettuceClientConfigurationBuilderCustomizer implements LettuceClientConfigurationBuilderCustomizer {/*** Customize the {@link LettuceClientConfigurationBuilder}.** @param clientConfigurationBuilder the builder to customize*/@Override public void customize(LettuceClientConfiguration.LettuceClientConfigurationBuilder clientConfigurationBuilder) {/*ClusterTopologyRefreshOptions配置用于开启自适应刷新和定时刷新。如自适应刷新不开启,Redis集群变更时将会导致连接异常!*/ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()//开启自适应刷新
// .enableAdaptiveRefreshTrigger(ClusterTopologyRefreshOptions.RefreshTrigger.MOVED_REDIRECT, ClusterTopologyRefreshOptions.RefreshTrigger.PERSISTENT_RECONNECTS).enableAllAdaptiveRefreshTriggers().adaptiveRefreshTriggersTimeout(Duration.ofSeconds(10))//开启定时刷新,时间间隔根据实际情况修改.enablePeriodicRefresh(Duration.ofSeconds(15)).build();clientConfigurationBuilder.clientOptions(ClusterClientOptions.builder().topologyRefreshOptions(topologyRefreshOptions).build());}
}
至此,可以实现拓扑的自动刷新
微信扫一扫关注该公众号
spring redis cluster Lettuce 拓扑刷新相关推荐
- Redis Client Lettuce 5 GA发布
经过13个月的开发阶段和208张已解决的故障单,我很高兴宣布Lettuce 5.0全面上市. 这是一个主要发行版,带有一些重大更改,新的有趣功能以及Java 9兼容性. 从Maven Central获 ...
- Redis Cluster深入与实践(续)
前文回顾 上一篇文章基于redis的分布式锁实现写了基于redis实现的分布式锁.分布式环境下,不会还使用单点的redis,做到高可用和容灾,起码也是redis主从.redis的单线程工作,一台物理机 ...
- redis cluster中添加删除重分配节点例子
redis cluster中添加删除重分配节点例子 作者:用户 来源:互联网 时间:2016-05-05 10:22:27 摘要: 本文讲的是redis cluster中添加删除重分配节点例子, re ...
- Spring Boot整合Redis缓存(Lettuce)
spring-boot-demo-cache-redis 此 demo 主要演示了 Spring Boot 如何整合 redis,操作redis中的数据,并使用redis缓存数据.连接池使用 Lett ...
- Spring Boot Redis Cluster 实战干货
转载自 Spring Boot Redis Cluster 实战干货 添加配置信息 spring.redis:database: 0 # Redis数据库索引(默认为0)#host: 192.168 ...
- 【故障演练】 Redis Cluster集群,当master宕机,主从切换,客户端报错 timed out
大家好,我是Tom哥 性能不够,缓存来凑 一个高并发系统肯定少不了缓存的身影,为了保证缓存服务的高可用,我们通常采用 Redis Cluster 集群模式. 描述: 集群部署采用了 3主3从 拓扑结构 ...
- 高性能分布式缓存redis(持久化原理 安全策略 过期删除内存淘汰策略 性能压测 高可用 Redis Cluster)
redis redis(持久化原理 安全策略 过期删除&内存淘汰策略 性能压测 高可用 Redis Cluster) 1. 持久化原理 1.1 持久化流程(落盘) 1.2 RDB详解 1.2. ...
- redis cluster 集群 HA 原理和实操(史上最全、面试必备)
文章很长,建议收藏起来慢慢读!疯狂创客圈总目录 语雀版 | 总目录 码云版| 总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 经典图书:<Java高并发核心编程(卷1)> 面试必备 ...
- 响应式久草编程基础教程:久草Spring Boot 与 Lettuce 在线整合
本文主要介绍响应式编程访问 Redis,以及 Spring Boot 与 Lettuce 的整合使用. Lettuce 是可扩展性线程安全的 Redis 客户端,用于同步.异步和响应式使用.如果多个线 ...
最新文章
- SAP S/4HANA现金管理之变
- python循环输入若干学生信息保存到字典、并按学号排序,Python实现按学生年龄排序的实际问题详解...
- 浅谈ajax中get与post的区别,以及ajax中的乱码问题的解决方法
- 今天开始学opnet14.5
- iDesktop点数据集构建DEM时三种插值方式的选择
- Windows学习总结(15)——Notepad++ 快捷键大全
- react native在static中使用this方法
- Codeforces Round #666 (Div. 2)D. Stoned Game(博弈问题)
- Linux系统U盘怎么格式化,u盘怎么格式化各系统教程
- IP变更导致fdfs文件上传服务不可用解决流程
- 在html5水平边距属性hspace,响应式网页设计(html5+css3+cms)教学课件作者李文奎第2章html基础.pptx...
- java使用itext导出pdf,图片、表格、背景图
- 高效率完成一次接入80个手游渠道SDK——游戏接入SDK服务端篇
- qq邮箱发件转发php,phpmailer 利用qq邮箱转发邮件的问题
- ASUS C302C Chromebook Windows声卡驱动
- VC++调节笔记本屏幕亮度(附源码)
- 摄像机(Camera)
- Java图片处理 - 创建工具类
- java代码json_JSON 解析(java代码)
- dz plugin.php,DZ支付积分充值插件 Discuz码支付免签约即时到账插件 Discuz手机支付插件...
热门文章
- Android二维码扫描之ZXing快速项目集成
- 贝克曼库尔特Beckman Coulter全自动血液生化分析仪AU5800双工通讯开发
- 学术论文翻译网址总结
- 消失的喀什老城 消失的大半新疆94
- 贵州二级计算机考试题库,2018贵州事业单位考试题库:事业单位模拟试卷试题及答案解析六...
- Oracle Applications DBA 基础(二)
- 开源源代码收集下载网站汇总
- Photoshop入门与进阶实例:4.2 封尘的杂志
- 操作系统OS-Lab1-100位大数除法NASM实现
- python 人形自动标注_自动设置人形生物