After you obtain a private endpoint, you can bypass proxy nodes and use the private endpoint to connect to an ApsaraDB for Redis cluster instance. This reduces the response time of ApsaraDB for Redis. This topic describes the precautions and method of using a private endpoint to connect to an ApsaraDB for Redis cluster instance. The Jedis and PhpRedis clients are used in this topic.

Prerequisites

  • The direct connection mode is enabled for the cluster instance. For more information, see Enable the direct connection mode.
  • The client IP address is added to a whitelist of the ApsaraDB for Redis cluster instance. For more information, see Step 2: Configure whitelists.
  • A client that supports Redis Cluster is used, such as Jedis and PhpRedis.
    Note
    • If you use a client that does not support Redis Cluster, you may fail to obtain data because the client cannot redirect your request to the correct shard.
    • Jedis uses the JedisCluster class to support Redis Cluster. For more information, see Class JedisCluster.
    • You can obtain a list of clients that support Redis Cluster from the Clients page on the Redis official website.
  • The Elastic Compute Service (ECS) instance on which the Redis client is deployed and the ApsaraDB for Redis cluster instance are within the same virtual private cloud (VPC).

Background information

When you enable the direct connection mode, ApsaraDB for Redis allocates a virtual IP (VIP) address to the master node of each data shard in the ApsaraDB for Redis cluster instance. Before a client sends the first request to a private endpoint, the client uses a domain name server (DNS) to resolve the private endpoint. The resolution result is the VIP address of a random data shard in the cluster instance. The client can use this VIP address to manage the data of the ApsaraDB for Redis cluster instance over the Redis Cluster protocol. The following figure shows the service architecture of an ApsaraDB for Redis cluster instance in the direct connection mode.
Figure 1. Architecture of a cluster instance in direct connection mode
Architecture of a cluster instance in direct connection mode

Precautions

  • ApsaraDB for Redis instances of different architectures provide different support for native Redis commands. For example, the cluster architecture does not support the SWAPDB command, and has restrictions on Lua scripts. For more information,see Limits on commands supported by cluster instances.
  • In direct connection mode, when you change the configurations of an instance, slot migration is performed during the process. In this case, the client may prompt error messages such as MOVED and TRYAGAIN when the client accesses the slots being migrated. For more information about how to change the configurations of an instance, see Change the configurations of an instance. To ensure the successful execution of the request, configure a retry mechanism for the client. For more information, see Retry mechanisms for Redis clients.
  • In direct connection mode, you can use the SELECT command to switch databases. However, specific Redis Cluster clients do not support the SELECT command, such as StackExchange.redis. If you use StackExchange.redis, you can only use database 0.
  • Private endpoints can be used to access ApsaraDB for Redis cluster instances only over the Alibaba Cloud internal network. When you use the private endpoint of a cluster instance to access the instance, password-free access and account and password authentication are supported.

Sample code for connecting Jedis to a cluster instance

import redis.clients.jedis.HostAndPort;
 import redis.clients.jedis.JedisCluster;
 import redis.clients.jedis.JedisPoolConfig;
 
 import java.util.HashSet;
 import java.util.Set;
  
 public class DirectTest  {
     private static final int DEFAULT_TIMEOUT = 2000;
     private static final int DEFAULT_REDIRECTIONS = 5;
     private static final JedisPoolConfig DEFAULT_CONFIG = new JedisPoolConfig();
 
     public static void main(String args[]){
  
         // Specify the private endpoint that you applied for the cluster instance.
         String host = "r-bp1xxxxxxxxxxxx.redis.rds.aliyuncs.com";
         int port = 6379;
         String password = "xxxx";
  
         Set<HostAndPort>  jedisClusterNode = new HashSet<HostAndPort>();
         jedisClusterNode.add(new HostAndPort(host, port));
  
         JedisCluster jc = new JedisCluster(jedisClusterNode, DEFAULT_TIMEOUT, DEFAULT_TIMEOUT,
                 DEFAULT_REDIRECTIONS,password, "clientName", DEFAULT_CONFIG);
  
         jc.set("key","value");
         jc.get("key");
  
         jc.close();
     }
 }
import redis.clients.jedis.*;
  
 import java.util.HashSet;
 import java.util.Set;
 public class main {
     private static final int DEFAULT_TIMEOUT = 2000;
     private static final int DEFAULT_REDIRECTIONS = 5;
     private static final JedisPoolConfig DEFAULT_CONFIG = new JedisPoolConfig();
 
     public static void main(String args[]){
         JedisPoolConfig config = new JedisPoolConfig();
         // Specify the maximum number of idle connections. In direct connection mode, the client directly connects to a shard of a cluster instance. Therefore, the following requirement must be met: Number of clients × Value of MaxTotal < Maximum number of connections to a single shard. 
         // Set the maximum number of connections to a shard of an ApsaraDB for Redis Community Edition instance to 10000 and set the maximum number of connections to a shard of an ApsaraDB for Redis Enhanced Edition (Tair) instance to 30000. 
         config.setMaxTotal(30);
         // Specify the maximum number of idle connections based on your business needs. 
         config.setMaxIdle(20);
         config.setTestOnBorrow(false);
         config.setTestOnReturn(false);
 
         // Specify the private endpoint that you applied for the cluster instance.
         String host = "r-bp1xxxxxxxxxxxx.redis.rds.aliyuncs.com";
         int port = 6379;
         // Specify the password of the instance.
         String password = "xxxxx";
 
         Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
         jedisClusterNode.add(new HostAndPort(host, port));
         JedisCluster jc = new JedisCluster(jedisClusterNode, DEFAULT_TIMEOUT, DEFAULT_TIMEOUT,
                 DEFAULT_REDIRECTIONS,password, "clientName", config);
     }
 }
Note For more information about how to use Jedis, visit GitHub.

Sample code for connecting PhpRedis to a cluster instance

<?php
 // Specify the private endpoint and the port number to connect to the cluster instance.
 $array = ['r-bp1xxxxxxxxxxxx.redis.rds.aliyuncs.com:6379'];
 // Specify the password for the connection.
 $pwd = "xxxx";
 
 // Use the password to connect to the cluster instance.
 $obj_cluster = new RedisCluster(NULL, $array, 1.5, 1.5, true, $pwd);
 
 // Display the result of the connection.
 var_dump($obj_cluster);
 
 if ($obj_cluster->set("foo", "bar") == false) {
     die($obj_cluster->getLastError());
 }
 $value = $obj_cluster->get("foo");
 echo $value;
 ?>
Note For more information about how to use PhpRedis, visit GitHub.

Sample code for connecting Spring Data Redis to a cluster instance

@Bean
     JedisConnectionFactory redisConnectionFactory() {
         List<String> clusterNodes = Arrays.asList("host1:port1", "host2:port2", "host3:port3");
         RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(clusterNodes);
         redisClusterConfiguration.setPassword("xxx");
 
         JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
         // Specify the maximum number of idle connections. In direct connection mode, the client directly connects to a shard of a cluster instance. Therefore, the following requirement must be met: Number of clients × Value of MaxTotal < Maximum number of connections to a single shard. 
         // Set the maximum number of connections to a shard of an ApsaraDB for Redis Community Edition instance to 10000 and set the maximum number of connections to a shard of an ApsaraDB for Redis Enhanced Edition (Tair) instance to 30000. 
         jedisPoolConfig.setMaxTotal(30);
         // Specify the maximum number of idle connections based on your business needs. 
         jedisPoolConfig.setMaxIdle(20);
         // Disable testOn[Borrow|Return] to prevent generating additional ping commands.
         jedisPoolConfig.setTestOnBorrow(false);
         jedisPoolConfig.setTestOnReturn(false);
 
         return new JedisConnectionFactory(redisClusterConfiguration, jedisPoolConfig);
     }
@Bean
     public LettuceConnectionFactory redisConnectionFactory() {
         List<String> clusterNodes = Arrays.asList("host1:port1", "host2:port2", "host3:port3");
         RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(clusterNodes);
         redisClusterConfiguration.setPassword("xxx");
 
         ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
             .enablePeriodicRefresh(Duration.ofSeconds(15))                     // Specify the interval at which the topology of the cluster instance is refreshed. We recommend that you set the interval to 15 seconds. If you set it to a smaller value, a large number of calls are made to the nodes of the cluster instance. This degrades the cluster instance performance. 
             .dynamicRefreshSources(false)                                      // Specify whether to use the IP addresses of the nodes obtained from the topology as nodes to be called to refresh the topology of the cluster instance. If you connect to an ApsaraDB for Redis instance, you must set the parameter to false. 
             .enableAllAdaptiveRefreshTriggers()                                // Enable all triggers to adaptively refresh the topology. After adaptive refresh is enabled, the topology of the cluster instance is automatically refreshed each time a runtime event such as a MOVED redirection occurs on the cluster instance. 
             .adaptiveRefreshTriggersTimeout(Duration.ofSeconds(15)).build();   // Specify the time period during which the topology of the cluster instance can be refreshed only once. This prevents the topology from being frequently refreshed. 
 
         LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder().
             clientOptions(ClusterClientOptions.builder()
                 .validateClusterNodeMembership(false)
                 .topologyRefreshOptions(topologyRefreshOptions).build()).build();
 
         return new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration);
     }
Note For more information about how to use Spring Data Redis, visit Spring.

Sample code for connecting Lettuce to a cluster instance

The Lettuce client supports synchronous and asynchronous communication by using Redis APIs. The Lettuce client does not automatically reconnect to an instance after multiple requests time out. If failures occur in ApsaraDB for Redis and cause failovers for proxy nodes or data nodes, a connection timeout may occur. This may result in the failure to reconnect to ApsaraDB for Redis. To prevent this issue, we recommend that you use other clients.

public class ClusterDemo {
     public static void main(String[] args) throws Exception {
         String host = "r-bp1xxxxxxxxxxxx.redis.rds.aliyuncs.com";
         int port = 30001;
         String password = "xxxx";
 
         RedisURI redisURI = RedisURI.Builder.redis(host)
             .withPort(port)
             .withPassword(password)
             .build();
 
         ClusterTopologyRefreshOptions refreshOptions = ClusterTopologyRefreshOptions.builder()
             .enablePeriodicRefresh(Duration.ofSeconds(15))                     // Specify the interval at which the topology of the cluster instance is refreshed. We recommend that you set the interval to 15 seconds. If you set it to a smaller value, a large number of calls are made to the nodes of the cluster instance. This degrades the cluster instance performance. 
             .dynamicRefreshSources(false)                                      // Specify whether to use the IP addresses of the nodes obtained from the topology as nodes to be called to refresh the topology of the cluster instance. If you connect to an ApsaraDB for Redis instance, you must set the parameter to false. 
             .enableAllAdaptiveRefreshTriggers()                                // Enable all triggers to adaptively refresh the topology. After adaptive refresh is enabled, the topology of the cluster instance is automatically refreshed each time a runtime event such as a MOVED redirection occurs on the cluster instance. 
             .adaptiveRefreshTriggersTimeout(Duration.ofSeconds(15)).build();   // Specify the time period during which the topology of the cluster instance can be refreshed only once. This prevents the topology from being frequently refreshed. 
 
         RedisClusterClient redisClient = RedisClusterClient.create(redisURI);
         redisClient.setOptions(ClusterClientOptions.builder()
             .socketOptions(SocketOptions.builder()
                 .keepAlive(true) // Set the keepAlive parameter to true. 
                 .build())
             .validateClusterNodeMembership(false)
             .topologyRefreshOptions(refreshOptions).build());
 
         StatefulRedisClusterConnection<String, String> connection = redisClient.connect();
         connection.sync().set("key", "value");
     }
 }
Note For more information about how to use Lettuce, visit GitHub.

FAQ

  • Q: What do I do if the Connection to xxx not allowed. This partition is not known in the cluster view. error occurs when I use Lettuce to connect to an ApsaraDB for Redis cluster instance?

    A: Specify the refreshOptions parameter. For more information, see Sample code for connecting Lettuce to a cluster instance.