如何将 AWS Elasticache Redis 集群连接到 Spring 启动应用程序?
How to connect AWS Elasticache Redis cluster to Spring Boot app?
我有 Spring 使用 Jedis 连接工厂连接到 Redis 集群的引导应用程序:
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
redisClusterConfiguration.setPassword(redisProperties.getPassword());
jedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration);
并从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
现在我们想切换到 Elasticache,因为无论如何我们都在 AWS 上托管我们的 Redis 集群。
这很容易完成。如果可以使用 AmazonElastiCache 库。
然后我们可以使用 AWS 凭证连接到 Elasticache 集群,拉取可用节点并将其放入列表并将其传递给 Jedis,而不是将它们硬编码在 application.yml 中,例如:
//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;
}
但 DevOps 团队表示他们无法在所有实验室上配置 AWS 访问权限,他们有这样做的理由。此外,我们不需要连接到 AWS 并拉取所有可用集群,而是需要通过 URL.
连接到特定集群
所以我尝试将 Elasticache 集群 url 作为独立的和 application.yml 配置中的集群直接传递给 Jedis。
在这两种情况下都建立了连接,但是当 App 尝试写入 Elasticache 时,它会出现 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
据我了解,这意味着 App 试图写入 Elasticache 中的一个节点,但无法连接。
所以问题是有没有办法从 Spring 仅使用 Elasticache 集群 URL 启动应用程序连接到 Elasticache Redis 集群 URL?
我知道用Elasticache Memecache是可以的。
Jedis 驱动程序也不是硬性要求。
谢谢。
经过一些研究,我们了解到如果 AWS Elasticache 集群端点被设置为 RedisClusterConfiguration
中的一个节点,那么驱动程序(Jedis 或 Lettuce)能够连接并找到 Elasticache 集群中的所有节点。此外,如果其中一个节点出现故障,驱动程序能够通过其他节点与 Elasticache 集群通信。
我们在进行此升级时也迁移到了 Lettuce 驱动程序,因为 Lettuce 是 Spring Boot Redis Started 中提供的默认驱动程序并支持最新的 Redis 版本。 Lettuce 连接也设计为线程安全的,Jedis 不是。
代码示例:
List<String> nodes = Collections.singletonList("****.***.****.****.cache.amazonaws.com:6379");
RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration(nodes);
return new LettuceConnectionFactory(clusterConfiguration);
灵感来自于上面的答案:,完整更详细的代码
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(clusterConfiguration, lettuceClientConfiguration);
lettuceConnectionFactory.afterPropertiesSet();//**this is REQUIRED**
StringRedisTemplate redisTemplate = new StringRedisTemplate(lettuceConnectionFactory);
我有 Spring 使用 Jedis 连接工厂连接到 Redis 集群的引导应用程序:
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
redisClusterConfiguration.setPassword(redisProperties.getPassword());
jedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration);
并从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
现在我们想切换到 Elasticache,因为无论如何我们都在 AWS 上托管我们的 Redis 集群。 这很容易完成。如果可以使用 AmazonElastiCache 库。 然后我们可以使用 AWS 凭证连接到 Elasticache 集群,拉取可用节点并将其放入列表并将其传递给 Jedis,而不是将它们硬编码在 application.yml 中,例如:
//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;
}
但 DevOps 团队表示他们无法在所有实验室上配置 AWS 访问权限,他们有这样做的理由。此外,我们不需要连接到 AWS 并拉取所有可用集群,而是需要通过 URL.
连接到特定集群所以我尝试将 Elasticache 集群 url 作为独立的和 application.yml 配置中的集群直接传递给 Jedis。 在这两种情况下都建立了连接,但是当 App 尝试写入 Elasticache 时,它会出现 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
据我了解,这意味着 App 试图写入 Elasticache 中的一个节点,但无法连接。
所以问题是有没有办法从 Spring 仅使用 Elasticache 集群 URL 启动应用程序连接到 Elasticache Redis 集群 URL?
我知道用Elasticache Memecache是可以的。 Jedis 驱动程序也不是硬性要求。
谢谢。
经过一些研究,我们了解到如果 AWS Elasticache 集群端点被设置为 RedisClusterConfiguration
中的一个节点,那么驱动程序(Jedis 或 Lettuce)能够连接并找到 Elasticache 集群中的所有节点。此外,如果其中一个节点出现故障,驱动程序能够通过其他节点与 Elasticache 集群通信。
我们在进行此升级时也迁移到了 Lettuce 驱动程序,因为 Lettuce 是 Spring Boot Redis Started 中提供的默认驱动程序并支持最新的 Redis 版本。 Lettuce 连接也设计为线程安全的,Jedis 不是。
代码示例:
List<String> nodes = Collections.singletonList("****.***.****.****.cache.amazonaws.com:6379");
RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration(nodes);
return new LettuceConnectionFactory(clusterConfiguration);
灵感来自于上面的答案:,完整更详细的代码
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(clusterConfiguration, lettuceClientConfiguration);
lettuceConnectionFactory.afterPropertiesSet();//**this is REQUIRED**
StringRedisTemplate redisTemplate = new StringRedisTemplate(lettuceConnectionFactory);