Como conectar o cluster do AWS Elasticache Redis ao aplicativo Spring Boot?

8

Eu tenho o aplicativo Spring Boot, que se conecta ao cluster Redis, usando o Jedis Connection Factory:

RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
redisClusterConfiguration.setPassword(redisProperties.getPassword());
jedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration);

e lendo a lista de nós do application.yml:

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    timeout: 300s
    cluster:
      nodes: 127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382

Agora, queremos mudar para o Elasticache, já que estamos hospedando nosso cluster Redis na AWS. Isso seria feito com bastante facilidade. Se o AmazonElastiCache lib pudesse ser usado. Em seguida, poderíamos conectar-se ao cluster Elasticache com credenciais da AWS, puxar os nós disponíveis, colocá-lo na lista e passá-lo para os Jedis, em vez de codificá-los em application.yml, como:

//get cache cluster nodes using AWS api
private List<String> getClusterNodes(){
    AmazonElastiCache client = AmazonElastiCacheClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
    DescribeCacheClustersRequest describeCacheClustersRequest = new DescribeCacheClustersRequest();
    describeCacheClustersRequest.setShowCacheNodeInfo(true);
    List<CacheCluster> cacheClusterList = client.describeCacheClusters(describeCacheClustersRequest).getCacheClusters();
    List<String> nodeList = new ArrayList<>();
    try {
        for (CacheCluster cacheCluster : cacheClusterList) {
            for(CacheNode cacheNode :cacheCluster.getCacheNodes()) {
                String nodeAddr = cacheNode.getEndpoint().getAddress() + ":" +cacheNode.getEndpoint().getPort();
                nodeList.add(nodeAddr);
            }
        }
    }
    catch(Exception e) {
        e.printStackTrace();
    }
    return nodeList;
}

Mas a equipe do DevOps disse que não pode configurar o acesso à AWS em todos os laboratórios e tem motivos para isso. Além disso, em vez de conectar-se à AWS e extrair todos os clusters disponíveis, precisamos conectar-nos a um específico por URL.

Por isso, tentei passar o URL do cluster Elasticache diretamente para o Jedis como autônomo e como um cluster na configuração application.yml. Nos dois casos, a conexão é estabelecida, mas quando o App tenta gravar no Elasticache, a exceção é MOVED:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.data.redis.ClusterRedirectException: Redirect: slot 1209 to 10.10.10.011:6379.; nested exception is redis.clients.jedis.exceptions.JedisMovedDataException: MOVED 1209 10.10.10.102:6379

O que, pelo que entendi, significa que o App tentou gravar em um dos nós no Elasticache, mas não conseguiu se conectar.

Portanto, a questão seria: existe uma maneira de conectar-se ao cluster Elasticache Redis a partir do aplicativo Spring Boot usando apenas o URL do cluster Elasticache?

Eu sei que é possível se o Elasticache Memecache for usado. O driver Jedis também não é um requisito difícil.

Obrigado.

Marius Jaraminas
fonte

Respostas:

2

Após algumas pesquisas, descobrimos que, se o ponto de extremidade do cluster do AWS Elasticache estiver definido como um nó no RedisClusterConfigurationdriver, o driver (Jedis ou Lettuce) poderá se conectar e encontrar todos os nós em um cluster do Elasticache. Além disso, se um dos nós ficar inativo, o driver poderá se comunicar com o cluster Elasticache através de outro nó.

Também migramos para o driver Lettuce enquanto trabalhamos nessa atualização, pois o Lettuce é o driver padrão fornecido no Spring Boot Redis Started e suporta as versões mais recentes do Redis. As conexões de alface são projetadas para serem seguras também para roscas, Jed não.

Exemplo de código:

List<String> nodes = Collections.singletonList("****.***.****.****.cache.amazonaws.com:6379");
RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration(nodes);
return new LettuceConnectionFactory(clusterConfiguration);
Marius Jaraminas
fonte
é "" ****. ***. ****. ****. cache.amazonaws.com: "um nome de host de cluster Elastic?
Santh
sim esse é o nome do host do cluster ElastiCache
Marius Jaraminas
0

Inspirado na resposta acima:, complete o código mais detalhado

List<String> nodes = Collections.singletonList("<cluster-host-name>:<port>");
RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration(nodes);

ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder().closeStaleConnections(true)
            .enableAllAdaptiveRefreshTriggers().build();

ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder().autoReconnect(true)
            .topologyRefreshOptions(topologyRefreshOptions).validateClusterNodeMembership(false)
            .build();
//If you want to add tuning options
LettuceClientConfiguration  lettuceClientConfiguration = LettuceClientConfiguration.builder().readFrom(ReadFrom.REPLICA_PREFERRED).clientOptions(clusterClientOptions).build();

LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration);
lettuceConnectionFactory.afterPropertiesSet();//**this is REQUIRED**
StringRedisTemplate redisTemplate = new StringRedisTemplate(lettuceConnectionFactory);
Santh
fonte