[英]Spring Boot Caching with Redis Sentinel always connects to master node
我有一個 Spring Boot (2.3.1.RELEASE) 應用程序,它使用 Redis Sentinel 進行緩存。 這是我的 Sentinel 連接配置:
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
.master(redisProperties.getSentinel().getMaster());
redisProperties.getSentinel().getNodes().forEach(s -> sentinelConfig.sentinel(s, redisProperties.getPort()));
sentinelConfig.setPassword(RedisPassword.of(redisProperties.getPassword()));
return new LettuceConnectionFactory(sentinelConfig);
}
這是我的緩存管理器配置:
@Bean
public RedisCacheManager cacheManager() {
Map<String, RedisCacheConfiguration> cacheConfigs = new HashMap<>();
cacheConfigs.put("cache1", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(ttlMinutes)));
cacheConfigs.put("cache2", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(ttlMinutes)));
return RedisCacheManager.builder(redisConnectionFactory())
.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(ttlMinutes)))
.withInitialCacheConfigurations(cacheConfigs)
.transactionAware()
.build();
}
從緩存的角度來看一切正常。
但是,如果我在io.lettuce.core.protocol.CommandHandler
中打開調試日志,我會看到它始終連接到同一個節點(主節點)。 我可以通過查看節點上的日志來確認這一點。
我在網上到處看,這似乎是正確的配置。
這讓我想到了我的問題:
這種期望是否有效? 或者這是應該使用 Sentinel 的方式(所有請求 go 掌握)?
是的,這是可以做到的。
來自Spring 數據 Redis 文檔 - 10.4.4。 寫入主控,從副本讀取:
據說Spring Data Redis提供了Redis Master/Replica 設置,它不僅允許數據安全地存儲在更多節點上,還允許從副本讀取數據,同時使用Lettuce將寫入推送到 master。
為此,您必須更新配置 class 中的redisConnectionFactory()
方法:
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
.readFrom(ReadFrom.REPLICA_PREFERRED)
.build();
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
.master(redisProperties.getSentinel().getMaster());
redisProperties.getSentinel().getNodes().forEach(s -> sentinelConfig.sentinel(s, redisProperties.getPort()));
sentinelConfig.setPassword(RedisPassword.of(redisProperties.getPassword()));
return new LettuceConnectionFactory(sentinelConfig, clientConfig);
}
如果你想寫主控,只讀所有的從屬(副本),你可以使用下面的配置。
這些配置包括連接池、寫入主節點和從具有循環負載平衡的所有從節點讀取。
@Bean
public RedisConnectionFactory lettuceConnectionFactory(RedisProperties redisProperties, LettucePoolingClientConfiguration lettucePoolingClientConfiguration) {
final RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration().master(redisProperties.getMaster());
redisSentinelConfiguration.setDatabase(redisProperties.getDbIndex());
addSentinels(redisProperties, redisSentinelConfiguration);
return new LettuceConnectionFactory(redisSentinelConfiguration, lettucePoolingClientConfiguration);
}
private void addSentinels(RedisProperties redisProperties, RedisSentinelConfiguration redisSentinelConfiguration) {
redisProperties.getNodes()
.forEach(node -> {
final String[] splitted = node.split(NODE_SPLITTER);
final String host = splitted[0];
final int port = Integer.parseInt(splitted[1]);
redisSentinelConfiguration.addSentinel(RedisNode.newRedisNode()
.listeningAt(host, port)
.build());
});
}
@Bean
public LettucePoolingClientConfiguration lettucePoolingClientConfiguration(ClientOptions clientOptions, ClientResources clientResources, RedisProperties redisProperties) {
return LettucePoolingClientConfiguration.builder()
.readFrom(ReadFrom.ANY_REPLICA)
.poolConfig(genericObjectPoolConfig(redisProperties))
.clientOptions(clientOptions)
.clientResources(clientResources)
.build();
}
@Bean
public GenericObjectPoolConfig genericObjectPoolConfig(RedisProperties redisProperties) {
final GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxIdle(redisProperties.getPoolMaxIdle());
config.setMinIdle(redisProperties.getPoolMinIdle());
config.setMaxTotal(redisProperties.getPoolMaxTotal());
config.setBlockWhenExhausted(false);
config.setMaxWaitMillis(redisProperties.getPoolMaxWaitMillis());
return config;
}
@Bean
public ClientOptions clientOptions(RedisProperties redisProperties) {
return ClientOptions.builder()
.autoReconnect(true)
.disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)
.timeoutOptions(TimeoutOptions.builder().fixedTimeout(Duration.ofSeconds(redisProperties.getCommandTimedOutSec())).build())
.build();
}
@Bean(destroyMethod = "shutdown")
public ClientResources clientResources() {
return DefaultClientResources.create();
}
您應該為負載平衡讀取模式導入新的生菜核心版本( ReadFrom.ANY_REPLICA ),它將與 spring-boot 2.4.0 一起提供
pom.xml
<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>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.0.1.RELEASE</version>
</dependency>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.