springboot集成redis集群实现集群拓扑动态刷新
一个redis-cluster的三主三从集群,在其中一个master节点挂了之后,springboot集成redis集群配置信息没有及时刷新,出现读取操作报错。下面聊聊如何实现springboot集成redis集群实现集群拓扑动态刷新。
开启redis client的集群拓扑刷新功能,不同的方式,采用不同的处理方式:
- jedis client方式;
- luttuce client方式;
- springboot1.x之前方式;
- springboot2.0~2.3方式;
- springboot2.3之后方式;
1、jedis方式
jedis client默认自动支持集群拓扑刷新(由于jedis通过自身异常反馈来识别重连、刷新服务端的集群信息机制,保证其自动故障恢复)
2、lettuce方式
lettuce client默认未开启集群拓扑刷新,需要手动开启动态刷新。
ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
.autoReconnect(true)
.maxRedirects(6)
.topologyRefreshOptions(ClusterTopologyRefreshOptions.builder()
.enablePeriodicRefresh(30000, TimeUnit.MILLISECONDS)
.enableAllAdaptiveRefreshTriggers()
.build())
.build();
RedisClusterClient redisClusterClient = RedisClusterClient.create(clientResources, redisURIs);
redisClusterClient.setOptions(clusterClientOptions);
3、springboot1.x版本环境
springboot1.x之前版本默认使用jedis,无需手动开启动态刷新。
4、springboot2.0~2.3版本环境
springboot2.0-2.3版本默认使用lettuce,默认不支持属性配置集群拓扑刷新。
解决方案:
- 使用jedis,不需要手动指定开启刷新;
依赖如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
配置文件类似如下:
spring.redis.cluster.nodes=192.168.100.1:6379,192.168.100.2:6379,192.168.100.3:6379,192.168.100.4:6379,192.168.100.5:6379,192.168.100.6:6379
spring.redis.jedis.pool.max-active=10
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.max-wait=-1s
spring.redis.jedis.pool.min-idle=0
- 使用lettuce,需要增加配置类,需要手动开启刷新;
配置类如下:
@Configuration
public class RedisConfig {
@Autowired
private RedisProperties redisProperties;
@Bean(destroyMethod = "destroy")
public LettuceConnectionFactory redisConnectionFactory() {
// redis单节点
if (null == redisProperties.getCluster() || null == redisProperties.getCluster().getNodes()) {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisProperties.getHost(),
redisProperties.getPort());
configuration.setPassword(redisProperties.getPassword());
return new LettuceConnectionFactory(configuration);
}
// redis集群
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
redisClusterConfiguration.setPassword(redisProperties.getPassword());
redisClusterConfiguration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());
GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
genericObjectPoolConfig.setMaxTotal(redisProperties.getLettuce().getPool().getMaxActive());
genericObjectPoolConfig.setMaxIdle(redisProperties.getLettuce().getPool().getMaxIdle());
genericObjectPoolConfig.setMinIdle(redisProperties.getLettuce().getPool().getMinIdle());
genericObjectPoolConfig.setMaxWaitMillis(redisProperties.getLettuce().getPool().getMaxWait().getSeconds());
// 支持自适应集群拓扑刷新和动态刷新源
ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
.enableAllAdaptiveRefreshTriggers()
// 开启自适应刷新
.enableAdaptiveRefreshTrigger()
// 开启定时刷新
.enablePeriodicRefresh(Duration.ofSeconds(5))
.build();
ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
.topologyRefreshOptions(clusterTopologyRefreshOptions).build();
LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder()
.poolConfig(genericObjectPoolConfig)
// .readFrom(ReadFrom.SLAVE_PREFERRED) //读写分离:主写从读模式配置
.clientOptions(clusterClientOptions).build();
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration);
lettuceConnectionFactory.setShareNativeConnection(false);// 是否允许多个线程操作共用同一个缓存连接,默认 true,false 时每个操作都将开辟新的连接
lettuceConnectionFactory.resetConnection();// 重置底层共享连接, 在接下来的访问时初始化
return lettuceConnectionFactory;
}
/**
* RedisTemplate配置
*/
@Bean
public RedisTemplate<Object, Object> redisTemplate(LettuceConnectionFactory factory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
// 使用注解@Bean返回RedisTemplate的时候,同时配置hashkey和hashValue的序列虎方式
// key采用String的序列化方式
redisTemplate.setKeySerializer(keySerializer());
// value使用jackson序列化方式
redisTemplate.setValueSerializer(valueSerializer());
// hash的key采用String的序列化方式
redisTemplate.setHashKeySerializer(keySerializer());
// hash的value使用jackson序列化方式
redisTemplate.setHashValueSerializer(valueSerializer());
/**必须执行这个函数,初始化RedisTemplate*/
// 需要先调用afterPropertiesSet方法,此方法是应该是初始化参数和初始化工作。
redisTemplate.afterPropertiesSet();
log.info("序列化完成!");
return redisTemplate;
}
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuffer sb = new StringBuffer();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
/**
* key键序列化方式
*
* @return RedisSerializer
*/
private RedisSerializer<String> keySerializer() {
return new StringRedisSerializer();
}
/**
* value值序列化方式
*
* @return
*/
private Jackson2JsonRedisSerializer valueSerializer() {
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
return jackson2JsonRedisSerializer;
}
}
配置文件类似如下:
#Redis Configuration
spring.redis.cluster.max-redirects=10
spring.redis.cluster.nodes=192.168.100.1:6379,192.168.100.2:6379,192.168.100.3:6379,192.168.100.4:6379,192.168.100.5:6379,192.168.100.6:6379
spring.redis.timeout=60000ms
spring.redis.password=
spring.redis.lettuce.pool.max-active=10
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.pool.max-wait=-1ms
注意:注入LettuceConnectionFactory后,一定要记得注入RedisTemplate,并 redisTemplate.setConnectionFactory(redisConnectionFactory);
5、springboot2.3之后版本环境
springboot2.3之后版本默认使用lettuce,默认支持属性配置开启集群拓扑刷新,其解决方案:属性配置开启即可。
配置文件如下:
spring.redis.lettuce.cluster.refresh.adaptive= true
spring.redis.lettuce.cluster.refresh.period=30000
或
spring:
redis:
lettuce:
cluster:
refresh:
adaptive: true
period: 30000 # 30秒自动刷新一次
6、小结
在springboot工程中,集成了redis集群,当集群中主节点挂掉或从节点挂掉,springboot工程调用redis进行读取操作出现报错,主要排查两方面:第一排查redis集群部署配置的是否正常,当主节点挂掉后redis集群会自动进行故障转移,形成新的3主节点,其中一个主节点无从节点,可以登录客户端通过命令cluster nodes查看;第二排查springboot工程中集成redis集群使用的是那种方式,具体解决方式见上面。但工程中引入了shiro安全框架,则其session共享redis集群方案可能还是会有问题,具体深入分析解决。
感兴趣的小伙伴可以尝试~
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfhifif
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13