【Redis运维】Redis运行变慢的原因与分析思路
一、查看Redis响应延迟
"慢"属于主观感觉,在不同的环境下对慢的定义是不一样的,比如在一个复杂的网络环境中可能延迟为10ms时才判定为慢,但是对于一台硬件配置足够高的服务器,可能延迟2ms就可以认定Redis变慢了。在确定Redis慢之前尽量能有一个基线性能作为参考标准,可以使用redis-cli –intrinsic-latency命令来监测和统计Redis运行时期内最大延迟峰值,这个延迟就可以作为当前环境的基线性能。
/redis-cli --intrinsic-latency 120 # 打印 120 秒内监测到的最大延迟
Max latency so far: 17 microseconds.
Max latency so far: 44 microseconds.
Max latency so far: 94 microseconds.
Max latency so far: 110 microseconds.
Max latency so far: 119 microseconds. #这里最大延迟是 119 微秒,也就是基线性能为 119 微秒,如果当前延迟远大于基线数据就可以判定变慢了
36481658 total runs (avg latency: 3.2893 microseconds / 3289.32 nanoseconds per run).
Worst run took 36x longer than the average latency.
Redis从2.8.13开始支持latency monitor命令用于监控Redis运行过程中的峰值延迟。
config set latency-monitor-threshold 1000 #设置命令执行时长阈值为1000微妙,当命令执行时长超过该阈值就会被监控到
latency latest #查看最新和最大的超过阈值的延迟情况
1) 1) "command"
2) (integer) 1600991500 #命令执行的时间戳
3) (integer) 2500 #最近的超过阈值的延迟
4) (integer) 10100 #最大的超过阈值的延迟
二、是否使用时间复杂度高的命令
生产环境尽量避免执行时间复杂度为O(N)的命令
三、触发过期Key的清理机制
过期key的自动删除机制是Redis回收内存的常用机制,但是该机制本身会引起Redis操作阻塞,导致性能变慢。Redis默认每100毫秒删除一些过期key,这些需要被删除的Key的个数是Redis配置文件ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP选项所指定(默认是20,那么1秒所需要删除的Key就是200个,这个对Redis影响并不大)。除了每100毫秒进行删除外,如果过期Key比例超过25%,就会重复执行删除操作直到比例降至25%以下。由于删除操作是阻塞的,一旦该条件触发就会导致无法正常处理其他键值操作,且慢日志中也不会有相关记录存在(bigkey过期淘汰也会触发该问题)。要触发这种行为通常是有大量的Key同时过期,即使用相同时间参数的EXPIREAT命令,使得同一秒内有大量的key过期,造成缓存雪崩现象。遇到这种情况就要根据实际业务的使用需求,决定EXPIREAT和EXPIRE的过期时间参数。
四、分析Redis慢日志
1、设置Redis慢日志
如果在使用Redis时发现访问延迟突然增大,第一步建议检查Redis慢日志。Redis提供了慢日志命令的统计功能,只需要打开该功能就会记录符合条件的慢日志。需要注意Redis的慢查询的是命令执行时间,而不包括数据网络传输时间和命令排队时间。当客户端被阻塞后,很有可能还处在等待其他命令执行的阶段。
# 命令执行超过1秒记录慢日志
CONFIG SET slowlog-log-slower-than 1000000
# 只保留最近1000条慢日志
CONFIG SET slowlog-max-len 1000
2、查询Redis慢日志
redis > slowlog get #显示当前所有慢命令
redis > slowlog get 100 #查看最新的100个慢命令
3、分析Redis慢日志
1>:该行是日志的唯一标识符
2>:该行记录命令的执行时间点,以 UNIX 时间戳格式表示
3>:该行记录命令执行耗时,以微秒为单位。例子中命令使用54毫秒
4>:该行记录执行的具体命令,以数组的形式排列。图上完整命令是config get *
4、清空Redis慢查询日志
127.0.0.1:6379> slowlog reset
OK
5、解决慢日志带来的问题
如果业务经常使用O(n)以上复杂度的命令,例如sort、sunion、zunionstore,或者在执行O(n)命令时操作的数据量比较大,这些情况下Redis处理数据时就会很耗时。如果服务请求量并不大,但Redis实例的CPU使用率很高,很有可能是使用了复杂度高的命令导致的。解决方案就是不使用这些复杂度较高的命令,并且一次不要获取太多的数据,每次尽量操作少量的数据,让Redis可以及时处理返回。另可以定期检查Redis慢查询日志,以便及时发现和改进 Redis在运行中的不合理操作。
五、持久化数据
Redis配置数据持久化后,虽然是采用子进程的方式生成RDB文件,然后再执行AOF日志重写的方式避免因为磁盘IO而阻塞主线程。但是当Redis记录AOF日志时会根据不同的写回策略对数据做落盘保存,如果有大量的写操作需要记录,势必会有大量的落盘操作,这样就会阻塞主线程。如果的确需要高性能+数据持久化,建议采用高速固态硬盘作为AOF日志的写入设备。
六、SWAP
触发 swap 的原因主要是物理机器内存不足,针对这个问题只有增加机器内存或者使用 Redis 集群。下面是查看Redis是否产生SWAP的方法
$ redis-cli info | grep process_id #获取redis进程号,假设为5332
cd /proc/5332
cat smaps | egrep '^(Swap|Size)' #查看进程使用情况,每一行Size表示Redis所用内存大小,每个服务会产生N个size区域。
Size: 462044 kB
Swap: 462008 kB #Swap表示Size大小的内存区域有多少已经被交换到磁盘,如果两值相等表示内存区域已经完全被换出到磁盘
Size: 21392 kB
Swap: 0 kB
七、内存大页(Transparent Huge Page, THP)
如果采用了内存大页,即使客户端请求只修改 100B 的数据,但是Redis会拷贝默认2M的大页,当客户端请求修改或新写入数据较多时内存大页机制将导致大量的无用拷贝,影响 Redis性能。
cat /sys/kernel/mm/transparent_hugepage/enabled #如果是always表明内存大页机制被启动了;never表示内存大页机制被禁止
echo never > /sys/kernel/mm/transparent_hugepage/enabled
八、NUMA架构下的CPU切换问题
在CPU多核环境下,可以通过绑定Redis实例和CPU核来降低 Redis延迟、提升吞吐率。在进行绑核操作时需要注意,除了主线程,Redis 还有用于 RDB 和 AOF 重写的子进程。当 Redis 实例和一个逻辑核绑定后,这些子进程和后台线程会和主线程竞争 CPU 资源,也会对 Redis 性能造成影响,所以建议将Redis绑定在物理核而不是逻辑核。
taskset -c 0 ./redis-server #将redis绑定在CPU 0上
lscpu #查看CPU核心与对应编号
九、其它导致性能降低的问题
1、网卡负载过高,如对一个Big key进行大量请求或者高并发请求某个Key都可能导致流量异常。比如一个10K的Key被请求了上万次,那么就是接近百M的流量了
2、缓存雪崩:属于"面",Key集中过期导致导致大量并发请求到数据库上,在删除大量Key的时候必然会产生阻塞
3、缓存穿透:客户端请求了一个缓存和数据库中都不存在的数据,如果应用持续大量请求访问数据,就会同时给Redis和数据库带来巨大压力。该问题一般是恶意攻击或者是业务层错误导致。可以考虑对请求的数据在缓存中设置空值来降低后端数据库压力,也可以通过布隆过滤器的快速检测特性或者前端限流来避免
4、缓存击穿:属于"点",主要表现为某个热点数据失效后导致大量并发请求到数据库上。可以通过将热点数据设置永不过期来防止该问题(需和业务确认)
5、命中率低:如果写入了大量Key而命中率又非常低,那么就是代码逻辑存在问题,考虑是否对写入和读取到Redis中的数据进行调整
评论