分析一下在实际使用中,某个时间点或一段时间内导致Redis突然出现访问延迟可能出现的原因。有时间记得更出这些原因的具体排查方法。
可能导致Redis出现延迟的原因分析
1. 使用了复杂度高的命令
通过查看慢日志记录,我们就可以知道Redis在什么时间执行哪些命令比较耗时,
如果你的业务经常使用O(n)以上复杂度的命令,例如sort、sunion、zunionstore,
或者在执行O(n)命令时操作的数据量比较大,这些情况下Redis处理数据时就会很耗时。
最好不使用这些复杂度较高的命令,并且一次不要获取太多的数据,每次尽量操作少量的数据,让Redis可以及时处理返回。
2. 存储了大key
针对大key的问题,Redis官方在4.0版本推出了lazy-free的机制,用于异步释放大key的内存,降低对Redis性能的影响。
即使这样,也不建议使用大key,大key在集群的迁移过程中,也会影响到迁移的性能。
3. 大量的key集中过期
平时在使用Redis时没有延时比较大的情况,但在某个时间点突然出现一波延时,而且报慢的时间点很有规律,
例如某个整点,或者间隔多久就会发生一次。如果出现这种情况,就需要考虑是否存在大量key集中过期的情况。
在集中过期时增加一个随机时间,把这些需要过期的key的时间打散即可。
4. 实例内存达到上限
有时我们把Redis当做纯缓存使用,就会给实例设置一个内存上限maxmemory,然后开启LRU淘汰策略。
当实例的内存达到了maxmemory后,你会发现之后的每次写入新的数据,有可能变慢了。
导致变慢的原因是,当Redis内存达到maxmemory后,每次写入新的数据之前,必须先踢出一部分数据,让内存维持在maxmemory之下。这个踢出旧数据的逻辑也是需要消耗时间的,而具体耗时的长短,要取决于配置的淘汰策略。
5. fork耗时严重
如果Redis开启了自动生成RDB和AOF重写功能,那么有可能在后台生成RDB和AOF重写时导致Redis的访问延迟增大,而等这些任务执行完毕后,延迟情况消失。
生成RDB和AOF都需要父进程fork(分)出一个子进程进行数据的持久化,
在fork执行过程中,父进程需要拷贝内存页表给子进程,
如果整个实例内存占用很大,那么需要拷贝的内存页表会比较耗时, 此过程会消耗大量的CPU资源,
在完成fork之前,整个实例都会被阻塞住,无法处理任何请求, 如果此时CPU资源紧张,那么fork的时间会更长,甚至达到秒级。这会严重影响Redis的性能。 所以使用Redis时建议部署在物理机上,降低fork的影响。
6. 绑定CPU
绑定CPU的Redis,在进行数据持久化时,fork出的子进程,子进程会继承父进程的CPU使用偏好,
而此时子进程会消耗大量的CPU资源进行数据持久化,子进程会与主进程发生CPU争抢,这也会导致主进程的CPU资源不足而访问延迟增大。
所以在部署Redis进程时,如果需要开启RDB和AOF重写机制,一定不能进行CPU绑定操作!
7. 开启了AOF
当执行AOF文件重写时会因为fork执行耗时导致Redis延迟增大,
除了这个之外,如果开启AOF机制,设置的策略不合理,也会导致性能问题。
8. (操作系统)使用了Swap
如果发现Redis突然变得非常慢,每次访问的耗时都达到了几百毫秒甚至秒级,
那此时就检查Redis是否使用到了Swap,这种情况下Redis基本上已经无法提供高性能的服务。
因为操作系统中提供了Swap机制,目的是为了当内存不足时,可以把一部分内存中的数据换到磁盘上,以达到对内存使用的缓冲。
但当内存中的数据被换到磁盘上后,访问这些数据就需要从磁盘中读取,这个速度要比内存慢太多!
9. 网卡负载过高
Redis也稳定运行了很长时间, 但在某个时间点之后开始,访问Redis开始变慢了,而且一直持续到现在,
检查一下机器的网卡流量,是否存在网卡流量被跑满的情况。
网卡负载过高,在网络层和TCP层就会出现数据发送延迟、数据丢包等情况。 Redis的高性能除了内存之外,就在于网络IO,请求量突增会导致网卡负载变高。
后续
提示:之后再更新具体的排查方法和解决办法。