安全组配置和选择
由于Redis 3.0和Redis 4.0/5.0/6.0实例的部署模式不一样,DCS在控制访问缓存实例的方式也不一样,差别如下:
- Redis 3.0:通过配置安全组访问规则控制,不支持白名单功能。安全组配置操作请参考本章节操作。
- Redis 4.0/5.0/6.0:不支持安全组,只支持通过白名单控制。
VPC内访问Redis 3.0实例
客户端只能部署在与DCS缓存实例处于相同虚拟私有云(VPC)和相同子网的弹性云主机(ECS)上。
除了ECS、DCS缓存实例必须处于相同VPC和相同子网之外,还需要将安全组分别配置了正确的规则,客户端才能访问DCS缓存实例。
- 如果ECS、DCS缓存实例配置了相同的安全组,安全组创建后,默认包含组内网络访问不受限制的规则。
- 如果ECS、DCS缓存实例配置了不同的安全组,可参考如下配置方式:
说明
假设ECS、DCS缓存实例分别配置了安全组:sg-ECS、sg-DCS。
假设DCS缓存实例服务端口为6379。
以下规则,远端可使用安全组,也可以使用具体的IP地址。
a. 配置ECS所在安全组。
ECS所在安全组需要增加出方向规则,以保证客户端能正常访问DCS缓存实例。如果出方向规则不受限,则不用添加。
b. 配置DCS缓存实例所在安全组。
DCS实例所在安全组需要增加入方向规则,以保证能被客户端访问。
注意缓存实例的入方向规则中,远端地址建议使用与子网同网段的IP地址。
慎用“0.0.0.0/0”,避免绑定相同安全组的弹性云主机遭受Redis漏洞攻击。
DCS实例支持公网访问吗?
不支持在DCS实例绑定弹性IP进行公网访问的方式。您必须通过同一虚拟私有云下的弹性云主机来访问缓存实例,以确保缓存数据的安全。
DCS实例是否支持跨VPC访问?
跨VPC访问,即客户端和实例是否在同一个VPC。
一般情况下,不同VPC间网络不互通,不在同一VPC下的弹性云主机无法访问DCS缓存实例。
对于单机和主备类型的DCS缓存实例,可以通过创建VPC对等连接,将两个VPC的网络打通,实现跨VPC访问DCS缓存实例。
用户通过VPC对等访问DCS缓存实例时,除了满足VPC对等网跨VPC访问的约束之外,还存在如下约束:
- 当创建实例时使用了172.16.0.0/12~24网段时,客户端不能在192.168.1.0/24、192.168.2.0/24、192.168.3.0/24网段。
- 当创建实例时使用了192.168.0.0/16~24网段时,客户端不能在172.31.1.0/24、172.31.2.0/24、172.31.3.0/24网段。
- 当创建实例时使用了10.0.0.0/8~24网段时,客户端不能在172.31.1.0/24、172.31.2.0/24、172.31.3.0/24网段。
关于创建和使用VPC对等连接,请参考《虚拟私有云 用户指南》的“对等连接”章节。
注意DCS Redis集群实例不支持跨VPC访问,比如不能通过建立VPC对等连接的方式,从一个VPC去访问另一个VPC的集群实例。
Redis连接时报错:“(error) NOAUTH Authentication required”。
报错信息是指实例设置了免密访问。连接时不输入密码,即可避免上述错误。
客户Http的Server端关闭导致Redis访问失败
原因分析:客户端使用长连接,或者连接池,用完后关闭与DCS实例的连接,再次使用时,出现报错。
解决方案:使用长连接或连接池,用完后不要关闭连接;如果发现连接中断,请重新建连。
客户端出现概率性超时错误
针对低概率超时错误,是Redis使用的正常现象。Redis使用受到网络传输、客户端设置超时时间等因素影响,可能出现单个请求超时问题。
建议客户业务编码时,具备重试操作,提升业务的可靠性,避免低概率的单次请求失败时业务失败。
当出现了连接超时问题时,可以优先检查Redis是否开启了aof持久化功能,这需要根据业务需求,决定是否开启,防止出现阻塞,连接不上的情况。
如果出现超时错误概率频繁,请联系服务运维。
使用Jedis连接池报错如何处理?
在使用Jedis连接池JedisPool模式下,比较常见的报错如下:
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
首先确认DCS缓存实例是正常运行中状态,然后按以下步骤进行排查。
步骤 1 网络
- 核对IP地址配置
检查jedis客户端配置的ip地址是否与DCS缓存实例配置的子网地址一致。
- 测试网络
在客户端使用ping和Telnet小工具测试网络。
− 如果ping不通:
VPC内访问Redis 3.0实例时,要求客户端与DCS缓存实例的VPC相同,安全组相同或者DCS缓存实例的安全组放开了6379端口访问。
− 如果IP地址可以ping通,telnet对应的端口不通,则尝试重启实例,如重启后仍未恢复,请联系技术支持。
步骤 2 检查连接数是否超限
查看已建立的网络连接数是否超过JedisPool 配置的上限。如果连接数接近配置的上限值,则建议重启服务观察。如果明显没有接近,排除连接数超限可能。
Unix/Linux系统使用**:**
netstat -an | grep 6379 | grep ESTABLISHED | wc -l
Windows系统使用:
netstat -an | find "6379" | find "ESTABLISHED" /C
步骤 3 检查JedisPool连接池代码
如果连接数接近配置的上限,请分析是业务并发原因,或是没有正确使用JedisPool所致。
对于JedisPool连接池的操作,每次调用 jedisPool.getResource() 方法之后,需要调用 jedisPool.returnResource() 或者 jedis.close() 进行释放,优先使用close()方法。
步骤 4 客户端TIME_WAIT是否过多
通过ss -s查看time wait链接是否过多。
如果TIME_WAIT过多,可以调整内核参数(/etc/sysctl.conf):
##当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击
net.ipv4.tcp_syncookies = 1
##允许将TIME-WAIT sockets重新用于新的TCP连接
net.ipv4.tcp_tw_reuse = 1
##开启TCP连接中TIME-WAIT sockets的快速回收
net.ipv4.tcp_tw_recycle = 1
##修改系统默认的TIMEOUT时间
net.ipv4.tcp_fin_timeout = 30
调整后重启生效:/sbin/sysctl -p
步骤 5 无法解决问题
如果按照以上原因排查之后还有问题,可以通过抓包并将异常时间点、异常信息以及抓包文件发送给技术支持协助分析。
抓包可使用tcpdump工具,命令如下:
tcpdump -i eth0 tcp and port 6379 -n -nn -s 74 -w dump.pcap
Windows系统下还可以安装Wireshark工具抓包。
说明网卡名请改成实际的网卡名称。
客户端访问Redis实例出现“ERR unknown command”的原因是什么?
有以下可能原因:
- 命令拼写不正确
如下图所示,命令拼写有误,Redis实例返回“ERR unknown command”,删除String的正确命令为 del 。
- 在低版本Redis实例运行高版本命令
如下图所示,在Redis3.0版本运行Redis5.0新增的Stream相关命令,Redis实例返回命令出错信息。
- 部分命令被禁用
DCS Redis实例接口与开源Redis在数据访问方面完全兼容。但因易用性和安全性的原因,部分管理操作不能从Redis客户端发起,具体禁用的命令清单,请参考Redis命令。
如何使用Redis-desktop-manager访问Redis实例?
如下介绍通过内网使用Redis-desktop-manager访问Redis实例的操作:
1.填写DCS实例子网地址,端口6379,以及相应密码。
2.单击左下角“测试连接”。
提示成功后,说明连接正常。
通过内网使用Redis-desktop-manager访问Redis实例
说明使用Redis-desktop-manager访问DCS集群实例时,执行redis命令是正常的,但是左侧显示异常,这个是因为DCS集群是基于codis架构,info命令的输出和原生的redis不一样。
使用SpringCloud时出现ERR Unsupported CONFIG subcommand怎么办?
DCS的Redis实例可以配合Spring_Session进行Session共享。DCS的Redis实例对接SpringCloud时,遇到如下错误信息:
Spring Cloud报错信息
原因为出于安全考虑,DCS暂不支持客户端发起的CONFIG命令,需要按如下步骤进行操作:
- 通过管理控制台修改Redis实例的配置参数notify-keyspace-event,将值指定为“Egx”。
- 在Spring框架的XML配置文件中,增加如下:
<util:constant
static-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/>
- 修改Spring相关代码,通过启用ConfigureRedisAction.NO_OP这个bean组件,禁止通过客户端调用CONFIG命令,避免报错。
@Bean
public static ConfigureRedisAction configureRedisAction() {
return ConfigureRedisAction.NO_OP;
}
更多说明,可参考Spring官方文档。
注意仅Redis单机和主备实例支持Spring的Session共享,Redis集群版不支持。
连接实例必须使用密码吗?如何获取密码?
- Redis实例支持密码模式和免密模式。Redis本身支持不设置密码,客户端可以直接连接Redis缓存服务并使用,但出于安全考虑,建议尽量选用密码模式,通过密码来鉴权验证,提升安全性。若选用密码模式,您需要在创建实例时自定义密码。
- 如需修改Redis访问方式、修改或重置密码,请参考密码管理。
Redis实例连接失败的原因排查
初步排查:
- 检查连接地址
连接地址可从管理控制台的实例详情页面获取。
- 检查密码
密码输入错误时,端口可以连接上,但鉴权认证失败。
- 检查端口
VPC内访问,Redis实例端口默认为6379。
- 检查带宽是否使用超限
当实例使用带宽达到实例规格上限,可能会导致部分Redis连接超时现象。
- 如果是Redis 3.0实例,检查安全组的入方向规则
VPC内访问时,如果Redis客户端和Redis实例绑定了不同的安全组,则需要将Redis实例的入方向安全组放开6379端口。
具体请参考:安全组配置和选择。
- 如果是Redis 4.0/5.0/6.0实例,检查白名单配置
如果实例开启了白名单,在使用客户端连接时,需要确保客户端IP在白名单内,如果不在白名单,会出现连接失败。
客户端IP如果有变化,需要将变化后的IP加入白名单。
- 检查实例配置参数notify-keyspace-events
建议将notify-keyspace-events参数配置为Egx。
进阶排查
- Jedis连接池报错
- 出现Read timed out或Could not get a resource from the pool
排查是否使用了keys命令,keys命令会消耗大量资源,造成Redis阻塞。建议使用scan命令替代,且避免频繁执行。
使用短连接访问Redis出现“Cannot assign requested address”错误
问题描述
应用程序通过短连接访问Redis实例时,报错:Cannot assign requested address。
问题分析
出现这种错误的应用程序使用的架构基本都是php-fpm加上phpredis,这种架构在并发量较大的情况下,处于TIME-WAIT状态下的TCP连接数较多,客户端无法分配出新的端口,则会出现“Cannot assign requested address”问题。
处理方案
- 方案一:使用pconnect替换connect。
此方案的思路是用长连接替代短连接,减少TCP连接,同时可以避免每次请求都会重新建立连接的问题,减少延时。
之前连接Redis的代码如下:
$redis->connect('${Hostname}',${Port});
$redis->auth('${Inst_Password}');
现使用pconnect替换connect,即使用persistent connection的方式连接。
$redis->pconnect('${Hostname}', ${Port}, 0, NULL, 0, 0, ['auth' => ['${Inst_Password}']]);
说明
示例中的连接参数请根据业务实现情况修改,${Hostname}、${Port}和${Inst_Password}为Redis实例的连接地址、端口号和密码。
PhpRedis应为5.3.0及以上版本,且建议使用这种pconnect初始化方式,避免断连时出现no auth问题。
- 方案二:修改客户端所在ECS实例的tcp_max_tw_buckets内核参数。
此方案的思路是直接复用处于TIME-WAIT状态的端口,但是如果ECS和后端服务之间有重传,连接可能会失败,所以建议使用pconnect的方案。
a. 连接客户端所在ECS实例。
b. 执行以下命令,查看ip_local_port_range和tcp_max_tw_buckets参数。
sysctl net.ipv4.tcp_max_tw_buckets net.ipv4.ip_local_port_range
系统显示类似如下:
net.ipv4.tcp_max_tw_buckets = 262144
net.ipv4.ip_local_port_range = 32768 61000
c. 执行以下命令,修改tcp_max_tw_buckets参数,确保tcp_max_tw_buckets的值比ip_local_port_range范围的值小。
sysctl -w net.ipv4.tcp_max_tw_buckets=10000
一般情况推荐使用方案一,对于一些特定场景(业务代码牵涉过多组件不易变更等场景),需要更快的满足高并发,可以使用方案二
连接池选择及Jedis连接池参数配置建议
Jedis连接池优势
Lettuce客户端及Jedis客户端比较如下:
-
Lettuce:
- Lettuce客户端没有连接保活探测,错误连接存在连接池中会造成请求超时报错。
- Lettuce客户端未实现testOnBorrow等连接池检测方法,无法在使用连接之前进行连接校验。
-
Jedis:
- Jedis客户端实现了testOnBorrow、testWhileIdle、testOnReturn等连接池校验配置
- 开启testOnBorrow在每次借用连接前都会进行连接校验,可靠性最高,但是会影响性能(每次Redis请求前会进行探测)。
- testWhileIdle可以在连接空闲时进行连接检测,合理配置阈值可以及时剔除连接池中的异常连接,防止使用异常连接造成业务报错。
- 在空闲连接检测之前,连接出现问题,可能会造成使用该连接的业务报错,此处可以通过参数控制检测间隔(timeBetweenEvictionRunsMillis)。
因此,Jedis客户端在面对连接异常,网络抖动等场景下的异常处理和检测能力明显强于Lettuce,可靠性更强。
Jedis连接池参数配置建议
参数 | 配置介绍 | 配置建议 |
---|---|---|
maxTotal | 最大连接,单位:个 | 根据Web容器的Http线程数来进行配置,估算单个Http请求中可能会并行进行的Redis调用次数,例如:Tomcat中的Connector内的maxConnections配置为150,每个Http请求可能会并行执行2个Redis请求,在此之上进行部分预留,则建议配置至少为:150 x 2 + 100= 400**限制条件:**单个Redis实例的最大连接数。maxTotal和客户端节点数(CCE容器或业务VM数量)数值的乘积要小于单个Redis实例的最大连接数。例如:Redis主备实例配置maxClients为10000,单个客户端maxTotal配置为500,则最大客户端节点数量为20个。 |
maxIdle | 最大空闲连接,单位:个 | 建议配置为maxTotal一致。 |
minIdle | 最小空闲连接,单位:个 | 一般来说建议配置为maxTotal的X分之一,例如此处常规配置建议为:100。对于性能敏感的场景,防止经常连接数量抖动造成影响,也可以配置为与maxIdle一致,例如:400。 |
maxWaitMillis | 最大获取连接等待时间,单位:毫秒 | 获取连接时最大的连接池等待时间,根据单次业务最长容忍的失败时间减去执行命令的超时时间得到建议值。例如:Http最大容忍超时时间为15s,Redis请求的timeout设置为10s,则此处可以配置为5s。 |
timeout | 命令执行超时时间,单位:毫秒 | 单次执行Redis命令最大可容忍的超时时间,根据业务程序的逻辑进行选择,一般来说处于对网络容错等考虑至少建议配置为210ms以上。特殊的探测逻辑或者环境异常检测等,可以适当调整达到秒级。 |
minEvictableIdleTimeMillis | 空闲连接逐出时间,大于该值的空闲连接一直未被使用则会被释放,单位:毫秒 | 如果希望系统不会经常对连接进行断链重建,此处可以配置一个较大值(xx分钟),或者此处配置为-1并且搭配空闲连接检测进行定期检测。 |
timeBetweenEvictionRunsMillis | 空闲连接探测时间间隔,单位:毫秒 | 根据系统的空闲连接数量进行估算,例如系统的空闲连接探测时间配置为30s,则代表每隔30s会对连接进行探测,如果30s内发生异常的连接,经过探测后会进行连接排除。根据连接数的多少进行配置,如果连接数太大,配置时间太短,会造成请求资源浪费。对于几百级别的连接,常规来说建议配置为30s,可以根据系统需要进行动态调整。 |
testOnBorrow | 向资源池借用连接时是否做连接有效性检测(ping),检测到的无效连接将会被移除。 | 对于业务连接极端敏感的,并且性能可以接受的情况下,可以配置为True,一般来说建议配置为False,启用连接空闲检测。 |
testWhileIdle | 是否在空闲资源监测时通过ping命令监测连接有效性,无效连接将被销毁。 | True |
testOnReturn | 向资源池归还连接时是否做连接有效性检测(ping),检测到无效连接将会被移除。 | False |
maxAttempts | 在JedisCluster模式下,您可以配置maxAttempts参数来定义失败时的重试次数。 | 建议配置3-5之间,默认配置为5。根据业务接口最大超时时间和单次请求的timeout综合配置,最大配置不建议超过10,否则会造成单次请求处理时间过长,接口请求阻塞。 |