This topic shows how to connect to a Tair Serverless KV Redis-compatible instance using redis-cli and code examples.
Prerequisites
Add your client's IP address to the instance's whitelist.
The ECS instance running your client and the Tair Serverless KV instance must be in the same VPC.
ImportantTair Serverless KV supports only connections within the same VPC. What do I do if my ECS instance and Tair Serverless KV Redis-compatible instance are in different VPCs?
Connect to the instance
The following table lists the parameters required to connect.
Parameter | Description | How to obtain |
hostname | endpoint |
|
port | port number | The default port number is 6379. You can also customize the port number. For more information, see Modify an endpoint or port number. |
password | password | Enter the username and password based on the account type:
If you forget your password or have not set one, you can change or reset the password. |
Tair Serverless KV uses a distributed architecture and is compatible with the native Redis Cluster protocol. Ensure that your client connects to the instance in Redis Cluster mode.
Connect using code
Jedis
In this example, Jedis 4.3.0 is used. For more information, visit GitHub.
Custom connection pool (recommended)
import redis.clients.jedis.*; 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 ConnectionPoolConfig config = new ConnectionPoolConfig(); public static void main(String args[]) { // Specify the maximum number of 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. config.setMaxTotal(30); // Specify the maximum number of idle connections based on your business needs. config.setMaxIdle(20); config.setMinIdle(15); // Specify the private endpoint that is allocated to the cluster instance. String host = "r-bp1xxxxxxxxxxxx.redis.rds.aliyuncs.com"; int port = 6379; // Specify the password that is used to connect to the cluster 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); jc.set("key", "value"); jc.get("key"); jc.close(); // If the application exits and you want to destroy the resources, call this method. This way, the connection is closed, and the resources are released. } }Default connection pool
import redis.clients.jedis.ConnectionPoolConfig; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; 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 ConnectionPoolConfig DEFAULT_CONFIG = new ConnectionPoolConfig(); public static void main(String args[]){ // Specify the private endpoint that is allocated to 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(); // If the application exits and you want to destroy the resources, call this method. This way, the connection is closed, and the resources are released. } }
Connect with Spring Data Redis
The following Maven project uses Spring Data Redis 2.4.2. Alternatively, download the Lettuce or Jedis client manually.
Step 1: Add Maven dependencies
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.aliyun.tair</groupId>
<artifactId>spring-boot-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-example</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport-native-epoll</artifactId>
<version>4.1.100.Final</version>
<classifier>linux-x86_64</classifier>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>Step 2: Configure the connection
Choose either Jedis (recommended) or Lettuce as the underlying client.
Spring Data Redis with Jedis (recommended)
@Bean
JedisConnectionFactory redisConnectionFactory() {
List<String> clusterNodes = Arrays.asList("r-bp10noxlhcoim2****.redis.rds.aliyuncs.com:6379");
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(clusterNodes);
redisClusterConfiguration.setUsername("user");
redisClusterConfiguration.setPassword("password");
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
// Number of clients x MaxTotal < Maximum connections to a single shard.
jedisPoolConfig.setMaxTotal(30);
jedisPoolConfig.setMaxIdle(20);
// Disable testOn[Borrow|Return] to avoid extra ping commands.
jedisPoolConfig.setTestOnBorrow(false);
jedisPoolConfig.setTestOnReturn(false);
return new JedisConnectionFactory(redisClusterConfiguration, jedisPoolConfig);
}Spring Data Redis with Lettuce
Default Lettuce configurations may cause increased latency and inaccessibility during instance changes. Read the Lettuce parameter reference carefully before configuring.
Use Lettuce 6.3.0.RELEASE or later. For more information, see [Notice] Suggestions for upgrading Lettuce.
/**
* Enable TCP keepalive and configure the following three parameters:
* TCP_KEEPIDLE = 30
* TCP_KEEPINTVL = 10
* TCP_KEEPCNT = 3
*/
private static final int TCP_KEEPALIVE_IDLE = 30;
/**
* TCP_USER_TIMEOUT avoids scenarios where Lettuce remains stuck in a
* continuous timeout loop during a failure or crash event.
* refer: https://github.com/lettuce-io/lettuce-core/issues/2082
*/
private static final int TCP_USER_TIMEOUT = 30;
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
List<String> clusterNodes = Arrays.asList("r-bp10noxlhcoim2****.redis.rds.aliyuncs.com:6379");
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(clusterNodes);
redisClusterConfiguration.setUsername("user");
redisClusterConfiguration.setPassword("password");
// Config TCP KeepAlive
SocketOptions socketOptions = SocketOptions.builder()
.keepAlive(KeepAliveOptions.builder()
.enable()
.idle(Duration.ofSeconds(TCP_KEEPALIVE_IDLE))
.interval(Duration.ofSeconds(TCP_KEEPALIVE_IDLE / 3))
.count(3)
.build())
.tcpUserTimeout(TcpUserTimeoutOptions.builder()
.enable()
.tcpUserTimeout(Duration.ofSeconds(TCP_USER_TIMEOUT))
.build())
.build();
ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
.enablePeriodicRefresh(Duration.ofSeconds(60))
.dynamicRefreshSources(false)
.enableAllAdaptiveRefreshTriggers()
.adaptiveRefreshTriggersTimeout(Duration.ofSeconds(15)).build();
LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder().
clientOptions(ClusterClientOptions.builder()
.socketOptions(socketOptions)
.validateClusterNodeMembership(false)
.topologyRefreshOptions(topologyRefreshOptions).build()).build();
return new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration);
}PhpRedis
In this example, PhpRedis 5.3.7 is used. For more information, visit GitHub.
<?php
// Specify the private endpoint and port number that are used to connect to the cluster instance.
$array = ['r-bp1xxxxxxxxxxxx.redis.rds.aliyuncs.com:6379'];
// Specify the password that is used to connect to the cluster instance.
$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;
?>redis-py
In this example, Python 3.9 and redis-py 4.4.1 are used. For more information, visit GitHub.
# !/usr/bin/env python
# -*- coding: utf-8 -*-
from redis.cluster import RedisCluster
# Replace the values of the host and port parameters with the endpoint and port number that are used to connect to the instance.
host = 'r-bp10noxlhcoim2****.redis.rds.aliyuncs.com'
port = 6379
# Replace the values of the user and pwd parameters with the username and password that are used to connect to the instance.
user = 'testaccount'
pwd = 'Rp829dlwa'
rc = RedisCluster(host=host, port=port, username=user, password=pwd)
# You can perform operations on the instance after the connection is established. The following code provides an example on how to call the set and get methods:
rc.set('foo', 'bar')
print(rc.get('foo')).NET
In this example, .NET 6.0 and StackExchange.Redis 2.6.90 are used.
using StackExchange.Redis;
class RedisConnSingleton {
// Specify the endpoint, port number, username, and password that are used to connect to the cluster instance.
private static ConfigurationOptions configurationOptions = ConfigurationOptions.Parse("r-bp10noxlhcoim2****.redis.rds.aliyuncs.com:6379,user=testaccount,password=Rp829dlwa,connectTimeout=2000");
//the lock for singleton
private static readonly object Locker = new object();
//singleton
private static ConnectionMultiplexer redisConn;
//singleton
public static ConnectionMultiplexer getRedisConn()
{
if (redisConn == null)
{
lock (Locker)
{
if (redisConn == null || !redisConn.IsConnected)
{
redisConn = ConnectionMultiplexer.Connect(configurationOptions);
}
}
}
return redisConn;
}
}
class Program
{
static void Main(string[] args)
{
ConnectionMultiplexer cm = RedisConnSingleton.getRedisConn();
var db = cm.GetDatabase();
db.StringSet("key", "value");
String ret = db.StringGet("key");
Console.WriteLine("get key: " + ret);
}
}node-redis
In this example, Node.js 19.4.0 and node-redis 4.5.1 are used.
import { createCluster } from 'redis';
// Specify the endpoint, port number, username, and password that are used to connect to the instance.
// After you supply the username and password for the url parameter, you must also supply the global username and password for the defaults parameter.
// The global username and password are used to authenticate the remaining nodes. If the remaining nodes are not authenticated, the NOAUTH error occurs.
const cluster = createCluster({
rootNodes: [{
url: 'redis://testaccount:Rp829dlwa@r-bp10noxlhcoim2****.redis.rds.aliyuncs.com:6379'
}],
defaults: {
username: 'testaccount',
password: 'Rp829dlwa'
}
});
cluster.on('error', (err) => console.log('Redis Cluster Error', err));
await cluster.connect();
await cluster.set('key', 'value');
const value = await cluster.get('key');
console.log('get key: %s', value);
await cluster.disconnect();
Go-redis
In this example, Go 1.19.7 and go-redis 9.5.1 are used.
Use go-redis 9.0 or later. If you use a go-redis version earlier than 9.0, an incompatibility error may occur when you connect to a private endpoint. For more information, see Common errors and troubleshooting.
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v9"
)
var ctx = context.Background()
func main() {
rdb := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{"r-bp10noxlhcoim2****.redis.rds.aliyuncs.com:6379"},
Username: "testaccount",
Password: "Rp829dlwa",
})
err := rdb.Set(ctx, "key", "value", 0).Err()
if err != nil {
panic(err)
}
val, err := rdb.Get(ctx, "key").Result()
if err != nil {
panic(err)
}
fmt.Println("key", val)
}Connect with Lettuce (standalone)
Default Lettuce configurations may cause increased latency and inaccessibility during instance changes. Read the Lettuce parameter reference carefully before configuring.
Use Lettuce 6.3.0.RELEASE or later. For more information, see [Notice] Suggestions for upgrading Lettuce.
Step 1: Add Maven dependencies
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport-native-epoll</artifactId>
<version>4.1.65.Final</version>
<classifier>linux-x86_64</classifier>
</dependency>Step 2: Add the connection code
Replace the values of host, port, and password with the actual instance information.
import io.lettuce.core.RedisURI;
import io.lettuce.core.SocketOptions;
import io.lettuce.core.cluster.ClusterClientOptions;
import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
import io.lettuce.core.cluster.RedisClusterClient;
import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
import java.time.Duration;
public class ClusterDemo {
/**
* Enable TCP keepalive and configure the following three parameters:
* TCP_KEEPIDLE = 30
* TCP_KEEPINTVL = 10
* TCP_KEEPCNT = 3
*/
private static final int TCP_KEEPALIVE_IDLE = 30;
/**
* TCP_USER_TIMEOUT avoids situations where Lettuce remains stuck in a
* continuous timeout loop during a failure or crash event.
* refer: https://github.com/lettuce-io/lettuce-core/issues/2082
*/
private static final int TCP_USER_TIMEOUT = 30;
public static void main(String[] args) throws Exception {
// Replace with the actual instance information.
String host = "r-bp1ln3c4kopj3l****.redis.rds.aliyuncs.com";
int port = 6379;
String password = "Da****3";
RedisURI redisURI = RedisURI.Builder.redis(host)
.withPort(port)
.withPassword(password)
.build();
ClusterTopologyRefreshOptions refreshOptions = ClusterTopologyRefreshOptions.builder()
.enablePeriodicRefresh(Duration.ofSeconds(60))
.dynamicRefreshSources(false)
.enableAllAdaptiveRefreshTriggers()
.adaptiveRefreshTriggersTimeout(Duration.ofSeconds(15)).build();
// Config TCP KeepAlive
SocketOptions socketOptions = SocketOptions.builder()
.keepAlive(SocketOptions.KeepAliveOptions.builder()
.enable()
.idle(Duration.ofSeconds(TCP_KEEPALIVE_IDLE))
.interval(Duration.ofSeconds(TCP_KEEPALIVE_IDLE/3))
.count(3)
.build())
.tcpUserTimeout(SocketOptions.TcpUserTimeoutOptions.builder()
.enable()
.tcpUserTimeout(Duration.ofSeconds(TCP_USER_TIMEOUT))
.build())
.build();
RedisClusterClient redisClient = RedisClusterClient.create(redisURI);
redisClient.setOptions(ClusterClientOptions.builder()
.socketOptions(socketOptions)
.validateClusterNodeMembership(false)
.topologyRefreshOptions(refreshOptions).build());
StatefulRedisClusterConnection<String, String> connection = redisClient.connect();
connection.sync().set("key", "value");
System.out.println(connection.sync().get("key"));
}
}Expected output on success:
valueConnect using redis-cli
Connect to the instance:
./redis-cli -h r-bp1zxszhcgatnx****.redis.rds.aliyuncs.com -p 6379 -cAuthenticate the connection.
AUTH testaccount:Rp829dlwa
For more information about redis-cli, see Connect to an instance using redis-cli.
FAQ
Q: What do I do if my ECS instance and Tair Serverless KV Redis-compatible instance are not in the same VPC?
A: You can either change the VPC of the ECS instance to match the Tair Serverless KV instance's VPC, or create a new Tair Serverless KV instance in the same VPC as the ECS instance.
Q: Can the client and the Tair Serverless KV instance be in different availability zones?
A: Yes. As long as they are in the same VPC, they can connect. Cross-availability zone connections typically add only 1–2 ms of latency.