Wie verbinde ich den AWS Elasticache Redis-Cluster mit der Spring Boot-App?

8

Ich habe eine Spring Boot-App, die mithilfe von Jedis Connection Factory eine Verbindung zum Redis-Cluster herstellt:

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

und Lesen der Liste der Knoten aus 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

Jetzt möchten wir zu Elasticache wechseln, da wir unseren Redis-Cluster ohnehin auf AWS hosten. Es würde ganz einfach gemacht werden. Wenn AmazonElastiCache lib verwendet werden könnte. Dann könnten wir einfach eine Verbindung zum Elasticache-Cluster mit AWS-Anmeldeinformationen herstellen, verfügbare Knoten abrufen, in die Liste aufnehmen und an Jedis übergeben, anstatt sie in application.yml fest zu codieren, wie:

//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;
}

Das DevOps-Team gab jedoch an, dass es den AWS-Zugriff nicht in allen Labors konfigurieren kann und Gründe dafür hat. Anstatt eine Verbindung zu AWS herzustellen und alle verfügbaren Cluster abzurufen, müssen wir auch eine Verbindung zu einem bestimmten über die URL herstellen.

Daher habe ich versucht, die Elasticache-Cluster-URL als eigenständige und als Cluster in der application.yml-Konfiguration direkt an Jedis zu übergeben. In beiden Fällen wird eine Verbindung hergestellt, aber wenn die App versucht, in Elasticache zu schreiben, wird die Ausnahme verschoben:

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

Was meines Wissens bedeutet, dass die App versucht hat, auf einen der Knoten in Elasticache zu schreiben, aber keine Verbindung herstellen konnte.

Die Frage wäre also, ob es eine Möglichkeit gibt, über die Spring Boot-App eine Verbindung zum Elasticache Redis-Cluster herzustellen, indem nur die Elasticache-Cluster-URL verwendet wird.

Ich weiß, dass es machbar ist, wenn Elasticache Memecache verwendet wird. Auch Jedis-Fahrer ist keine harte Anforderung.

Vielen Dank.

Marius Jaraminas
quelle

Antworten:

2

Nach einigen Recherchen haben wir RedisClusterConfigurationfestgestellt, dass der Treiber (Jedis oder Lettuce) eine Verbindung herstellen und alle Knoten in einem Elasticache-Cluster finden kann , wenn der Endpunkt des AWS Elasticache-Clusters als Knoten festgelegt ist. Auch wenn einer der Knoten ausfällt, kann der Treiber über einen anderen Knoten mit dem Elasticache-Cluster kommunizieren.

Wir haben auch bei der Arbeit an diesem Upgrade auf den Lettuce-Treiber migriert, da Lettuce der Standardtreiber ist, der in Spring Boot Redis Started bereitgestellt wird und die neuesten Redis-Versionen unterstützt. Salatverbindungen sind auch fadensicher, Jedis nicht.

Codebeispiel:

List<String> nodes = Collections.singletonList("****.***.****.****.cache.amazonaws.com:6379");
RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration(nodes);
return new LettuceConnectionFactory(clusterConfiguration);
Marius Jaraminas
quelle
ist "" ****. ***. ****. ****. cache.amazonaws.com: "ein elastischer Cluster-Hostname?
Santh
Ja, das ist der Hostname des ElastiCache-Clusters
Marius Jaraminas
0

Inspiriert von der obigen Antwort: Vervollständigen Sie den detaillierteren Code

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
quelle