如何通过直连模式访问Redis集群实例 您所在的位置:网站首页 百度直连模式 如何通过直连模式访问Redis集群实例

如何通过直连模式访问Redis集群实例

2023-10-17 21:48| 来源: 网络整理| 查看: 265

前提条件

开通直连访问。

将客户端地址加入Redis白名单。

使用Jedis、PhpRedis等支持Redis Cluster的客户端。

说明

使用不支持Redis Cluster的客户端,可能因客户端无法重定向请求到正确的分片而获取不到需要的数据。

您可以在Redis官网的客户端列表里查找更多支持Redis Cluster的客户端。

Redis客户端所在的ECS与目标Redis实例在同一VPC网络(相同VPC ID)。

背景信息

开启直连模式时,云Redis系统会为云Redis集群中所有数据分片的master节点分配一个虚拟IP(VIP)地址。客户端在首次向直连地址发送请求前会通过DNS服务器解析直连地址,解析结果会是集群中一个随机数据分片的VIP。获取到VIP后,客户端即可通过Redis Cluster协议操作云Redis集群中的数据。下图展示了直连模式下Redis集群版的服务架构。

图 1. Redis集群版直连模式服务架构Redis集群版直连模式服务架构

注意事项

由于部署架构的不同,相对标准架构来说,集群架构的实例在原生Redis命令的支持上有一定的区别(例如不支持SWAPDB命令、Lua存在使用限制等)。更多信息,请参见集群架构实例的命令限制。

直连模式下,如果执行变更实例配置,系统会采用Slot(槽)迁移的方式来完成,此场景下,客户端可能因访问到正在迁移的Slot而提示MOVED、TRYAGAIN等错误信息。如需确保请求的成功执行,请为客户端设计重试机制。更多信息,请参见Redis客户端重连指南。

直连模式支持使用SELECT命令切换DB,但部分Redis Cluster客户端(例如stackExchange.redis)不支持SELECT命令,如果使用该类客户端则只能使用DB0。

直连地址仅支持通过阿里云内网访问,且同时支持VPC免密和账号密码认证。

redis-cli

使用集群架构直连地址连接实例。

重要

使用直连地址连接时必须添加-c参数,否则会导致连接失败。

./redis-cli -h r-bp1zxszhcgatnx****.redis.rds.aliyuncs.com -p 6379 -c

完成密码验证。

AUTH testaccount:Rp829dlwa

关于redis-cli的更多介绍请参见通过redis-cli连接Tair。

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 < 单个数据库分片的最大连接数。 // 其中社区版单个分片的最大连接数为10,000,企业版单个分片的最大连接数为30,000。 config.setMaxTotal(30); // 最大空闲连接数, 根据业务需要设置。 config.setMaxIdle(20); config.setMinIdle(15); // 开通直连访问时申请到的直连地址。 String host = "r-bp1xxxxxxxxxxxx.redis.rds.aliyuncs.com"; int port = 6379; // 实例的密码。 String password = "xxxxx"; Set jedisClusterNode = new HashSet(); 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 jedisClusterNode = new HashSet(); 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(); // 当应用退出,需销毁资源时,调用此方法。此方法会断开连接、释放资源。 } }PhpRedis

本示例的PhpRedis版本为5.3.7,更多信息请参见PhpRedis。

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'))Spring Data Redis

本示例的Spring Data Redis版本为2.7.6,更多信息请参见Spring。

Spring Data Redis With Jedis(推荐)

@Bean JedisConnectionFactory redisConnectionFactory() { List clusterNodes = Arrays.asList("host1:port1", "host2:port2", "host3:port3"); RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(clusterNodes); redisClusterConfiguration.setPassword("xxx"); JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); // 最大空闲连接数,由于直连模式为客户端直接连接某个数据库分片,需要保证:业务机器数 * MaxTotal < 单个数据库分片的最大连接数。 // 其中社区版单个分片的最大连接数为10,000,企业版单个分片的最大连接数为30,000。 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

Bean public LettuceConnectionFactory redisConnectionFactory() { List 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)) .dynamicRefreshSources(false) .enableAllAdaptiveRefreshTriggers() .adaptiveRefreshTriggersTimeout(Duration.ofSeconds(15)).build(); LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder(). clientOptions(ClusterClientOptions.builder() .validateClusterNodeMembership(false) .topologyRefreshOptions(topologyRefreshOptions).build()).build(); return new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration); }

ClusterTopologyRefreshOptions.builder参数说明如下:

参数

说明

示例(推荐值)

enablePeriodicRefresh(Duration refreshPeriod)

启用定期集群拓扑刷新周期,建议为15s,若配置的值太小会产生大量的Cluster Nodes调用,影响性能。

15s

dynamicRefreshSources()

是否采用使用Cluster Nodes中获取的IP用来作为集群拓扑刷新的调用节点。连接Redis实例时,需要配置为false。由于Redis实例通常都是使用VIP(Virtual IP address),如果在迁移可用区的情况下,VIP会全部替换,从而无法刷新路由。因此关闭这个参数,使用阿里云提供的域名来查询Cluster nodes,域名服务会自动进行负载均衡,并且指向当前Redis节点。

false

enableAllAdaptiveRefreshTriggers()

开启集群拓扑刷新,包含遇到MOVED等消息就自动刷新集群一次。

无需配置

adaptiveRefreshTriggersTimeout(Duration timeout)

为防止集群拓扑刷新频率过高,此参数只允许在对应时间内产生一次拓扑刷新。

15s

validateClusterNodeMembership()

是否校验Cluster节点逻辑,阿里云Redis实例无需校验。

false

.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.18.5、Go-redis版本为8.11.5。

重要

Redis 6.0及以下版本:选择Go-redis v8.0及以下版本。

Redis 7.0及以上版本:选择Go-redis v9.0及以上版本。

package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) 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支持完整Redis API的同步和异步通信使用。由于Lettuce客户端在请求多次请求超时后,不再自动重连,当Redis实例因故障等因素导致代理或者数据库节点发生切换时,可能出现连接超时导致无法重连。为避免此类风险,推荐您使用其他客户端,更多信息请参见Lettuce。

本示例的Lettuce版本为6.2.2。

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)) .dynamicRefreshSources(false) .enableAllAdaptiveRefreshTriggers() .adaptiveRefreshTriggersTimeout(Duration.ofSeconds(15)).build(); RedisClusterClient redisClient = RedisClusterClient.create(redisURI); redisClient.setOptions(ClusterClientOptions.builder() .socketOptions(SocketOptions.builder() // 开启keepAlive参数。 .keepAlive(true) .build()) .validateClusterNodeMembership(false) .topologyRefreshOptions(refreshOptions).build()); StatefulRedisClusterConnection connection = redisClient.connect(); connection.sync().set("key", "value"); } }

关于ClusterTopologyRefreshOptions.builder参数,请参见上方Spring Data Redis With Lettuce中的说明。

常见问题

请参见Redis常见报错。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有