Java 带有Redis Sentinel的Spring引导缓存始终连接到主节点
我有一个SpringBoot(2.3.1.RELEASE)应用程序,它使用RedisSentinel进行缓存。 这是我对Sentinel连接的配置:Java 带有Redis Sentinel的Spring引导缓存始终连接到主节点,java,spring,redis,redis-sentinel,Java,Spring,Redis,Redis Sentinel,我有一个SpringBoot(2.3.1.RELEASE)应用程序,它使用RedisSentinel进行缓存。 这是我对Sentinel连接的配置: @Bean public LettuceConnectionFactory redisConnectionFactory() { RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration() .master(redisPrope
@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();
}
@Bean
公共RedisCacheManager cacheManager(){
Map cacheConfigs=new HashMap();
cacheConfigs.put(“cache1”,RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(ttlMinutes)));
cacheConfigs.put(“cache2”,RedisCacheConfiguration.defaultCacheConfig().entryTtl(持续时间:分钟(ttlMinutes)));
返回RedisCacheManager.builder(redisConnectionFactory())
.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig().entryTtl(持续时间:分钟(ttlMinutes)))
.withInitialCacheConfigurations(缓存配置)
.TransactionWare()
.build();
}
从缓存的角度来看,一切都很好
但是,如果我在io.莴苣.core.protocol.CommandHandler
中打开调试日志,我会发现它总是连接到同一个节点(主节点)。我可以通过查看节点上的日志来确认这一点
无论我在网上看到什么,这似乎都是正确的配置
这就引出了我的问题:
- 是否可以将Spring缓存抽象配置为仅将主节点用于写入,将从节点用于读取?
这一期望是否成立?或者这就是Sentinel应该使用的方式(所有请求都转到master)?是的,可以这样做。
@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();
}
来自:
据说Spring Data Redis提供了Redis主/副本设置 哪一个不是
不仅允许数据安全地存储在更多节点上,而且还允许
使用从副本读取数据,同时将写入推送到主副本
生菜
为此,必须更新配置类中的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>
org.springframework.boot
spring启动程序数据redis
生菜
莴苣核
生菜
莴苣核
6.0.1.1发布