2、Redis变慢原因排查(下)

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

Redis变慢排查的上一篇【感觉Redis变慢了,这些可能的原因你查了没 ?(上)】,我们是基于Redis命令为入口,比如命令使用不得当,bigkey问题,以及集中过期问题来看现象和如何进行优化处理的,认真读过的同学想必大家对这些现象和处理方式有了比较深的印象。

本期将基于存储层,比如AOF和RDB持久化、内存分配机制、系统层以及一些额外的影响因素,来看看这些情况是如何导致对Redis造成影响的!

先看下篇的大纲:
在这里插入图片描述
持久化

在服务层影响Redis性能的因素中,在存储层就涉及到持久化可能导致的影响,那到底是在什么情况下会发生呢!
在这里插入图片描述

AOF持久化到磁盘
大家可能想过没,在数据持久化方面,还有影响 Redis 性能的因素,这就是AOF 数据持久化。

这里回顾一下AOF机制和三种刷盘策略
在这里插入图片描述
Redis开启AOF后,工作原理如下:

1:客户端发送命令到服务器,在服务器在执行完一个写命令之后,会以Redis协议格式将被执行的写命令追加到服务器状态的 aof_buf 缓冲区的末尾,要是再执行一个写命令,那么会继续追加到aof_buf 缓冲区末尾,这就是追加方式

2:通过 write() 函数,将 aof_buf 缓冲区的数据写入到 AOF 文件

3:在主服务进程死循环的最后,会调用flushAppendOnlyFile函数,该函数会将aof_buf中的数据写入到内核缓冲区,然后判断使用何种策略进行同步

AOF三种刷盘机制如下图:
在这里插入图片描述
通过同种对三种刷盘机制的分析,可以看出如果一般不建议采用always刷盘方式,这个机制会严重拖慢Redis的性能

如果只是将Redis作为缓存,不计较数据丢失的话,可以使用 no方式

大多数人会选择比较折中的方案 everysec同步机制,既保证了数据安全又兼顾了性能,那这种机制就没有任何问题了吗?

方案没有最完美的,everysec同步机制同样存在导致Redis延迟变慢的情况。

AOF耗时的刷盘操作不是已经创建了一个后台线程去处理吗,怎么还会影响Redis主进程呢?

不过这里有个知识点需要注意,就是:

当后台线程(aof_fsync 线程)调用 fsync 函数同步 AOF 文件时,需要等待,直到写入完成。

当磁盘压力太大的时候,会导致 fsync 操作发生阻塞,主线程调用 write 函数时也会被阻塞。fsync 完成后,主线程执行 write 才能成功返回

也就是说压力到了磁盘IO这边,因此磁盘IO压力过大,同样可能导致Redis主进程阻塞,主进程阻塞了,自然处理用户命令变慢了

排查方式:

1:info Persistence,查看aof_delayed_fsync指标,一直在增加,说明主线程频繁出现被阻塞情况

2:系统日志会有提示信息【Asynchronous AOF fsync is taking too long …】

AOF重写
先看AOF重写机制,这个大多数朋友都很清楚了,这里再回顾一下:

• fork 出一条子线程来将文件重写,在执行 BGREWRITEAOF 命令时,Redis 服务器会维护一个 AOF 重写缓冲区,该缓冲区会在子线程创建新 AOF 文件期间,记录服务器执行的所有写命令。

• 当子线程完成创建新 AOF 文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新 AOF 文件的末尾,使得新的 AOF 文件保存的数据库状态与现有的数据库状态一致。

• 最后,服务器用新的 AOF 文件替换旧的 AOF 文件,以此来完成 AOF 文件重写操作

看起来是是很正常的,但是刷盘策略和重写机制一起就可能出现以外

127.0.0.1:6379> config get *append*
1) "no-appendfsync-on-rewrite"
2) "no"
3) "appendonly"
4) "yes"
5) "appendfsync"
6) "everysec"

我们看到redis配置可以得出以下结论:

1:Redis实例使用AOF进行持久化,appendfsync策略采用的是everysec刷盘

2:AOF的文件会越来越大,Redis还有一个rewrite策略,实现AOF文件的重写瘦身

3:但是no-appendfsync-on-rewrite的策略是 no,这就会导致在进行rewrite操作时,append fsync会被阻塞

4:而fsync阻塞,会导致Redis主进程也会阻塞

总结起来就是说,AOF重写机制和AOF持久化刷盘一起发生了,冲突了!
在这里插入图片描述
不过我们可以进行配置将 no-appendfsync-on-rewrite 设置为 yes 。这样可以避免AOF rewrite 重写期间,后台子线程不执行刷盘操作,但是在rewrite 期间会有AOF丢失的风险,需要自己权衡好利弊!

不过我看到过一个相对比较折中的方案,分享给大家:

1:给当前Redis实例添加slave节点,当前节点设置为master, 然后master节点关闭AOF,slave节点开启AOF

2:在master 节点设置将 no-appendfsync-on-rewrite 设置为 yes(避免重写时造成和fsync写磁盘的冲突)

3:为了防止AOF文件越来越大,配置在凌晨低峰期定时手动执行bgrewriteaof命令完成每日一次的AOF重写

4:为避免硬盘空间不足或者IO使用率高影响重写功能,添加磁盘空报警和IO使用率报警保障重写的正常进行

技术问题的处理方案有时候没有最完美的,往往是选择合适自己的方案

fork子进程耗时
先来看看fork是什么

fork 是unix和linux这种操作系统的一个api,而不是Redis的api,fork()用于创建一个子进程,不是子线程

有一点我们可以知道的是fork 的目的最终一定是为了不阻塞主进程来提升 Redis 服务的可用性。

而Redis 开启了后台 RDB 和 AOF rewrite 后,在执行时,都需会主进程创建出一个子进程进行数据的持久化,而这个过程会调用操作系统的fork()操作。
在这里插入图片描述
想具体了解如何进行fork的同学可以看我之前的文章分享:redis aof和rdb

Redis中fork 对内存数据的 copy-On-Write (写时复制) 机制最廉价的实现内存镜像

虚拟内存表是在 fork 的瞬间就需要分配,所以这个操作会造成主线程短时间的卡顿(停止所有读写操作),不过卡顿时间跟Redis内存使用量有关。

GB 量级的 Redis 进行 fork 操作的时间在毫秒级 如果这个Redis实例很大,CPU负载再高些,那么 fork 的耗时就会更长,甚至达到秒级,也就会严重影响 Redis 的访问响应时间

这也就是为什么fork()子进程可能导致Redis变慢的原因了

我们可以通过命令去查看延迟大小

//执行 INFO 命令,查看 latest_fork_usec ,时间微秒

latest_fork_usec:15699

碎片化过大
什么是内存碎片?

你可以将内存碎片简单地理解为那些不可用的空闲内存

举个例子:操作系统为你分配了 16 字节的连续内存空间,而你存储数据实际只需要使用 12 字节内存空间,那这多余出来的 4 字节内存空间如果后续没办法再被分配存储其他数据的话,就可以被称为内存碎片
在这里插入图片描述
Redis 内存碎片产生比较常见的 2 个原因:

1、存储存储数据的时候向操作系统申请的内存空间可能会大于数据实际需要的存储空间

2、频繁修改 Redis 中的数据

我们可以通过info memory命令查看内存相关的信息,可以计算出内存碎片率

内存碎片率可通过参数计算:mem_fragmentation_ratio (内存碎片率)= used_memory_rss (操作系统实际分配给 Redis 的物理内存空间大小)/ used_memory(内存分配器为了存储数据实际申请使用的内存空间大小)

Redis清理内存碎片的方式有两种:

• Redis 4.0 以前的低版本,只能通过重启实例来解决,不能自动配置回收

• 从 4.0版本以后,提供了一种内存碎片自动回收的方法,可以通过配置动态开启碎片整理

碎片整理
注意开启内存碎片整理,有可能导致 Redis 服务性能下降

Redis 的碎片整理工作是在主线程中执行的,当其进行碎片整理时,操作系统会把多份数据拷贝到新位置以把原有空间释放出来,这会带来时间开销,而这个过程就会阻塞Redis处理请求

为了降低碎片整理带来的性能影响,Redis 为自动内存碎片整理机制提供了多个参数,具体有:

#是否开启碎片整理
activedefrag yes 

#碎片大小超过 500MB 时才会触发整理
active-defrag-ignore-bytes 500mb 

 #碎片大小占操作系统分配总空间比超过 20% 时触发整理
active-defrag-threshold-lower 20

#碎片整理过程占用的CPU比例不低于 15%,保证整理可以正常执行
active-defrag-cycle-min 15 

#碎片整理过程占用的CPU比例不高于70%,一旦超过就暂停整理,
#避免大量的内存拷贝等整理过程占用过多的CPU进而影响正常请求
active-defrag-cycle-max 70 

#碎片整理过程中,对于 HashListSetZSet 等成员集合类型一次扫描的元素数量
active-defrag-max-scan-fields 500 

在开启碎片自动整理时,一定要优先评估当前 Redis 服务的负载状态,以及应用程序可接受的响应延迟,合理设置碎片整理的参数值和回收时间段【比如放到凌晨程序定时触发】,来尽可能降低碎片整理期间对Redis服务的影响。

操作系统层Swap被使用
先来了解下什么是Swap

操作系统为了缓解内存不足对应用程序的影响,允许把一部分内存中的数据换到磁盘上,以达到应用程序对内存使用的缓冲,这些内存数据被换到磁盘上的区域,等到那些程序要运行时,再从Swap中恢复保存的数据到内存中,这就是 Swap。

在这里插入图片描述
也就是说内存中的数据被交换到了磁盘中,再次访问数据时,就需要从磁盘上读取,而我们知道访问磁盘的速度是比访问内存慢几个等级的。

Redis作为内存数据库,有个常识一定要记住:所有的数据默认都是在内存中,不存在一部分在内存一部分在磁盘中的情况,除非被迫发生了SWAP。

可以通过以下方式来查看 Redis 进程是否使用到了 Swap:

# 获取Redis 的进程 ID
[root@VM-12-10-opencloudos ~]#  redis-cli info | grep process_id
process_id:2600003

# 查看 Redis Swap 使用情况
[root@VM-12-10-opencloudos ~]#  cat /proc/260003/smaps | egrep '^(Swap|Size)'

Size:               1296 kB
Swap:                  0 kB
SwapPss:               0 kB
Size:                  4 kB
Swap:                  0 kB
SwapPss:               0 kB
Size:                 20 kB
Swap:                  0 kB
SwapPss:               0 kB
...

每一行 Size 表示 Redis 所用的一块内存大小,Size 下面的 Swap 就表示这块 Size 大小的内存,有多少数据已经被换到磁盘上了

如果这两个值相等,说明这块内存的数据都已经完全被换到磁盘上了

如果真的交换到了内存,对于Redis这种性能要求较高的,对这种延迟还是需要谨慎对待!

针对Swap情况可以参考以下解决方案:

• 建议将Redis的预留内存提高,可以多留个20%左右

• 单独不是Redis实例,避免和其他服务进程竞争使用内存

• 整理内存空间,释放出足够的内存供 Redis 使用,然后释放 Redis 的 Swap

总的来说这种内存余量和Swap情况还是要进行监控,毕竟不可能等到出现了问题才去查,那么只能做事后补救处理了

网络带宽被打满
Redis的性能问题,除了前面提到的各种可能影响因素之外,别忘了还有网络IO也可能存在瓶颈,如果网络存在瓶颈,一样会严重影响Redis性能的。

放在后面讲是默认我们认为网络环境是良好的,一般排查问题会从Redis服务去查,不过如果出现带宽过载情况的话,服务器在 TCP 层和网络层就会出现数据包发送延迟、丢包等情况。
在这里插入图片描述
如果因为流量确实大,那么可以考虑进行扩容,不过最好在运维层就Redis的这些指标进行监控,包括网络流量。

其他因素
除了上面主要列出的一些可能因素,这里也有一些其他可能导致影响的原因

Redis服务配置不合理
比如连接数配置啊,内存上限、前面我们讲的AOF持久化和重写的一些配置等等,合理的配置会尽量避免一些问题的出现

使用连接池
应该使用长连接操作 Redis,避免使用短连接模式,频繁的连接创建与销毁,在高QPS访问时网络开销巨大

cpu绑定进程影响
Redis是单线程模型处理处理用户需求,那么处理的吞吐、效率就会极度依赖CPU的处理能力

为了提高服务性能,降低应用程序在多个 CPU 核心之间的上下文切换带来的性能损耗,通常采用的方案是进程绑定 CPU 的方式提高性能

但是Redis的绑核操作过于复杂,对于单机多实例的管理挑战过高,不建议绑定 CPU来处理,这里也不做深入说明,我也没具体深入了解过了

总结
到这里,关于影响Redis性能的因素下篇就分享完了。

相信如果能耐心地看到这里的同学,想必你肯定已经对 Redis 的变慢该如何处理有了很大的收获,同样对Redis如何进行调优也收获很大。

但是通过上下两篇的内容发现 Redis 的性能问题,涉及到的知识点非常广,几乎涵盖了 CPU、内存、网络、甚至磁盘的方方面面。
在这里插入图片描述

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

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

相关文章

STM32F1的TIM输出比较(PWM)

目录 1. OC(Output Compare)输出比较 2. PWM简介 3. 输出比较通道(高级) 4. 输出比较通道(通用) 5. PWM基本结构 6. 配置介绍 6.1 输出比较模块配置 6.2 给输出比较结构体赋一个默认值 6.3 配置强制输出模式 6.4 配置CRR寄存器的预装…

Python Appium Selenium 查杀进程的实用方法

一、前置说明 在自动化过程中,经常需要在命令行中执行一些操作,比如启动应用、查杀应用等,因此可以封装成一个CommandExecutor来专门处理这些事情。 二、操作步骤 # cmd_util.pyimport logging import os import platform import shutil i…

Linux篇之在Centos环境下搭建Nvidia显卡驱动

一、前提条件 1、首先确认内核版本和发行版本,再确认显卡型号 uname -a // Linux localhost.localdomain 4.18.0-408.el8.x86_64 #1 SMP Mon Jul 18 17:42:52 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux1.2 cat /etc/redhat-release // CentOS Stream release 81.3…

TCP单聊和UDP群聊

TCP协议单聊 服务端: import java.awt.BorderLayout; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.V…

从Centos-7升级到Centos-Stream-8

如果在正式环境升级,请做好数据备份以及重要配置备份!因为升级会造一部分应用被卸载。 注意:升级前请备份好数据,升级可能会导致ssh的root用户无法登陆、网卡名称发生改变、引导丢失无法开机等问题。 1.安装epel源 yum -y install…

QT作业1

自由发挥登录窗口的应用场景&#xff0c;实现一个登录窗口界面 头文件代码&#xff1a; #ifndef MYWIDGET_H #define MYWIDGET_H#include <QWidget> #include <QIcon> #include <QLabel> //标签类 #include <QMovie> //动图类 #include <…

【华为数据之道学习笔记】3-4主数据治理

主数据是参与业务事件的主体或资源&#xff0c;是具有高业务价值的、跨流程和跨系统重复使用的数据。主数据与基础数据有一定的相似性&#xff0c;都是在业务事件发生之前预先定义&#xff1b;但又与基础数据不同&#xff0c;主数据的取值不受限于预先定义的数据范围&#xff0…

AI助力智慧农业,基于DETR【DEtection TRansformer】模型开发构建田间作物场景下庄稼作物、杂草检测识别系统

智慧农业随着数字化信息化浪潮的演变有了新的定义&#xff0c;在前面的系列博文中&#xff0c;我们从一些现实世界里面的所见所想所感进行了很多对应的实践&#xff0c;感兴趣的话可以自行移步阅读即可&#xff1a; 《自建数据集&#xff0c;基于YOLOv7开发构建农田场景下杂草…

Java 第21章 网络通信

网络程序设计基础 网络程序设计编写的是与其他计算机进行通信的程序。Java 已经将网络程序所需要的元素封装成不同的类&#xff0c;用户只要创建这些类的对象&#xff0c;使用相应的方法&#xff0c;即使不具备有关的网络支持&#xff0c;也可以编写出高质量的网络通信程序。 …

Python-Opencv图像处理的小坑

1.背景 最近在做一点图像处理的事情&#xff0c;在做处理时的cv2遇到一些小坑&#xff0c;希望大家遇到的相关的问题可以注意&#xff01;&#xff01; 2. cv2.imwrite保存图像 cv2.imwrite(filename, img, [params]) filename&#xff1a;需要写入的文件名&#xff0c;包括路…

一键AI智能改写,一键AI智能生成原创文章

在数字化时代&#xff0c;创作内容已经成为大家日常生活和工作中不可或缺的一部分。本文将深入探讨一键AI智能改写的概念&#xff0c;剖析其背后的技术原理&#xff0c;同时聚焦于147原创助手这一代表性工具&#xff0c;解读其在改写文案上的独特之处&#xff0c;以及在各大平台…

JavaWeb-Tomcat

1. Web服务器 web服务器由硬件和软件组成&#xff1a; 硬件&#xff1a;计算机系统软件&#xff1a;计算机上安装的服务器软件&#xff0c;安装后可以为web应用提供网络服务。 常见的JavaWeb服务器&#xff1a; Tomcat&#xff08;Apache&#xff09;&#xff1a;应用最广泛的…

B站缓存视频M4S合并MP4(js + ffmpeg )

文章目录 B站缓存视频转MP4&#xff08;js ffmpeg &#xff09;1、说明 2、ffmpeg2.1 下载地址2.2 配置环境变量2.3 测试2.4 转换MP4命令 3、处理程序 B站缓存视频转MP4&#xff08;js ffmpeg &#xff09; 注意&#xff1a;这样的方式只用于个人之间不同设备的离线观看。请…

Docker构建自定义镜像

创建一个docker-demo的文件夹,放入需要构建的文件 主要是配置Dockerfile文件 第一种配置方法 # 指定基础镜像 FROM ubuntu:16.04 # 配置环境变量&#xff0c;JDK的安装目录 ENV JAVA_DIR/usr/local# 拷贝jdk和java项目的包 COPY ./jdk8.tar.gz $JAVA_DIR/ COPY ./docker-demo…

进行生成简单数字图片

1.之前只能做一些图像预测,我有个大胆的想法,如果神经网络正向就是预测图片的类别,如果我只有一个类别那就可以进行生成图片,专业术语叫做gan对抗网络 2.训练代码 import torch import torch.nn as nn import torch.optim as optim import torchvision.transforms as transfo…

数据分析基础之《matplotlib(3)—散点图》

一、常见图形种类及意义 1、matplotlib能够绘制折线图、散点图、柱状图、直方图、饼图。我们需要知道不同的统计图的意义&#xff0c;以此来决定选择哪种统计图来呈现我们的数据 2、折线图plot 说明&#xff1a;以折线的上升或下降来表示统计数量的增减变化的统计图 特点&…

Django + Matplotlib:实现数据分析显示与下载为PDF或SVG

写作背景 首先&#xff0c;数据分析在当前的信息时代中扮演着重要的角色。随着数据量的增加和复杂性的提高&#xff0c;人们对于数据分析的需求也越来越高。 其次&#xff0c;笔者也确确实实曾经接到过一个这样的开发需求&#xff0c;甲方是一个医疗方面的科研团队&#xff0…

网络安全(五)--Linux 入侵检测分析技术

8. Linux 入侵检测分析技术 目标 了解入侵检测分析的基本方法掌握查看登录失败用户的方法掌握查阅历史命令的方法掌握检查系统开机自启服务的方法 8.1. 概述 最好的安全防护当然是“域敌于国门之外”&#xff0c; 通过安全防护技术&#xff0c;来保证当前主机不被非授权人员…

【链表Linked List】力扣-117 填充每个节点的下一个右侧节点指针II

目录 问题描述 解题过程 官方题解 问题描述 给定一个二叉树&#xff1a; struct Node {int val;Node *left;Node *right;Node *next; } 填充它的每个 next 指针&#xff0c;让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点&#xff0c;则将 next 指针设置为 N…

IT行业软件数据文件传输安全与高效是如何保障的?

在当今迅速发展的科技世界中&#xff0c;云计算、大数据、移动互联网等信息技术正迎来蓬勃发展&#xff0c;IT行业正置身于一个全新的世界。数据不仅是最重要的资产&#xff0c;也是企业竞争力的核心所在。然而&#xff0c;如何缩短信息共享时间、高速流转数据、跨部门/跨区域协…