Menina Home

避免Redis(Codis)的Timeout及监控

/ 缓存监控 / 没有评论 / 1630浏览
Redis(Codis)的常见Timeout有两种,一种是Connect Timeout,一种是Read Timeout。

之前从原理上解释过两种Timeout产生的原因。

Connect Timeout是因为Redis(Codis) accept新连接的速度低于新的EST连接加入Socket的Accpet Queue的速度,导致Accept Queue满服务器Reset或者直接Drop掉新的EST连接。

Read Timeout是因为客户端请求Socket设置Timeout,在Timeout时间内响应没有返回。

但以上Timeout还有一个容易被忽略的原因:

网络

包括:

1.网络质量
2.网卡打满

一.避免Connect Timeout

1.避免短连接,不要高频率创建连接,请使用连接池。

2.连接池参数保持maxActive和maxIdle一致。

不同连接池有不同的创建释放策略,具体参数连接池创建释放实现,但commons-pool2里,是先判断macActive优先满足创建连接再判断maxIdel是否关闭当前连接。

可以通过后端连接创建关闭日志的速率判断是否存在大量短连接。

3.以上条件都满足, 仍存在Connect Timeout,查看CPU负载是否正常

CPU负载过高会影响redis的处理性能。

4.以上条件都满足,仍存在Connect Timeout,查看网卡是否被打满。

先确认redis所在机器是物理机还是虚拟机,判断得出的流量是否需要汇总,使用iftop之类的工具获取机器的入口流量,判断是否流速已将网卡打满,如果网卡被打满,一定有请求被丢弃,也一定有Timeout ,接下来考虑升级/添加网卡,或者分流。

二.避免Redis Timeout

redis(codis)出现的read timeout,是因为在socket设置的Timeout时间内,请求没有得到响应。

redis客户端的一次请求到响应包括:

1.网络转发,可能的nginx代理,机器网卡
2.请求排队
3.请求处理,包括命令的复杂度,value的大小
4.请求返回

a.排除复杂操作引起的慢查询

a.查看Slowlog,排除慢查询导致雪崩
b.使用--bigkeys找到大key
c.使用redis-rdb-tools分析key值的大小

请求处理的耗时可以通过redis的slowLog拿到最耗时的操作,可以作为出现read timeout时的第一个排查方向。

我们从slowlog里看到的命令处理耗时,是命令的CPU消耗时间,正常的命令处理应该在微秒之别,当一个命令的CPU消耗时间达到毫秒级别,那么Redis的吞吐就只有1-1000/s,再加上网络耗时,整个redis的服务能力就只能达到每秒几百的QPS。

由于Redis是单线程操作,那么一定会导致后续的命令排队,并引起雪崩效应,导致后续请求频繁超时,比如一个简单的GET操作超时,如果GET操作的是一个小key,那么往往是因为之前的请求中存在慢查询的key导致此次请求排队直到超时。

除了命令的复杂度,比如setnx,hset,zadd,keys之类,导致慢查询的另一个原因是操作的Value的大小,对于一个key里放入上MB数据的操作,这样的指令在请求频繁时往往导致所有应用大批量的报出read timeout。

alt

取自官网How fast is Redis?,处于千兆网卡下,当请求数据包超过单个MTU,redis的请求耗时将大幅大于增加。

可以使用redis-benchmark做测试:

内网,-c 1000 -n 10 -d 10000

====== SET ======
10.00% <= 406 milliseconds
20.00% <= 528 milliseconds

====== GET ======
10.00% <= 16 milliseconds
30.00% <= 17 milliseconds

内网,-c 1000 -n 10 -d 1000

====== SET ======
10.00% <= 150 milliseconds
30.00% <= 151 milliseconds

====== GET ======
10.00% <= 29 milliseconds
100.00% <= 30 milliseconds

内网,-c 1000 -n 10 -d 256

====== SET ======
10.00% <= 84 milliseconds
100.00% <= 84 milliseconds

====== GET ======
10.00% <= 13 milliseconds
30.00% <= 15 milliseconds

b.使用--latency获取当前请求延迟

如果慢查询日志中没有得到有效的信息,那么使用--latency获取当前服务的请求平均延时,如果延时较高,超过平均100ms,那么考虑是网络出现问题,在redis所在服务端和应用所在客户端分别执行一次--latency可以确认是否是网络原因造成的问题,可以简单通过ping判断客户机和服务机是否存在丢包判断网络质量。

c.使用iftop等工具查看网卡是否被打满

如果网络质量理想,那么使用流量工具比如iftop判断服务器的网卡是否已被打满,如果是虚拟机部署的redis或者codis proxy,那么需要查看物理机的入口流量是否达到了网卡的容量,最后往往都是网卡被打满导致的Timeout。

所以为了避免Read Timeout,需要保证以下两点:

1.避免key的value值过大,为达到最好的性能,不要每个value体积不要超过一个MTU。

如果需要向一个key里放一个几百KB或者上MB的数据,线上是会时不时来点Read Timeout来骚扰你,高QPS下会放大影响。

2.对机器流量做监控,出入流量达到网卡上限要预警,避免应用出现超时逐步排查耗费时间,该分流的应用要分流,高流量的虚拟机不要架在同一台物理机上。

三.监控

最好的手段是监控,在线上出现问题前提前预警,可以快速解决问题,可以不用等到问题发生再去排查回溯问题再解决问题。

用Grafana+Telegraf+InfluxDB一套可以满足你的需求,并且也很好搭建

通过telegraf自带的监控指标,你可以监控redis(Telelgraf原生支持redis)或者Codis(Codis原生支持向InfluxDB写入关键指标),包括QPS,连接数,Latency,还可以一同监控redis,codis所在机器的流量,CPU等一系列信息。

如果你手上已经压测出了关键的指标,那么你就可以以此指标的80%作为预警线了,redis/codis的服务能力也就提升了。

Update 2019-1-5

四.流量倾斜和性能损耗

1.流量倾斜

针对分片处理的Redis集群,具体到Codis和Redis Cluster,通过监控,可以看到多个Proxy或者Redis Server节点流量存在差异,部分节点流量可以几倍于其他节点的流量.

影响:高流量节点带宽打满,创建连接导致Connect Timeout,长连接导致Read Timeout.

原因:Key粒度设计过大,粒度定义包括Key大小,Key操作频率,常见于存放大体积集合,此集合为热点数据.

解决方案:分流,业务层面,降低Key粒度,大体积,热点Key拆分,crc32(key) % 1024 分片到不同Slot->Group->Server.

2.性能损耗

1.固有延迟
2.Key集体超时
3.内存碎片

固有延迟:虚拟化环境下,主机过载,同主机上存在高CPU需求的虚拟机,导致Redis所在节点CPU Ready,性能下降,此情况下单一操作达到毫秒级别,客户端出现Read Timeout,且无慢查询记录,请求大部分时间被排队,常规监控往往无异常。

Key集体超时:大量Key设置同一时间超时.

这两个问题都是之前线上实际发生的,且对性能有较大损耗。

Redis latency problems troubleshooting