1、Redis变慢原因排查(上)

感觉Redis变慢了,这些可能的原因你查了没 ?(上)

Redis 作为一款业内使用率最高的内存数据库,其拥有非常高的性能,单节点的QPS压测能达到18万以上。但也正因此如此,当应用访问 Redis 时,如果发现响应延迟变大时就会给业务带来非常大的影响。

比如在日常使用Redis时,肯定或多或少都遇到过下面这种问题:
在这里插入图片描述

大部分兄弟面对这种访问变慢问题的排查就会一头雾水,不知道从哪里下手才好,因为不理解 Redis 的架构体系、核心功能的实现原理甚至一些命令的使用限制等。

今天就可能引起Redis变慢的原因一一分析,上篇看完后你将会形成一个比较完整的排查思路方案!
在这里插入图片描述
Redis真的变慢了吗?
当我们遇到服务响应比较慢时,往往需要先排查内部原因,先弄清楚是不是Redis服务导致的,我们大部分系统可能涉及较长的链路和多服务、比如同一个接口会调用Mysql、MQ、Redis等其他三方组件和服务。
在这里插入图片描述

因此需要确定是不是访问Redis服务变慢进而拖慢了整个服务的响应变慢,那就是先自查!🔔

• 应用服务访问Redis的请求,记录下每次请求的响应延时,对比是否响应变长

• 是否其他节点存在同样问题

假设我们确定了是Redis这条链路的问题!(如果不是Redis问题,文章就写不下去啦!!哈哈),这里同样存在两种可能 🤔

• 业务端请求到Redis服务网络是否存在问题,存在网络延迟情况

• Redis服务端本身出现问题,那需要进一步排查
在这里插入图片描述
正常来说网络存在问题的可能性还是比较小的,因为如果存在网络问题,那么其他服务同样都会发生网络延迟情况,如果你想了解网络对 Redis 性能的影响,可以用 iPerf 这样的工具,测量从 Redis 客户端到服务器端的网络延迟,如果这个延迟有几十毫秒甚至是几百毫秒,就说明,Redis 运行的网络环境中很可能有大流量的其他应用程序在运行。

好,现在就剩下确定请求Redis的服务响应耗时变长了,也是文章的要讲的焦点问题,分析Redis变慢的原因,先查看Redis的响应延迟,可以对Redis 进行基准性能测试。

基准测试

基准性能就是指 Redis 在一台负载正常的机器上,其最大的响应延迟和平均响应延迟分别是多少

但是这又不能把别人或者官方的测试结果作为参考的指标,因为在不同的软硬件环境下,它的性能表现差别特别大,不同主频型号的CPU、不同的SSD硬盘,都会极大影响Redis的性能表现。

那该以什么标准来认定Redis变慢呢?

🚩🚩一般来说,如果你观察到的 Redis 运行时延迟是其基线性能的 2 倍及以上,就可以认定 Redis 变慢了

比如:执行以下命令,就可以测试出这个实例 60 秒内的最大响应延迟
在这里插入图片描述
可以看到,此时的基线性能已经达到了 6.022ms,如果响应延时为12ms,那么基本可以认定为Redis变慢了,当然我测试的机器性能比较差,你们可以用自己的机器试试

注意:这个命令只在Redis所在的服务器上运行,避免网络对基线性能的影响,只考虑服务端软硬件环境的影响

到这里已经确定了是Redis服务变慢,那么是哪里变慢了呢,接下来将进行更详细的说明

Redis性能影响要素
分析可能影响因素很重要,是判断Redis性能的来源,如下图:

在这里插入图片描述

在排除了网络因素之后,可以归纳为Redis自身命令操作、文件系统和操作系统三个大因素可能导致Redis性能存在问题。

接下来的文章将围绕这几个要素出发排查和解决性能影响问题

Redis性能问题分析
慢日志分析
在这里插入图片描述

日志是个好东西,分析Mysql是否变慢我们可以通过查看慢日志的,同样的分析Redis慢,同样可以先看是否也存在慢日志 slowlog,这是基础和直观的方式。

Redis 提供的慢日志命令的统计功能,记录了有哪些命令在执行时耗时比较长,快速定位问题。

需要配置的参数:

• slowlog-log-slower-than 配置对执行时间大于多少微秒(microsecond, 1秒=10^6微秒) 的命令进行记录。线上可以设置为1000微秒,也就是1毫秒。

• slowlog-max-len 设置最大考验记录多少条记录。slow log 本身是一个先进先出(FIFO) 队列,当队列大小超过该配置的值时,最旧的一条日志将被删除。线上可以设置为1000以上。

配置如下:

//命令执行耗时超过 10 毫秒,记录慢日志
CONFIG SET slowlog-log-slower-than 10000

//只保留最近 500 条慢日志
CONFIG SET slowlog-max-len 500

我们看下慢日志如何查询

127.0.0.1:6379> SLOWLOG get 3
1) (integer) 32693       # 慢日志ID
2) (integer) 1593763337  # 执行时间戳
3) (integer) 5299        # 执行耗时(微秒)
4) 1) "LRANGE"           # 具体执行的命令和参数
   2) "user_list:2000"
   3) "0"
   4) "-1

注意慢日志功能比较粗糙简单,没有持久化记录能力,都是记录在内存中,没有持久化到文件中,所以一般都是设置保留有限的慢命令条数,如果慢命令比较多,会存在不能全部记录的情况

常见集中导致Redis变慢不合理的命令使用方式:

• 获取Redis中的key时,避免使用keys *

• 高频使用了 O(N) 及以上复杂度的命令,例如:SUNION、SORT、ZUNIONSTORE、ZINTERSTORE 聚合类命令

• O(N) 复杂度的命令,但 N 的值非常大,比如:hgetall、smembers、lrange、zrange等命令

这种情况下我们可以将复杂的聚合放在业务端处理,并且每次尽量少获取大量数据

BigKey问题
在这里插入图片描述
分析慢日志时发现很多请求并不是复杂度高的命令,都是一些del、set、hset等的低复杂度命令,那么就要评估是否写入了大key,也就是BigKey。

Bigkey 是指当 Redis 的字符串类型过大,非字符串类型元素过多 (hash,list,set等存储中value值过多)

bigkey会带来如下问题:
在这里插入图片描述

1.数据请求大量超时:

redis是单线程的,当一个key数据响应的久一点,就会造成后续请求频繁超时。如果服务容灾措施考虑得不够,会引发更大的问题。

2.侵占带宽网络拥堵:

当一个key所占空间过大,多次请求就会占用较大的带宽,直接影响服务的正常运行。

3.内存溢出或处理阻塞:

当一个较大的key存在时,持续新增,key所占内存会越来越大,严重时会导致内存数据溢出;当key过期需要删除时,由于数据量过大,可能发生主库较响应时间过长,主从数据同步异常(删除掉的数据,从库还在使用)。

此时我们可以回想和检查业务代码,查看是否存在写入bigkey的情况,评估好单个key的数据大小,避免存在过大数据。

除了代码自查之外,可以使用命令查,如下:

# redis-cli -h 127.0.0.1 -p 6379 --bigkeys

-------- summary -------

Sampled 15 keys in the keyspace!
Total key length in bytes is 162 (avg len 10.80)
//最大的数据值
Biggest string found 'page4:20230921' has 12304 bytes
Biggest   list found 'article:100' has 8 items
Biggest    set found 'union:65:67' has 7 members
Biggest   hash found 'page2:20230921' has 2 fields
Biggest   zset found 'likeTopList' has 2 members
//平均值
6 strings with 24778 bytes (40.00% of keys, avg size 4129.67)
1 lists with 8 items (06.67% of keys, avg size 8.00)
6 sets with 24 members (40.00% of keys, avg size 4.00)
1 hashs with 2 fields (06.67% of keys, avg size 2.00)
1 zsets with 2 members (06.67% of keys, avg size 2.00)

–i 参数,降低扫描的执行速度,比如 --i 0.1 表示 100 毫秒执行一次,降低扫描过程中对 Redis运行实例的影响。

–bigkeys命令原理解析

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

面对bigkey问题,我们可以这些方面下手去处理:

  1. 对大Key进行拆分

  2. 优化使用删除Key的命令,可使用异步删除 unlink 命令删除缓存

  3. 尽量不写入大Key

  4. 合理使用批处理命令

key集中过期
不知道大家是否遇到过,在某个时间点Redis突然出现一波延时,而且报慢的,有时候超时还有时间规律

如果出现这种情况,就需要考虑是否存在大量key集中过期的情况,因为大量的key在某个固定时间点集中过期,在这个时间点访问Redis时,就有可能导致延迟增加。
在这里插入图片描述

如果出现了这种情况,那么需要从两个方面排查一下:

• 业务逻辑是否有定时任务的脚本程序,定期操作key

• Redis的Key数量出现集中过期清理

程序层面这个我们自己排查就好了,这里主要看下为什么Key数量集中过期,集中过期为啥造成了Redis访问变慢

Redis的Key过期策略是怎样的?

被动过期:只有应用发起访问某个key 时,才判断这个key是否已过期,如果已过期,则从Redis中删除

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

注意,这个主动过期 key 的定时任务,是在 Redis 主线程中执行的

这也是我们主要关注的问题 【主动过期清理】,那为什么会导致Redis延时呢?

因为主动过期是在Redis 主线程中执行的,也就意味着会阻塞正常的请求命令。

进一步说就是如果在执行主动过期的过程中,出现了需要大量删除过期 key 的请求,那么此时应用程序在访问 Redis 时,必须要等待这个过期任务执行结束,Redis 才可以继续处理新请求,这也就是为什么此时访问Redis会突然出现延迟。

即使删除过期key是耗时的,也不会记录在slowlog慢日志中哦!

这里大家估计又有疑惑了,这不是慢了吗?

别急,这是因为slowlog记录的是Redis服务端在命令执行前后计算每条命令的执行时长,而过期清理的时候Redis是登录状态,还不能处理客户端发过来的请求,也就是在命令执行之前进行的。

这种情况我们可以这样处理:

• 业务Key设置过期时间时,加上一个随机过期时间段,比如1分钟

• 通过执行info命令获取过期Key数量【expired_keys】的统计值

• Redis 4.0以上版本,开启 lazy-free 机制,把释放内存的操作放到后台线程中执行,避免阻塞主线程

预估内存不足
我们知道服务器的内存是有限的,这个是既定事实,而且使用Redis时都会配置当前实例可用的最大内存maxmemory和数据自动淘汰策略

maxmemory : 默认为0 不限制。

//获取maxmemory配置的大小
127.0.0.1:6379> config get maxmemory
1) "maxmemory"
2) "0"     //默认值是0

//可以在redis.conf中配置
maxmemory 1024mb
当使用的内存达到了 maxmemory 后,即使配置了自动淘汰策略,仍然会在之后每次写入新数据时,操作延迟都会变长。

原因在于,当 Redis 内存达到 maxmemory 后,每次写入新的数据之前,Redis 必须先从实例中踢出一部分数据,让整个实例的内存维持在 maxmemory 之下,然后才能把新数据写进来。
在这里插入图片描述

Redis的常用 allkeys-lru / volatile-lru 的淘汰策略

volatile-lru :利用LRU算法移除设置过过期时间的key

allkeys-lru :利用LRU算法移除任何key (和上一个相比,删除的key包括设置过期时间和不设置过期时间的)

Redis采用近似LRU算法,实现逻辑是什么样的?

1:每次从实例中随机选择一个key (样本集),并从样本集中挑选最长时间未使用的 key 淘汰,剩下的放入待淘汰池

2:再次随机获取一批样本集,并与第一步池子的key比较,进而进行淘汰最少访问的key,剩下的放入待淘汰池

3:循环往复上面两个操作步骤,直到实例内存降到maxmemory值为止

假如我们淘汰策略删除的是 bigkey,那么耗时还更久,可想而知 bigkey对Redis的危害应该很大

不过针对内存不足问题,我们也可以进行一个优化措施:

1:避免存储 bigkey,降低释放内存的耗时

2:合理预估内存占用,避免达到内存的使用上限

• 根据写入Key的类型、数量及平均大小计算预估

• 写入一小部分比例的真实业务数据,然后进行预估

3:Redis 4.0 及以上版本,开启 layz-free 机制,把淘汰 key 释放内存的操作放到后台线程中执行

实际请求量超预期
一个系统处理请求是有上限的。Redis虽然处理速度很快,但是也有上限。因此在流量暴增的时候,会比较快达到Redis的处理瓶颈,这个时候整个系统也会变慢,出现slowlog等。

这个现象也比较好观察,可以看看实例的cpu情况,如果持续100%,基本可以判定达到处理上限了。

这种情况最好我们要结合云监控,对CPU使用率、访问的QPS进行监控,发现系统瓶颈,看是否进行扩容和调整。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/241140.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【计算机设计大赛】冬残奥会可视化系统_附源码—信息可视化赛道获奖项目深入剖析【可视化项目案例-19】

🎉🎊🎉 你的技术旅程将在这里启航! 记得看本专栏里顶置的可视化宝典导航贴哦! 🚀🚀 本专栏为可视化专栏,包含现有的所有可视化技术。订阅专栏用户在文章底部可下载对应案例完整源码以供大家深入的学习研究。 🎓 每一个案例都会提供完整代码和详细的讲解,不论你…

数字基础设施及相关产业链报告:数据要素加快推进、AI终端应用加速发展

今天分享的AI系列深度研究报告:《数字基础设施及相关产业链报告:数据要素加快推进、AI终端应用加速发展》。 (报告出品方:长城证券) 报告共计:16页 1. 行业观点 在 TMT 各子板块:电子、通信、…

环境安全之配置管理及配置安全设置指导

一、前言 IT运维过程中,配置的变更和管理是一件非常重要且必要的事,除了一般宏观层面的配置管理,还有应用配置参数的配置优化,本文手机整理常用应用组件配置项配置,尤其安全层面,以提供安全加固指导实践。…

汉诺塔(函数递归)

前言 汉诺塔问题是一个经典的数学谜题,也是函数递归的一个经典问题,起源于印度。问题的设定是有三个柱子,第一个柱子上有一组不同大小的圆盘,按照从上到下依次变大的顺序摆放。目标是将所有的圆盘从第一个柱子移动到第三个柱子上&…

基于Java SSM框架实现东理咨询交流论坛系统项目【项目源码+论文说明】

基于java的SSM框架实现东理咨询交流论坛系统演示 摘要 在网络高速发展的时代,众多的软件被开发出来,给用户带来了很大的选择余地,而且人们越来越追求更个性的需求。在这种时代背景下,人们对东理咨询交流论坛越来越重视&#xff0…

Odoo:行业领先的免费开源供应链管理系统

先进且开源的供应链管理系统和全球供应链协作优化方案 为满足复杂的供应链和库存管理要求,如今绝大多数企业都不得不部署多个供应链管理软件和库存管理系统软件。如何利用一个库存管理与供应链管理软件,跨地区、跨时区地管理现代供应链?Odoo…

Java网络编程-深入理解BIO、NIO

深入理解BIO与NIO BIO BIO 为 Blocked-IO(阻塞 IO),在 JDK1.4 之前建立网络连接时,只能使用 BIO 使用 BIO 时,服务端会对客户端的每个请求都建立一个线程进行处理,客户端向服务端发送请求后,…

免费!简单优雅的手机视频制作PR模板抖音素材下载

这是一款多功能的Premiere Pro模板,无论你是为视频、宣传内容还是社交媒体帖子短视频,这个pr模板都会为你的项目增添一丝优雅和专业。适用于广播,俱乐部,音乐会,舞蹈,设计,宣传片,动…

什么是前端国际化(internationalization)和本地化(localization)?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

基于QTreeWidget实现带Checkbox的多级组织结构选择树

基于QTreeWidget实现带Checkbox的多级组织结构选择树 采用基于QWidgetMingw实现的原生的组织结构树 通过QTreeWidget控件实现的带Checkbox多级组织结构树。 Qt相关系列文章: 一、Qt实现的聊天画面消息气泡 二、基于QTreeWidget实现多级组织结构 三、基于QTreeWidget…

“新华三杯”第十届成都信息工程大学ACM程序设计竞赛(同步赛)L. 怎么走啊(最短路+二分 分段函数)

题目 登录—专业IT笔试面试备考平台_牛客网 思路来源 衡阳师范学院ac代码、pj学弟 题解 大致可以证明,在w从1e5减小到1的过程中, 之前某条反向边没有用到,现在需要用到反向边,也就是正向边用到的变少了 这样的变化有sqrt个&a…

【Django中间价】项目中常用中间件

原文作者:我辈李想 版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。 文章目录 前言一、常见用法二、JWT中间价三、操作日志中间件1.在user的app下建立models类2.如图位置新建LogMiddleware.py3.django中添加中间件 四、全…

Pandas缺失数据处理

好多数据集都含缺失数据,缺失数据有多重表现形式 数据库中,缺失数据表示为NULL 在某些编程语言中用NA表示 缺失值也可能是空字符串(’’)或数值 在Pandas中使用NaN表示缺失值; NaN简介 Pandas中的NaN值来自NumPy库&a…

IPQ6010 vs IPQ8072 What’s the difference?|802.11AX WiFi6 Solution DR6018 DR8072

IPQ6010 vs IPQ8072 What’s the difference?|802.11AX WiFi6 Solution DR6018 DR8072 IPQ6010 vs IPQ8072: In-Depth Comparison and Selection Guide The rapid evolution of networking technologies has driven continuous innovation in routers and network devices. Am…

msvcp80.dll文件丢失怎么恢复?详解多种DLL文件修复方法

本文将为您详细介绍msvcp80.dll的定义、作用以及丢失的原因,并提供5个解决方法,帮助您解决这一问题。 一、msvcp80.dll是什么? msvcp80.dll是Microsoft Visual C Runtime Library中的一个动态链接库文件,它包含了许多C运行库函数…

SIM卡内部结构及外部物理接口

1. 内部组成 “SIM卡”是一个装有微处理器的芯片卡,它的内部有5个模块:1.微处理器CPU:控制SIM卡的运算和操作2.程序存储器ROM:存放片内操作系统,用户不可操作。3.工作存储器RAM:存放计算过程中的临时数据4…

Video anomaly detection with spatio-temporal dissociation 论文阅读

Video anomaly detection with spatio-temporal dissociation 摘要1.介绍2.相关工作3. Methods3.1. Overview3.2. Spatial autoencoder3.3. Motion autoencoder3.4. Variance attention module3.5. Clustering3.6. The training objective function 4. Experiments5. Conclusio…

基于Dockerfile创建镜像

Docker镜像的创建 1.基于现有镜像创建 //首先启动一个镜像,在容器里做修改 docker run -itd --name web centos:7 /bin/bash #启动容器docker exec -it web bash #进入容器​ yum install -y epel-release #安装epel源 yum install -y nginx #安装nginx …

共享门店会在未来新零售占据主角吗?

共享门店作为一种创新的商业模式,在未来新零售领域中可能会占据一定的角色,但具体是否会成为主角,还需要根据市场的发展和技术的进步来判断。 首先,共享门店模式通过资源共享、风险共担、客户共享和收益共享等方式,为…

Python 递归及目录遍历

递归调用:一个函数,调用了自身,称为递归调用 递归函数:一个会调用自身的函数 凡是循环能做的事,递归都能做。 目录 递归示例 普通方法实现 递归方式实现 计算分析: 递归遍历目录 引入os 遍历目录 执…