Redis性能大挑战:深入剖析缓存抖动现象及有效应对的战术指南

        在实际应用中,你是否遇到过这样的情况,本来Redis运行的好好的,响应也挺正常,但突然就变慢了,响应时间增加了,这不仅会影响用户体验,还会牵连其他系统。

        那如何排查Redis变慢的情况呢?首先有个问题需要确定,就是确定Redis是否真的变慢了。

Redis基线性能

        要判断Redis是否变慢了,一个最直接的方法就是查看Redis的响应时间。

        大部分情况下,Redis的延迟很低,但是在某些情况下,Redis会出现很高的延迟,可能会达到几秒甚至更长,不过持续的时间又不长,这到底是怎么情况呢?如果出现了响应延迟到秒级别就可以确定Redis变慢了。

        首先需要先确定Redis的延迟绝对值,但是在不同运行环境下,Redis的绝对性能是不同的。所以就需要当前环境的基线性能,所谓基线性能,就是一个系统在低压力、无干扰下的基本性能,这个性能只由当前软硬件环境配置决定。

        基线性能可以通过Redis提供的命令来确定,具体为在redis-cli中添加--intrinsic-latency选项,可以用来检测和统计Redis在运行期间内的最大延迟,这就可以作为基线性能。

redis-cli -h localhost --intrinsic-latency 120
Max latency so far: 1 microseconds.
Max latency so far: 29 microseconds.
Max latency so far: 31 microseconds.
Max latency so far: 34 microseconds.
Max latency so far: 53 microseconds.
Max latency so far: 68 microseconds.
Max latency so far: 103 microseconds.
Max latency so far: 106 microseconds.
Max latency so far: 142 microseconds.
Max latency so far: 158 microseconds.
Max latency so far: 164 microseconds.
Max latency so far: 273 microseconds.
Max latency so far: 296 microseconds.
Max latency so far: 673 microseconds.
Max latency so far: 946 microseconds.
Max latency so far: 2138 microseconds.
Max latency so far: 2234 microseconds.
Max latency so far: 16164 microseconds.2383205581 total runs (avg latency: 0.0504 microseconds / 50.35 nanoseconds per run).
Worst run took 321018x longer than the average latency.

        在自己的电脑上运行命令后,会打印120秒内检测到的最大延迟,可以看到这里的最大延迟为16164微妙,16ms左右。一般情况下,检测120s的时长已经够了。

        一般来说,运行时响应时间和基线性能做对比,如果响应时间达到了基线性能的2倍以上,就可以认定Redis变慢了。

Redis变慢的原因

        一旦发现变慢了,接下来就要查找原因解决这个问题了。这个过程要基于Redis本身的工作原理,并结合和它交互的操作系统、存储以及网络等外部系统的关键机制,在借助一些辅助工具来定位问题,并指定行之有效的解决方案。

        Redis变慢的原因有几下几点,如图所示:Redis变慢的原因

        慢查询指令

        慢查询命令,指在Redis中执行速度慢的命令,这会导致Redis延迟增加。Redis提供的命令操作很多,并不是所有命令都慢,这和命令操作的复杂度有关,所以我们必须知道不同命令的复杂度。

        比如,操作的value为String类型时,由于操作的事hash表,这个操作的复杂度是固定的,都是O(1),除非出现了hash碰撞严重。但操作的数据类型为集合时,如果集合中包含大量的元素,那这个操作复杂度是比较高的,会比较耗时。

        Redis官网提供了各个命令的复杂度:Commands | Redisicon-default.png?t=N7T8https://redis.io/commands/        如果有复杂的操作,就要考虑是否需要用简单的命令来替换。如果使用keys命令,查询大量的key,也会导致慢查询,因为需要扫描所有的键值对,所以生产环境要禁用这样的命令。

        删除key操作

        如果Redis中key过期了是会被自动删除的,这也是Redis的回收机制,Redis 的 key可以设置过期时间,默认情况下,每100ms就会扫描一次,删除过期的key,具体如下:

  • 采样ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP个数的key,并将其中过期的key全部删除;
  • 如果超过25%的key过期了,则重复删除过程,直到过期key的比例降至25%以下。

        如果触发了第二条规则,Redis就会一直删除以释放内存空间。注意,删除操作是阻塞的(Redis 4.0提供了异步机制减少阻塞)。所以一旦触发了就会一直删除key,这样一来,就没办法给客户端提供服务了。

        磁盘I/O:AOF

        为了保证数据的可靠性,Redis提供了AOF和RDB两种机制(想具体了解请查看:Redis持久化(AOF、RDB)用到的写时复制到底是什么-CSDN博客)。其中AOF提供了三种写回策略:always、everysec、no,这三种写回策略依赖文件系统来完成,也就是write和fsync。

        write把日志写到内核的缓冲区,就可以返回了,并不需要等待日志实际写回磁盘;而fsync需要把日志记录写回到磁盘才能返回,时间较长。

        当写回策略配置为everysec和always时,Redis需要调用fsync把日志写回磁盘。但是这两种写回策略的具体情况不一样。但不管怎么说,都会涉及到写回磁盘,而且fsync通常比较耗时,如果Redis主线程执行写回,就会造成阻塞。

        另外AOF日志重写时,也容易阻塞主线程,所以Redis使用了子线程来完成该操作。但是AOF重写会对磁盘又大量的IO操作,同时fsync又需要等到数据写到磁盘才能返回,所以,当AOF重写的压力比较大时,就会导致fsync阻塞,虽然fsync由后台子线程完成,但是主线程会监测fsync的执行进度。

        当主线程使用子线程执行了一次fsync,需要再次把接收的数据写回磁盘,如果主线程发现上一次的fsync还没有执行完,那么它就会阻塞。所以,如果后台线程执行fsync频繁阻塞的话,主线程也会阻塞,导致Redis性能变慢。

        内存大页

        内存大页机制也会影响Redis性能。Linux内核从2.6.38开始支持内存大页,支持2MB大小的内存页分配,而常规的也大小是4KB。你可能会说,Redis是内存数据库,内存大页对Redis不是有好处的吗,减少了内存的分配,但是任何事都有两面性,这时一个权衡的过程。

        Redis为了提高可靠性,提供了持久化的机制。这个过程需要额外的线程来执行,所以不会阻塞主线程为客户端提供服务。如果在持久化的过程中,客户端修改了数据,Redis会才用写时复制(Copy On Write)机制,数据一旦修改了不会直接修改内存中的数据,而是复制一份,然后再进行修改。

        如果采用了内存大页,那Redis就需要拷贝该大页。如果关闭了内存大页,那需要拷贝的页数据只有4kb,可见内存大页会复制大量数据。

        所以正常情况下,关闭内存大页就可以了。

        swap操作

        操作系统swap是将内存数据在内存和磁盘来回换入核换出的机制,涉及到磁盘的读写。所以一旦涉及到了swap,其性能都会收到磁盘性能的影响。

        Redis是内存数据库,内存使用量大,如果用Redis保存海量数据,而且没有控制好内存使用量,就可能会触发swap机制,从而影响性能。一旦触发swap机制,Redis需要操作磁盘才能完成,这回极大的降低Redis的性能。

        关于海量数据的处理请参考:面对海量数据Redis如何应对-CSDN博客

        Redis对于swap的排查有现成的命令,具体这里不做详细介绍了。

        内存碎片

        内存碎片很好理解,明明有内存空间,但是申请时就是无法分配需要的内存空间,这对于使用内存的Redis来说无疑影响巨大。

        内存碎片的原因

  1. 内存不是按需分配的,操作系统为了减少内存的分配次数,每次都是按照固定大小进行内存分配的,例如8字节、16字节、32字节等,比如申请了20字节的内存,但是实际上会分配32字节,此时如果在写入5字节数据,就不用再申请内存了,减少了内存申请的次数。
  2. Redis键值对大小不一和删除操作的影响,内存分配器只能按照固定大小分配内存。所以,分配的内存空间一般都会比申请的空间大一些,不会完全一直,这本身就会造成一定碎片,降低内存空存储效率。键值对会被修改或删除,这会导致空间的扩容和释放。一方面,如果修改后的键值对变大或变小了,就需要占用额外的空间或释放不用的空间。另一方面,删除的键值对就不在需要内存空间了,此时会把空间释放出来,变成空闲空间。

        如何判断内存碎片

        Redis是内存数据库,内存利用率的高低直接关系到Redis运行效率的高低。为了让用户能监控到实时的内存使用情况,Redis自身提供了info命令,可以用来查询内存使用的详细信息

info memory
# Memory
used_memory:1143520
used_memory_human:1.09M
used_memory_rss:1114112
used_memory_rss_human:1.06M
used_memory_peak:1144672
used_memory_peak_human:1.09M
used_memory_peak_perc:99.90%
used_memory_overhead:1096754
used_memory_startup:1079248
used_memory_dataset:46766
used_memory_dataset_perc:72.76%
allocator_allocated:1098416
allocator_active:1076224
allocator_resident:1076224
total_system_memory:8589934592
total_system_memory_human:8.00G
used_memory_lua:37888
used_memory_lua_human:37.00K
used_memory_scripts:0
used_memory_scripts_human:0B
number_of_cached_scripts:0
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
allocator_frag_ratio:1.1
allocator_frag_bytes:18446744073709529424
allocator_rss_ratio:1.00
allocator_rss_bytes:0
rss_overhead_ratio:1.04
rss_overhead_bytes:37888
mem_fragmentation_ratio:1.01
mem_fragmentation_bytes:15696
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:16986
mem_aof_buffer:0
mem_allocator:libc
active_defrag_running:0
lazyfree_pending_objects:0

        mem_fragmentation_ratio指标表示内存碎片化率,该值大于1但小于1.5时,这种情况是正常的,因为内存碎片是无法避免的。如果该值大于1.5,就表名内存碎片化率比较严重了,超过了50%,这时需要采取措施来处理内存碎片化。

        Redis从4.0版本后提供了专门清理内存碎片化的参数,通过该参数来设置内存碎片化的清理的开始和结束时机,以及占用CPU比例,从而减少碎片清理对Redis本身请求处理的性能影响。

config set activedefrag yes

        这个命令只是启动了自动清理功能,但具体什么时候清理,会受下面两个参数的控制。这两个参数分别设置了触发内存清理的一个条件,如果同时满足这两个条件,就开始清理,清理过程中,只要有一个条件不满足,就停止清理。

  • active-defrag-ignore-bytes 100mb:表示内存碎片的字节数达到100MB时,就开始清理。
  • active-defrag-threshold-lower 10:表示内存碎片空间占操作系统分配给Redis的总空间比例达到10%时,开始清理。

总结

        关于Redis变慢的问题排查就介绍到这里,不知道你有没有清晰的思路,欢迎关注并留言讨论。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯基础知识2 全排列 next_permutation(), prev_permutation()

蓝桥杯基础知识2 全排列 next_permutation()&#xff0c; prev_permutation() #include<bits/stdc.h> using namespace std;int a[10];int main(){for(int i 1; i < 4; i)a[i] i; //4*3*2*1 24bool tag true;while(tag){for(int i1; i < 4; i)cout << a[…

Page 251~254 Win32 GUI项目

win32_gui 源代码&#xff1a; #if defined(UNICODE) && !defined(_UNICODE)#define _UNICODE #elif defined(_UNICODE) && !defined(UNICODE)#define UNICODE #endif#include <tchar.h> #include <windows.h>/* Declare Windows procedure */…

3D软件坐标系速查【左手/右手】

本文介绍不同3D软件的世界坐标系之间的差异及其工作原理。 NSDT工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 基本上&#xff0c;游戏引擎和3…

XSKY SDS 产品率先获得 OceanBase V4 新版本认证

近日&#xff0c;北京奥星贝斯科技有限公司&#xff08;简称&#xff1a;OceanBase&#xff09;与北京星辰天合科技股份有限公司&#xff08;简称&#xff1a;XSKY 星辰天合&#xff09;顺利完成产品兼容性认证。 XSKY 的高性能全闪存储以及混闪存储&#xff0c;与 OceanBase V…

文献阅读:Sparse Low-rank Adaptation of Pre-trained Language Models

文献阅读&#xff1a;Sparse Low-rank Adaptation of Pre-trained Language Models 1. 文章简介2. 具体方法介绍 1. SoRA具体结构2. 阈值选取考察 3. 实验 & 结论 1. 基础实验 1. 实验设置2. 结果分析 2. 细节讨论 1. 稀疏度分析2. rank分析3. 参数位置分析4. 效率考察 4.…

【STM32】STM32学习笔记-DMA数据转运+AD多通道(24)

00. 目录 文章目录 00. 目录01. DMA简介02. DMA相关API2.1 DMA_Init2.2 DMA_InitTypeDef2.3 DMA_Cmd2.4 DMA_SetCurrDataCounter2.5 DMA_GetFlagStatus2.6 DMA_ClearFlag 03. DMA数据单通道接线图04. DMA数据单通道示例05. DMA数据多通道接线图06. DMA数据多通道示例一07. DMA数…

jupyter notebook 配置conda 虚拟环境python

conda创建python环境 conda create -n openvoice python3.9 激活环境 source activate openvoice 在虚拟环境中安装ipykernel pip install ipykernel 添加虚拟环境进到 jupyter notebook python -m ipykernel install --user --name openvoice --display-name openvoice …

base64与BytesIO图片进行编码、解码;api调用

base64与BytesIO简单介绍 io.BytesIO 和 Base64 编码都是用于在内存中处理二进制数据的方法&#xff0c;但它们的目的和使用场景有所不同。 1&#xff09; io.BytesIO io.BytesIO 是 Python io 库中的一个类&#xff0c;它提供了一个在内存中处理二进制数据的接口&#xff0…

Linux-shell简单学习

我是南城余&#xff01;阿里云开发者平台专家博士证书获得者&#xff01; 欢迎关注我的博客&#xff01;一同成长&#xff01; 一名从事运维开发的worker&#xff0c;记录分享学习。 专注于AI&#xff0c;运维开发&#xff0c;windows Linux 系统领域的分享&#xff01; 其他…

Qt6入门教程 4:Qt Creator常用技巧

在上一篇Qt6入门教程 3&#xff1a;创建Hello World项目中&#xff0c;通过创建一个Qt项目&#xff0c;对Qt Creator已经有了比较直观的认识&#xff0c;本文将介绍它的一些常用技巧。 Qt Creator启动后默认显示欢迎页面 创建项目已经用过了&#xff0c;打开项目也很简单&#…

C++力扣题目226--翻转二叉树

给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1]示例 2&#xff1a; 输入&#xff1a;root [2,1,3] 输出&#xff1a;[2,3,1]示例 3&#x…

Apache Doris 入门 10 问

基于 Apache Doris 在读写流程、副本一致性机制、 存储机制、高可用机制等方面的常见疑问点进行梳理&#xff0c;并以问答形式进行解答。在开始之前&#xff0c;我们先对本文相关的名词进行解释&#xff1a; FE&#xff1a;Frontend&#xff0c;即 Doris 的前端节点。主要负责接…

《堆排序》与《Top—k》

目录 ​编辑 前言&#xff1a; 关于《堆排序》&#xff1a; 第一步&#xff1a;建堆 第二步&#xff1a;排序 《Top—K问题》 关于Top—k问题&#xff1a; 前言&#xff1a; 我们在前面的blog中&#xff0c;对于《堆》已经有了初步的概念&#xff0c;那么接下来我们可以…

FineBI实战项目一(18):每小时上架商品个数分析开发

点击新建组件&#xff0c;创建每小时上架商品个数组件。 选择线图&#xff0c;拖拽cnt&#xff08;总数&#xff09;到纵轴&#xff0c;拖拽hourStr到横轴。 修改横轴和纵轴的文字。 调节连线样式。 添加组件到仪表板。

MYSQL的学习——单行函数详解

目录 1. 数值函数 1) 基本函数 2) 角度与弧度互换函数 3) 三角函数 4) 指数与对数函数 5) 进制间的转换 2. 字符串函数 3. 日期和时间函数 1) 获取日期、时间 2) 日期与时间戳的转换 3) 获取月份、星期、星期数、天数等函数 4) 日期的操作函数 5) 时间和秒钟转换的…

程序员有哪些接单的渠道?

这题我会&#xff01;程序员接单的渠道那可太多了&#xff0c;想要接到合适的单子&#xff0c;筛选一个合适的平台很重要。如果你也在寻找一个合适的接单渠道&#xff0c;可以参考以下这些方向。 首先&#xff0c;程序员要对接单有一个基本的概念&#xff1a;接单渠道可以先粗略…

[足式机器人]Part3 机构运动学与动力学分析与建模 Ch00-3(2) 刚体的位形 Configuration of Rigid Body

本文仅供学习使用&#xff0c;总结很多本现有讲述运动学或动力学书籍后的总结&#xff0c;从矢量的角度进行分析&#xff0c;方法比较传统&#xff0c;但更易理解&#xff0c;并且现有的看似抽象方法&#xff0c;两者本质上并无不同。 2024年底本人学位论文发表后方可摘抄 若有…

SpringBoot中使用LocalDateTime踩坑记录

文章目录 前言一、为什么推荐使用java.time包的LocalDateTime而不是java.util的Date&#xff1f;二、使用LocalDateTime和LocalDate时遇到了哪些坑&#xff1f;2.1 Redis序列化报错2.1.1 问题现象2.1.2 问题分析2.1.3 解决方案 2.2 LocalDateTime和LocalDate类型的属性返回给前…

python_数据可视化_pandas_导入excel数据

目录 1.1导入库 1.2读取excel文件 1.3读取excel&#xff0c;指定sheet2工作表 1.4指定行索引 1.5指定列索引 1.6指定导入列 案例速览&#xff1a; 1.1导入库 import pandas as pd 1.2读取excel文件 pd.read_excel(文件路径) data pd.read_excel(D:/desktop/TestExcel…

Docker安装Jenkins,配置Maven和Java

前言 这是一个java的springboot项目&#xff0c;使用maven构建 安装准备 需要将maven和jdk安装在服务器上&#xff0c;Jenkins需要用到&#xff0c;还有创建一个jenkins的目录&#xff0c;安装命令如下&#xff1a; docker run -d -uroot -p 9095:8080 -p 50000:50000 --n…