什么是Redis慢查询?

redis的"慢查询"与redis定义慢查询的时间阈值有关,Redis提供了slowlog-log-slower-thanslowlog-max-len两个配置,slowlog-log-slower-than指当redis命令的执行时间超过该值时,redis会将其记录在redis的慢查询日志中,slowlog-max-len表示记录的条数(超过时会只存储最新的slowlog-max-len条),slowlog-log-slower-than的默认值为10000us,也就是一般来说,redis命令执行时间超过10ms时,我们认为产生了慢查询,redis慢查询日志记录的是执行时间,没有慢查询,并不表示客户端没有超时问题,有可能网络传输有延迟,也有可能排队的命令比较多,导致redis查询也很慢。

产生慢查询有哪些原因?

在业务使用过程中,我们发现redis使用上出现慢查询的原因有主要以下几种:

  • 使用复杂度过高的命令
  • 大key问题
  • 集中过期

如何解决慢查询问题?

针对上述的原因,下面逐个给出导致慢查询的原因细节,并提出对应解决redis慢查询的有效方法。

使用复杂度过高的命令

负责的命令一般指O(N)以上的命令,比如sort、sunion、zunionstore聚合类的命令,或是O(N)类的命令,但是N的值由于业务原因特别大。
对于O(N)以上的命令,redis在操作内存数据时,耗时过高,会耗费更多的cpu资源,导致查询变慢。对于O(N)类的命令,由于N的值特别大Redis 一次需要返回给客户端的数据过多,更多时间花费在数据协议的组装和网络传输过程中。
除此之外,我们都知道,Redis 是单线程处理客户端请求的,如果你经常使用以上命令,那么当 Redis 处理客户端请求时,一旦前面某个命令发生耗时,就会导致后面的请求发生排队,对于客户端来说,响应延迟也会长。

针对此类原因,我们一般有以下两个原则:

  1. 尽量不使用O(N)以上复杂度的命令,某些数据排序或聚合操作,可以放在客户端处理。
  2. 执行O(N)命令时,保证 N 尽量的小(推荐 N <= 300 经验值),每次获取尽量少的数据,让 Redis 可以及时处理返回。

大key问题

所谓大key问题其实并不是值key过大,实则值key对应的value的值过大,此类问题在SET / DEL这类命令中也常出现慢查询。
首先我们要了解下redis写入与删除数据做了什么:

  • 写入数据:为该数据分配内存。
  • 删除数据:释放该数据对应的内存空间。
    很明显,当数据值比较大时,redis分配数据内存或释放空间内存都会比较耗时,针对大key问题,有以下建议:
  1. 尽量避免写入大key(不要写入无关的数据,数据实在过大可以进行拆分,通过多key存储)
  2. 如果你使用的 Redis 是 4.0 以上版本,用 UNLINK 命令替代 DEL,此命令可以把释放 key 内存的操作,放到后台线程中去执行,从而降低对 Redis 的影响
  3. 如果你使用的 Redis 是 6.0 以上版本,可以开启 lazy-free 机制(lazyfree-lazy-user-del = yes),在执行 DEL 命令时,释放内存也会放到后台线程中执行。

顺边提下检测大key的一个命令:

redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 0.01

输出结果会展示每种数据类型所占用的最大内存 / 拥有最多元素的 key 是哪一个,以及每种数据类型在整个实例中的占比和平均大小 / 元素数量。

其实,使用这个命令的原理,就是 Redis 在内部执行了 SCAN 命令,遍历整个实例中所有的 key,然后针对 key 的类型,分别执行 STRLEN、LLEN、HLEN、SCARD、ZCARD 命令,来获取 String 类型的长度、容器类型(List、Hash、Set、ZSet)的元素个数。

这里我需要提醒你的是,当执行这个命令时,要注意 2 个问题:

  1. 对线上实例进行 bigkey 扫描时,Redis 的 OPS 会突增,为了降低扫描过程中对 Redis 的影响,最好控制一下扫描的频率,指定 -i 参数即可,它表示扫描过程中每次扫描后休息的时间间隔,单位是秒
  2. 扫描结果中,对于容器类型(List、Hash、Set、ZSet)的 key,只能扫描出元素最多的 key。但一个 key 的元素多,不一定表示占用内存也多,你还需要根据业务情况,进一步评估内存占用情况

集中过期

集中过期产生的慢查询很容易被忽略,可能我们在业务上线时,并没有发生慢查询,而是业务运行时在某个时间点总是突然发生慢查询。为什么集中过期会导致慢查询呢?我们首先了解下redis的两种过期策略:

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

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

如果此时需要过期删除的是一个 bigkey,那么这个耗时会更久。而且,这个操作延迟的命令并不会记录在慢日志中

因为慢日志中只记录一个命令真正操作内存数据的耗时,而 Redis 主动删除过期 key 的逻辑,是在命令真正执行之前执行的。

对于集中过期问题,有以下建议

  1. 避免集中过期,比如将过期时间随机化,添加一个随机的值,分散集中过期的key的过期时间,降低 Redis 清理过期 key 的压力
  2. 对于Redis 是 4.0 以上版本,可以开启 lazy-free 机制,当删除过期 key 时,把释放内存的操作放到后台线程中执行,避免阻塞主线程

总结

本文介绍了redis慢查询的含义,列举了业务使用种常导致redis慢查询的几个原因以及对应的解决办法,希望大家有所收获。

一文弄懂Redis慢查询相关推荐

  1. 一文弄懂redis分布式缓存之微博推送技术方案

    1️⃣业务场景分析 关注微博 登录首页展示了我关注的所有人发的微博,展示形式是列表 滚动有分页加载 2.个人微博 我发的微博展示在个人微博,展示形式也是列表 滚动有分页加载 2️⃣ 基于redis技术 ...

  2. 一文弄懂元学习 (Meta Learing)(附代码实战)《繁凡的深度学习笔记》第 15 章 元学习详解 (上)万字中文综述

    <繁凡的深度学习笔记>第 15 章 元学习详解 (上)万字中文综述(DL笔记整理系列) 3043331995@qq.com https://fanfansann.blog.csdn.net ...

  3. 程序员,想要彻底弄懂Redis,这15点你一定要明白~(纯干货)

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:Java实现QQ登录和微博登录个人原创+1博客:点击前往,查看更多 作者:耿直的小码农 来源:https://s ...

  4. 面试必问:一文弄懂MySQL数据库索引之底层数据结构和索引类型

    面试必问:一文弄懂MySQL数据库索引之底层数据结构和索引类型 前言 一.索引 1.1作用 1.2特点 1.3使用 1.3.1创建索引 1.3.2删除索引 1.3.3查看表中的索引 1.3.4查看SQ ...

  5. 一文弄懂神经网络中的反向传播法

    最近在看深度学习的东西,一开始看的吴恩达的UFLDL教程,有中文版就直接看了,后来发现有些地方总是不是很明确,又去看英文版,然后又找了些资料看,才发现,中文版的译者在翻译的时候会对省略的公式推导过程进 ...

  6. 一文弄懂各种loss function

    有模型就要定义损失函数(又叫目标函数),没有损失函数,模型就失去了优化的方向.大家往往接触的损失函数比较少,比如回归就是MSE,MAE,分类就是log loss,交叉熵.在各个模型中,目标函数往往都是 ...

  7. 一文弄懂神经网络中的反向传播法——BackPropagation【转】

    本文转载自:https://www.cnblogs.com/charlotte77/p/5629865.html 一文弄懂神经网络中的反向传播法--BackPropagation 最近在看深度学习的东 ...

  8. 一文弄懂String的所有小秘密

    文章目录 简介 String是不可变的 传值还是传引用 substring() 导致的内存泄露 总结 一文弄懂String的所有小秘密 简介 String是java中非常常用的一个对象类型.可以说ja ...

  9. 一文弄懂EnumMap和EnumSet

    文章目录 简介 EnumMap 什么时候使用EnumMap EnumSet 总结 一文弄懂EnumMap和EnumSet 简介 一般来说我们会选择使用HashMap来存储key-value格式的数据, ...

最新文章

  1. aria2下载工具命令行和图形化界面使用
  2. clojure入门: hello world
  3. SDN和SD-WAN有本质区别—Vecloud微云
  4. BZOJ 1085 [SCOI2005]骑士精神 【A*启发式搜索】
  5. 深入信号和槽(Signals and Slots in Depth)
  6. Valid Number
  7. 人工智能在建筑运营_打造智能建筑商
  8. 获取json配置_ASP.NET Core集成Nacos配置中心之适配多格式配置
  9. SQL中的左连接和右连接
  10. 计算机与宽带路由的连接步骤,宽带拨号和设置路由器步骤【图】
  11. SAS硬盘安装Windows 7操作方法
  12. 广度优先遍历搜索的最通俗介绍,如何实现广度优先搜索算法?广度优先遍历搜索可用于哪些行业?
  13. MATLAB实现语音信号的读取
  14. pixhawk编译环境搭建--2018.4.25
  15. 虚幻5新特性之EnhancedInput
  16. oracle数据库建立外键级联删除
  17. 【Linux】Linux进程控制(学习复习兼顾)
  18. JavaScript中this的指向
  19. 第1讲韩顺平 PHP视频教程 zend framework zend介绍 zend快速入门 韩顺平php视频教程ppt 笔记心得
  20. Linux、window服务器下创建共享文件夹(方便于局域网内进行文件共享)

热门文章

  1. 最大似然估计(机器学习)
  2. 【Pyecharts50例】GEO图中忽略不存在的位置
  3. css中float问题,列表中的css float问题
  4. 宇宙最强IDE!微软正式宣布 Visual Studio 2019
  5. linux中write的实例,Linux内核 down_write()
  6. Ubuntu14.04 LTS更新源
  7. GCN学习:Pytorch-Geometric教程(二)
  8. Home Assistant初学者指南 - 5 之 如何在Home Assistant中设置Picture Elements卡 - Lovelace
  9. swiper.js显示指定图片
  10. Mysql数据库使用规范