Redis慢查询分析优化

文章目录


一、定义

在Redis执行时耗时超过某个阈值的命令,称为慢查询。

慢查询日志帮助开发和运维人员定位系统存在的慢操作。慢查询日志就是系统在命令执行前后计算每条命令的执行时间,当超过预设阀值,就将这条命令的相关信息(慢查询ID,发生时间戳,耗时,命令的详细信息)记录下来。


二、慢查询参数配置

1、通过配置指定慢查询的阈值

slowlog-log-slower-than:慢查询阈值,单位是微秒。默认是10000,建议1000

2、慢查询会被放入慢查询日志中,日志的长度有上限,可以通过配置指定

slowlog-max-len:慢查询日志(本质是一个队列)的长度。默认是128,建议1000


三、慢查询日志

查看慢查询日志列表

  • slowlog len:查询慢查询日志长度
  • slowlog get[n]:读取n条慢查询日志
  • slowlog reset:清空慢查询列表

四、排查步骤

查看slowlog(慢日志)

Redis 提供了慢日志命令的统计功能,它记录了有哪些命令在执行时耗时比较久。

查看 Redis 慢日志之前,你需要设置慢日志的阈值。例如,设置慢日志的阈值为 5 毫秒,并且保留最近 500 条慢日志记录:

bash 复制代码
# 命令执行耗时超过 5 毫秒,记录慢日志
CONFIG SET slowlog-log-slower-than 5000
# 只保留最近 500 条慢日志
CONFIG SET slowlog-max-len 500

设置完成之后,所有执行的命令如果操作耗时超过了 5 毫秒,都会被 Redis 记录下来。

此时,你可以执行以下命令,就可以查询到最近记录的慢日志:

bash 复制代码
127.0.0.1:6379> SLOWLOG get 5
1) 1) (integer) 32693       # 慢日志ID
   2) (integer) 1593763337  # 执行时间戳
   3) (integer) 5299        # 执行耗时(微秒)
   4) 1) "LRANGE"           # 具体执行的命令和参数
      2) "user_list:2000"
      3) "0"
      4) "-1"
2) 1) (integer) 32692
   2) (integer) 1593763337
   3) (integer) 5044
   4) 1) "GET"
      2) "user_info:1000"

通过查看慢日志,我们就可以知道在什么时间点,执行了哪些命令比较耗时。


五、Redis变慢原因

原因1:使用复杂度过高的命令

排查思路:

查看慢日志,看是否有复杂度过高的命令。

导致变慢的操作:

  • 经常使用 O(N) 以上复杂度的命令,例如 SORT、SUNION、ZUNIONSTORE 聚合类命令

   原因:Redis 在操作内存数据时,时间复杂度过高,要花费更多的 CPU 资源
  • 使用 O(N) 复杂度的命令,但 N 的值非常大

    原因:Redis 一次需要返回给客户端的数据过多,更多时间花费在数据协议的组装和网络传输过程中

除此之外,Redis 是单线程处理客户端请求的,如果你经常使用以上命令,那么当 Redis 处理客户端请求时,一旦前面某个命令发生耗时,就会导致后面的请求发生排队,对于客户端来说,响应延迟也会变长。
解决方案

  • 尽量不使用 O(N) 以上复杂度过高的命令,对于数据的聚合操作,放在客户端做
  • 执行 O(N) 命令,保证 N 尽量的小(推荐 N <= 300),每次获取尽量少的数据,让 Redis 可以及时处理返回

原因2:操作bigkey(value很大)

排查思路

若你查询慢日志发现,并不是复杂度过高的命令导致的,而都是 SET / DEL 这种简单命令出现在慢日志中,那么你就要怀疑你的实例否写入了 bigkey。

导致变慢的操作

Redis 在写入数据时,需要为新的数据分配内存,相对应的,当从 Redis 中删除数据时,它会释放对应的内存空间。如果一个 key 写入的 value 非常大,那么 Redis 在分配内存时就会比较耗时。同样的,当删除这个 key 时,释放内存也会比较耗时,这种类型的 key 我们一般称之为 bigkey。此时,需要检查业务代码是否存在写入 bigkey 的情况。你需要评估写入一个 key 的数据大小,尽量避免一个 key 存入过大的数据。

针对 bigkey 导致延迟的解决方案

  1. 业务应用尽量避免写入 bigkey
  2. 将释放key的操作放到后台线程执行
   Redis4.0 以上版本:用 UNLINK 命令替代 DEL,此命令可以把释放 key 内存的操作,放到后台线程中去执行,从而降低对 Redis 的影响
    Redis6.0 以上版本:可以开启 lazy-free 机制(lazyfree-lazy-user-del = yes),在执行 DEL 命令时,释放内存也会放到后台线程中执行

在此不建议在实例中存入 bigkey。这是因为 bigkey 在很多场景下,依旧会产生性能问题。例如,bigkey 在分片集群模式下,对于数据的迁移也会有性能影响,以及我后面即将讲到的数据过期、数据淘汰、透明大页,都会受到 bigkey 的影响。

原因3:集中过期

排查思路

如果你发现,平时在操作 Redis 时,并没有延迟很大的情况发生,但在某个时间点突然出现一波延时,其现象表现为:变慢的时间点很有规律,例如某个整点,或者每间隔多久就会发生一波延迟。

如果是出现这种情况,那么你需要排查一下,业务代码中是否存在设置大量 key 集中过期的情况。

导致变慢的原因

如果有大量的 key 在某个固定时间点集中过期,在这个时间点访问 Redis 时,就有可能导致延时变大。

为什么集中过期会导致 Redis 延迟变大?这就需要我们了解 Redis 的过期策略是怎样的。

Redis 的过期数据采用被动过期 + 主动过期两种策略:

  • 被动过期:只有当访问某个 key 时,才判断这个 key 是否已过期,如果已过期,则从实例中删除
  • 主动过期:Redis 内部维护了一个定时任务,默认每隔 100 毫秒(1秒10次)就会从全局的过期哈希表中随机取出 20 个 key,然后删除其中过期的 key,如果过期 key 的比例超过了 25%,则继续重复此过程,直到过期 key 的比例下降到 25% 以下,或者这次任务的执行耗时超过了 25 毫秒,才会退出循环。

注意,这个主动过期 key 的定时任务,是在 Redis 主线程中执行的。也就是说如果在执行主动过期的过程中,出现了需要大量删除过期 key 的情况,那么此时应用程序在访问 Redis 时,必须要等待这个过期任务执行结束,Redis 才可以服务这个客户端请求。此时就会出现,应用访问 Redis 延时变大。

如果此时需要过期删除的是一个 bigkey,那么这个耗时会更久。而且,这个操作延迟的命令并不会记录在慢日志中。因为慢日志中只记录一个命令真正操作内存数据的耗时,而 Redis 主动删除过期 key 的逻辑,是在命令真正执行之前执行的。所以,此时你会看到,慢日志中没有操作耗时的命令,但我们的应用程序却感知到了延迟变大,其实时间都花费在了删除过期 key 上,这种情况我们需要尤为注意。

解决方案

如果你使用的 Redis 是 4.0 以上版本,可以开启 lazy-free 机制

这样当删除过期 key 时,把释放内存的操作放到后台线程中执行,避免阻塞主线程

集中过期 key 增加一个随机过期时间,把集中过期的时间打散,降低 Redis 清理过期 key 的压力

  • 第1种方案
    Redis 4.0 以上版本,开启 lazy-free 机制:
bash 复制代码
# 释放过期 key 的内存,放到后台线程执行
lazyfree-lazy-expire yes
  • 第2种方案
    在设置 key 的过期时间时,增加一个随机时间,伪代码可以这么写:
bash 复制代码
# 在过期时间点之后的 5 分钟内随机过期掉
redis.expireat(key, expire_time + random(300))Copy

这样一来,Redis 在处理过期时,不会因为集中删除过多的 key 导致压力过大,从而避免阻塞主线程。

文章如有不足之处,欢迎大家在评论区指出进行讨论,大家一起进步!

相关推荐
麦香--老农31 分钟前
windows 钉钉缓存路径不能修改 默认C盘解决方案
缓存·钉钉
m0_7482448339 分钟前
StarRocks 排查单副本表
大数据·数据库·python
C++忠实粉丝1 小时前
Redis 介绍和安装
数据库·redis·缓存
wmd131643067121 小时前
将微信配置信息存到数据库并进行调用
数据库·微信
丰云1 小时前
一个简单封装的的nodejs缓存对象
缓存·node.js
Oneforlove_twoforjob1 小时前
【Java基础面试题025】什么是Java的Integer缓存池?
java·开发语言·缓存
泰伦闲鱼1 小时前
nestjs:GET REQUEST 缓存问题
服务器·前端·缓存·node.js·nestjs
是阿建吖!1 小时前
【Linux】基础IO(磁盘文件)
linux·服务器·数据库
凡人的AI工具箱1 小时前
每天40分玩转Django:Django国际化
数据库·人工智能·后端·python·django·sqlite
ClouGence2 小时前
Redis 到 Redis 数据迁移同步
数据库·redis·缓存