Redis集群Lettuce主從切換問題解決方案
一、問題描述
Redis Cluster集群,當master宕機,主從切換,客戶端報錯 timed out
二、原因
SpringBoot2.X版本開始Redis默認的連接池都是采用的Lettuce。當節(jié)點發(fā)生改變后,Letture默認是不會刷新節(jié)點拓撲的。
三、解決方案
3.1 方案一:把lettuce換成jedis
只需要在pom.xml里調整一下依賴的引用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.1.5.RELEASE</version>
<!-- 不用lettuce ,用jedis -->
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.1.0-m4</version>
</dependency>3.2 方案二:刷新節(jié)點拓撲視圖
Redis節(jié)點異常,服務端的Redis集群拓撲被刷新了,Java程序沒有獲取到新的拓撲。
Lettuce官方文檔中關于Redis Cluster的相關說明:Lettuce處理Moved和Ask永久重定向,由于命令重定向,你必須刷新節(jié)點拓撲視圖。而自適應拓撲刷新(Adaptive updates)與定時拓撲刷新(Periodic updates)是默認關閉的,可以通過如下代碼打開。
https://github.com/lettuce-io/lettuce-core/wiki/Redis-Cluster#user-content-refreshing-the-cluster-topology-view

修改代碼如下
package com.montnets.common.redis;
import io.lettuce.core.ClientOptions;
import io.lettuce.core.cluster.ClusterClientOptions;
import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisPassword;
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 org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Component
public class RedisPoolConfig {
@Autowired
private RedisProperties redisProperties;
public GenericObjectPoolConfig<?> genericObjectPoolConfig(RedisProperties.Pool properties) {
GenericObjectPoolConfig<?> config = new GenericObjectPoolConfig<>();
config.setMaxTotal(properties.getMaxActive());
config.setMaxIdle(properties.getMaxIdle());
config.setMinIdle(properties.getMinIdle());
if (properties.getTimeBetweenEvictionRuns() != null) {
config.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRuns().toMillis());
}
if (properties.getMaxWait() != null) {
config.setMaxWaitMillis(properties.getMaxWait().toMillis());
}
return config;
}
@Bean(destroyMethod = "destroy")
public LettuceConnectionFactory lettuceConnectionFactory() {
//開啟 自適應集群拓撲刷新和周期拓撲刷新
ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
// 開啟全部自適應刷新
.enableAllAdaptiveRefreshTriggers() // 開啟自適應刷新,自適應刷新不開啟,Redis集群變更時將會導致連接異常
// 自適應刷新超時時間(默認30秒)
.adaptiveRefreshTriggersTimeout(Duration.ofSeconds(30)) //默認關閉開啟后時間為30秒
// 開周期刷新
.enablePeriodicRefresh(Duration.ofSeconds(20)) // 默認關閉開啟后時間為60秒 ClusterTopologyRefreshOptions.DEFAULT_REFRESH_PERIOD 60 .enablePeriodicRefresh(Duration.ofSeconds(2)) = .enablePeriodicRefresh().refreshPeriod(Duration.ofSeconds(2))
.build();
// https://github.com/lettuce-io/lettuce-core/wiki/Client-Options
ClientOptions clientOptions = ClusterClientOptions.builder()
.topologyRefreshOptions(clusterTopologyRefreshOptions)
.build();
LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
.poolConfig(genericObjectPoolConfig(redisProperties.getJedis().getPool()))
//.readFrom(ReadFrom.MASTER_PREFERRED)
.clientOptions(clientOptions)
.commandTimeout(redisProperties.getTimeout()) //默認RedisURI.DEFAULT_TIMEOUT 60
.build();
List<String> clusterNodes = redisProperties.getCluster().getNodes();
Set<RedisNode> nodes = new HashSet<RedisNode>();
clusterNodes.forEach(address -> nodes.add(new RedisNode(address.split(":")[0].trim(), Integer.valueOf(address.split(":")[1]))));
RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();
clusterConfiguration.setClusterNodes(nodes);
clusterConfiguration.setPassword(RedisPassword.of(redisProperties.getPassword()));
clusterConfiguration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(clusterConfiguration, clientConfig);
// lettuceConnectionFactory.setShareNativeConnection(false); //是否允許多個線程操作共用同一個緩存連接,默認true,false時每個操作都將開辟新的連接
// lettuceConnectionFactory.resetConnection(); // 重置底層共享連接, 在接下來的訪問時初始化
return lettuceConnectionFactory;
}
}以上就是Redis集群Lettuce主從切換問題解決方案的詳細內(nèi)容,更多關于Redis集群Lettuce主從切換的資料請關注腳本之家其它相關文章!
相關文章
ELK配置轉存redis緩存采集nginx訪問日志的操作方法
本文介紹了在服務器上部署MySQL及如何啟動MySQL服務,并詳細說明了如何查找安裝軟件的日志文件位置,通過使用rpm命令查詢MySQL服務的日志文件位置,以及通過編輯Logstash配置文件來添加MySQL日志信息,感興趣的朋友一起看看吧2024-11-11
Redis中有序集合的內(nèi)部實現(xiàn)方式的詳細介紹
本文主要介紹了Redis中有序集合的內(nèi)部實現(xiàn)方式的詳細介紹,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03
Redis實現(xiàn)短信登錄的企業(yè)實戰(zhàn)
本文主要介紹了Redis實現(xiàn)短信登錄的企業(yè)實戰(zhàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-07-07
Redis集群設置maxmemory參數(shù)的實現(xiàn)
Redis集群中設置內(nèi)存限制需要為每個節(jié)點單獨配置maxmemory參數(shù),本文就來介紹一下Redis集群設置maxmemory參數(shù),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2026-01-01

