本文介紹如何通過redis-cli和代碼串連Tair Serverless KV Redis相容版執行個體。
前提條件
將用戶端IP地址加入白名單。
用戶端所在的ECS與執行個體在同一VPC網路(相同VPC ID)。
重要Tair Serverless KV僅支援在同VPC網路進行串連。ECS和Tair Serverless KV Redis相容版執行個體不在同一VPC怎麼辦?
串連執行個體
請根據表格擷取串連執行個體所需參數。
參數 | 說明 | 擷取方式 |
hostname | 串連地址 |
|
port | 連接埠號碼 | 連接埠號碼預設為6379,您也可以自訂連接埠號碼。具體操作,請參見修改串連地址或連接埠。 |
password | 密碼 | 根據使用帳號類型,填寫帳號、密碼:
如果忘記或未設定密碼,您可以修改或重設密碼。 |
Tair Serverless KV Redis相容版為分布式架構,相容原生Redis Cluster協議及串連、使用方式。請確保用戶端代碼以Redis Cluster的串連模式串連。
代碼串連
Jedis
本樣本的Jedis版本為4.3.0,更多資訊請參見Jedis。
使用自訂串連池(推薦)
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[]) { // 最大串連數,由於直連模式為用戶端直接連接某個資料庫分區,需要保證:業務機器數 * MaxTotal < 單個資料庫分區的最大串連數。 config.setMaxTotal(30); // 最大空閑串連數, 根據業務需要設定。 config.setMaxIdle(20); config.setMinIdle(15); // 開通直連訪問時申請到的直連地址。 String host = "r-bp1xxxxxxxxxxxx.redis.rds.aliyuncs.com"; int port = 6379; // 執行個體的密碼。 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(); // 當應用退出,需銷毀資源時,調用此方法。此方法會中斷連線、釋放資源。 } }使用預設串連池
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[]){ // 開通直連訪問時申請到的直連地址。 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(); // 當應用退出,需銷毀資源時,調用此方法。此方法會中斷連線、釋放資源。 } }
Spring Data Redis
本樣本使用Maven方式進行構建,您也可以手動下載Lettuce或Jedis用戶端。
添加下述Maven依賴。
<?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>在Spring Data Redis編輯器中輸入下述代碼,然後根據注釋提示修改代碼。
本樣本的Spring Data Redis版本為2.4.2。
(推薦)Spring Data Redis With Jedis
@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(); // 最大空閑串連數,由於直連模式為用戶端直接連接某個資料庫分區,需要保證:業務機器數 * MaxTotal < 單個資料庫分區的最大串連數。 jedisPoolConfig.setMaxTotal(30); // 最大空閑串連數, 根據業務需要設定。 jedisPoolConfig.setMaxIdle(20); // 關閉 testOn[Borrow|Return],防止產生額外的 PING jedisPoolConfig.setTestOnBorrow(false); jedisPoolConfig.setTestOnReturn(false); return new JedisConnectionFactory(redisClusterConfiguration, jedisPoolConfig); }Spring Data Redis With Lettuce
警告Lettuce 預設配置可能導致執行個體變更時應用延遲增加和無法訪問等問題。請仔細閱讀Lettuce相關參數說明,以正確配置 Lettuce。
Lettuce 的版本應大於等於 6.3.0.RELEASE,更多資訊請參見【通知】Lettuce用戶端升級建議。
/** * TCP_KEEPALIVE開啟,並且配置三個參數分別為: * TCP_KEEPIDLE = 30 * TCP_KEEPINTVL = 10 * TCP_KEEPCNT = 3 */ private static final int TCP_KEEPALIVE_IDLE = 30; /** * TCP_USER_TIMEOUT參數可以避免在故障宕機情境下,Lettuce持續逾時的問題。 * 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
本樣本的PhpRedis版本為5.3.7,更多資訊請參見PhpRedis。
<?php
// 直連地址和串連連接埠。
$array = ['r-bp1xxxxxxxxxxxx.redis.rds.aliyuncs.com:6379'];
// 串連密碼。
$pwd = "xxxx";
// 使用密碼串連叢集。
$obj_cluster = new RedisCluster(NULL, $array, 1.5, 1.5, true, $pwd);
// 輸出串連結果。
var_dump($obj_cluster);
if ($obj_cluster->set("foo", "bar") == false) {
die($obj_cluster->getLastError());
}
$value = $obj_cluster->get("foo");
echo $value;
?>redis-py
本樣本的Python版本為3.9、redis-py版本為4.4.1,更多資訊請參見redis-py。
# !/usr/bin/env python
# -*- coding: utf-8 -*-
from redis.cluster import RedisCluster
# 分別將host和port的值替換為執行個體的串連地址、連接埠號碼。
host = 'r-bp10noxlhcoim2****.redis.rds.aliyuncs.com'
port = 6379
# 分別將user和pwd的值替換為執行個體的帳號和密碼。
user = 'testaccount'
pwd = 'Rp829dlwa'
rc = RedisCluster(host=host, port=port, username=user, password=pwd)
# 串連建立後即可執行資料庫操作,下述代碼為您提供SET與GET的使用樣本。
rc.set('foo', 'bar')
print(rc.get('foo')).Net
本樣本的.Net版本為6.0,StackExchange.Redis版本為2.6.90。
using StackExchange.Redis;
class RedisConnSingleton {
// 分別設定執行個體的串連地址、連接埠號碼和使用者名稱、密碼。
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
本樣本的Node.js版本為19.4.0、node-redis版本為4.5.1。
import { createCluster } from 'redis';
// 分別設定執行個體的連接埠號碼、串連地址、帳號、密碼,
// 注意,在url中配置使用者和密碼之後,還需要在defaults中設定全域使用者和密碼,
// 用於其餘節點的認證,否則將出現NOAUTH的錯誤。
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
本樣本的Go版本為1.19.7、Go-redis版本為9.5.1。
請使用Go-redis v9.0及以上版本,否則在使用直連模式地址時,可能會產生不相容報錯。
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)
}Lettuce
Lettuce 預設配置可能導致執行個體變更時應用延遲增加和無法訪問等問題。請仔細閱讀Lettuce相關參數說明,以正確配置 Lettuce。
Lettuce 的版本應大於等於 6.3.0.RELEASE,更多資訊請參見【通知】Lettuce用戶端升級建議。
添加下述Maven依賴。
<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>添加下述代碼,並根據注釋提示修改代碼。
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 { /** * TCP_KEEPALIVE 開啟,並且配置三個參數分別為: * TCP_KEEPIDLE = 30 * TCP_KEEPINTVL = 10 * TCP_KEEPCNT = 3 */ private static final int TCP_KEEPALIVE_IDLE = 30; /** * TCP_USER_TIMEOUT可以避免在故障宕機情境下Lettuce持續逾時的問題。 * 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 { // 分別將host、port和password的值替換為實際的執行個體資訊。 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")); } }執行上述代碼,預期會返回如下結果:
value
Lettuce 相關參數說明如下:
參數 | 預設配置 | 說明 | 修改配置 |
enablePeriodicRefresh(Duration refreshPeriod) | 關閉 | 啟用後將進行周期性叢集拓撲重新整理。 | 建議配置為 60s。 開啟此配置可以使不活躍的長串連也能及時更新本地拓撲。 |
dynamicRefreshSources(boolean dynamicRefreshSources) | true | 為 true 時,使用 Cluster Nodes 命令返回的所有節點進行叢集拓撲重新整理;為 false 時,使用指定節點地址。 | 如無特殊需求,應配置為 false。 啟用此選項會向所有節點發送 CLUSTER NODES 命令,增加服務端壓力。此外,在變更配置期間,使用 endpoint 地址更新拓撲通常更為迅速可靠。 |
enableAllAdaptiveRefreshTriggers() | 關閉 | 啟用後,當收到 MOVED 訊息時,會自動重新整理叢集拓撲。 | 必須啟用。 啟用此配置才能確保拓撲變更後 Lettuce 能及時更新本地拓撲。 |
adaptiveRefreshTriggersTimeout(Duration timeout) | 30s | 限制叢集拓撲重新整理頻率,在指定時間內僅允許一次重新整理。 | 建議配置為 15s。 由於叢集中多個節點的拓撲變更並非原子操作,Lettuce 觸發的初次拓撲重新整理可能會失敗,因此需要快速進行後續重新整理以確保拓撲正確更新。當應用數量較少時,由於不會有大量用戶端同時發送 CLUSTER NODES 命令,可以適當降低該值,以實現更快的拓撲表收斂時間。 |
validateClusterNodeMembership(boolean validateClusterNodeMembership) | true | 在拓撲變化時,Lettuce 使用 MOVED 將命令重新導向到正確的節點。啟用此配置後,只允許將命令重新導向到 CLUSTER NODES 輸出中已知的節點。 | 必須配置為 false。 配置為 false 可以防止在叢集拓撲變更後,本地拓撲重新整理完成前無法訪問新增節點。 |
redis-cli串連
串連執行個體:
./redis-cli -h r-bp1zxszhcgatnx****.redis.rds.aliyuncs.com -p 6379 -c完成密碼驗證。
AUTH testaccount:Rp829dlwa
關於redis-cli的更多介紹請參見通過redis-cli串連執行個體。
常見問題
Q:ECS和Tair Serverless KV Redis相容版執行個體不在同一VPC怎麼辦?
A:可更換ECS執行個體的VPC至同一VPC或開通與ECS執行個體同一VPC的Tair Serverless KV執行個體。
Q:用戶端和Tair Serverless KV執行個體可以不在同一可用性區域嗎?
答:用戶端與Tair Serverless KV的連通僅需二者屬於同一VPC即可,跨可用性區域訪問僅會帶來時延的輕微增加(通常為1~2ms)。