【问题标题】:Spring Boot Caching with Redis Sentinel always connects to master node带有 Redis Sentinel 的 Spring Boot 缓存始终连接到主节点
【发布时间】:2020-11-12 18:48:51
【问题描述】:

我有一个带有 Redis Sentinel 缓存的 Spring Boot (2.3.1.RELEASE) 应用程序。 这是我的 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 中的调试日志,我会看到它始终连接到同一个节点(主节点)。我可以通过查看节点上的日志来确认。

我在网上看到的所有地方,这似乎都是正确的配置。

这让我想到了我的问题:

  • 是否可以将 Spring 缓存抽象配置为仅使用主节点进行写入,使用从节点进行读取?

这种期望是否有效?或者这就是应该使用 Sentinel 的方式(所有请求都转到 master)?

【问题讨论】:

    标签: java spring redis redis-sentinel


    【解决方案1】:

    是的,可以做到。

    来自Spring Data Redis Docs - 10.4.4. Write to Master, Read from Replica

    据说Spring Data Redis提供了Redis Master/Replica设置 没有 不仅允许数据安全地存储在更多节点上,而且还允许 从副本读取数据,同时通过使用将写入推送到主服务器 生菜

    为此,您必须更新配置类中的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);
    }
    

    【讨论】:

      【解决方案2】:

      如果你想从所有从属(副本)写入主和只读,你可以使用下面的配置。

      这些配置包括连接池、写入主节点和通过循环负载平衡从所有从节点读取。

          @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>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-09-01
        • 2022-08-03
        • 2015-02-20
        • 2016-02-12
        • 2022-01-11
        • 1970-01-01
        • 1970-01-01
        • 2020-07-08
        相关资源
        最近更新 更多