복붙노트

[REDIS] 스프링 데이터 레디 스 마스터 슬레이브 구성

REDIS

스프링 데이터 레디 스 마스터 슬레이브 구성

다음은 내 jedis의 설정입니다

@Bean
public JedisConnectionFactory getJedisConnectionFactory() {
    JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
    jedisConnectionFactory.setUsePool(true);
    return jedisConnectionFactory;
}

@Bean
public RedisTemplate<String, Object> getRedisTemplate() {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
    redisTemplate.setConnectionFactory(getJedisConnectionFactory());
    return redisTemplate;
}

내가 하나의 서버가있을 때이 설정은 잘 작동합니다. 내가인가를하고 싶은 1 레디 스 마스터와 여러 레디 스의 노예가 있습니다. 레디 스 문서 당, 읽기는 노예에서 발생해야하고, 쓰기는 마스터에서 발생한다. 어떻게 읽기, 쓰기 및 슬레이브 사용 마스터 구성 위의 변경합니까?

내 마스터가 192.168.10.10에 있으며 슬레이브는 로컬 호스트에서라고 말할 수 있습니다.

감사!

해결법

  1. ==============================

    1.이 때 원하는 동작을 가능하게 할 봄 데이터 레디 스에는 구성 옵션이 없습니다. 도 아니다 Jedis는 iteself이 (jedis # 458 참조) 이런 종류의 시나리오에 대한 지원을 제공한다. 작업을 실행할 때 RedisConnection는 공장에서 연결을 요청합니다. 이 시점에서 자원의 사용 목적은 명령, R 수 W 또는 RW 수 있기는 명확하지 않다 요청했다.

    이 때 원하는 동작을 가능하게 할 봄 데이터 레디 스에는 구성 옵션이 없습니다. 도 아니다 Jedis는 iteself이 (jedis # 458 참조) 이런 종류의 시나리오에 대한 지원을 제공한다. 작업을 실행할 때 RedisConnection는 공장에서 연결을 요청합니다. 이 시점에서 자원의 사용 목적은 명령, R 수 W 또는 RW 수 있기는 명확하지 않다 요청했다.

    당신이 가지고있는 노예 중 하나에 - - 읽기 전용 명령의 경우에 실행되는 하나 개의 잠재적 인 솔루션은 연결을 제공 할 수있는 사용자 정의 RedisConnectionFactory 될 것이다.

    SlaveAwareJedisConnectionFactory factory = new SlaveAwareJedisConnectionFactory();
    factory.afterPropertiesSet();
    
    RedisConnection connection = factory.getConnection();
    
    // writes to master
    connection.set("foo".getBytes(), "bar".getBytes());
    
    // reads from slave
    connection.get("foo".getBytes());
    
    /**
     * SlaveAwareJedisConnectionFactory wraps JedisConnection with a proy that delegates readonly commands to slaves.
     */
    class SlaveAwareJedisConnectionFactory extends JedisConnectionFactory {
    
      /**
        * Get a proxied connection to Redis capable of sending
        * readonly commands to a slave node
        */
      public JedisConnection getConnection() {
    
        JedisConnection c = super.getConnection();
    
        ProxyFactory proxyFactory = new ProxyFactory(c);
        proxyFactory.addAdvice(new ConnectionSplittingInterceptor(this));
        proxyFactory.setProxyTargetClass(true);
    
        return JedisConnection.class.cast(proxyFactory.getProxy());
      };
    
      /**
       * This one will get the connection to one of the slaves to read from there
       * 
       * @return
       */
      public RedisConnection getSlaveConnection() {
    
        //TODO: find the an available slave serving the data
        return new JedisConnection(new Jedis("your slave host lookup here"));
      }
    
      static class ConnectionSplittingInterceptor implements MethodInterceptor,
          org.springframework.cglib.proxy.MethodInterceptor {
    
        private final SlaveAwareJedisConnectionFactory factory;
    
        public ConnectionSplittingInterceptor(SlaveAwareJedisConnectionFactory factory) {
          this.factory = factory;
        }
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    
          RedisCommand commandToExecute = RedisCommand.failsafeCommandLookup(method.getName());
    
          if (!commandToExecute.isReadonly()) {
            return invoke(method, obj, args);
          }
    
          RedisConnection connection = factory.getSlaveConnection();
    
          try {
            return invoke(method, connection, args);
          } finally {
            // properly close the connection after executing command
            if (!connection.isClosed()) {
              connection.close();
            }
          }
        }
    
        private Object invoke(Method method, Object target, Object[] args) throws Throwable {
    
          try {
            return method.invoke(target, args);
          } catch (InvocationTargetException e) {
            throw e.getCause();
          }
        }
    
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
          return intercept(invocation.getThis(), invocation.getMethod(), invocation.getArguments(), null);
        }
      }
    }
    

    이 솔루션은 위의 serveral 문제를 보유하고 있습니다. 예. 명령은 이제 잠재적으로 당신이 그 (것)들을되고 싶지 않아 파이프 어딘가를 얻을 수 있기 때문에 당신의 MULTI EXEC 블록은 응용 프로그램이 더 이상 작동하지 예상 할 수있다. 그래서 어쩌면 그것은 또한 전용 읽기, 쓰기의 목적을 위해 여러 RedisTemplates을 가지고 감각을 만들 것입니다.

  2. ==============================

    2.당신은 레디 스의 마스터 / 슬레이브 구성을 유지하기 위해 레디 스 센티넬를 사용해야합니다 ... 당신은 감시 수영장 -에 연결하기 위해 아래에 사용할 수 있습니다

    당신은 레디 스의 마스터 / 슬레이브 구성을 유지하기 위해 레디 스 센티넬를 사용해야합니다 ... 당신은 감시 수영장 -에 연결하기 위해 아래에 사용할 수 있습니다

    @Bean
    public RedisConnectionFactory jedisConnectionFactory() {
    RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration() .master("mymaster")
        .sentinel("127.0.0.1", 26379) .sentinel("127.0.0.1", 26380);
    return new JedisConnectionFactory(sentinelConfig);
    }
    

    참조 : 봄 센티넬 지원

  3. ==============================

    3.당신이 원하는 쓰기에 마스터를 읽기 -에서 - 슬레이브

    당신이 원하는 쓰기에 마스터를 읽기 -에서 - 슬레이브

    이것은 감시 클러스터 봄 부팅과 그것을 구성하는 방법입니다

    spring:
      data:
        redis:
          sentinel: 
            master: mymaster
            nodes: my.sentinel.hostname1:26379,my.sentinel.hostname2:26379
          port: 6379
    

    그리고 스프링 설정

    @Configuration
    public class RedisDatasourceConfig {
    
      @Bean
      public LettuceClientConfigurationBuilderCustomizer lettuceClientConfigurationBuilderCustomizer() {
        return p -> p.readFrom(SLAVE_PREFERRED);
      }
    }
    
  4. from https://stackoverflow.com/questions/29527738/spring-data-redis-master-slave-config by cc-by-sa and MIT license