[转帖]如何应对变慢的Redis-波动的响应延迟

如何,应对,变慢,redis,波动,响应,延迟 · 浏览次数 : 0

小编点评

**内存溢出解决方案** * **配置选项:no-appendfsync-on-rewrite** * 避免 AOF 重写和 fsync 竞争磁盘 IO 资源,导致 Redis 延迟增加。 * **配置选项:always** * 确保每个操作记录日志都写回磁盘,提高性能。 * **内存大页机制** * 支持 2MB 大小的内存页分配,可以减少内存分配次数。 * **内存大页配置** * 开启内存大页机制,可以减少内存分配次数,但需要将数据做持久化保存。 * **AOF 配置级别** * 设置**no-appendfsync-on-rewrite**,避免 AOF 重写和 fsync 竞争磁盘 IO 资源。 * 使用高速固态盘作为 AOF 日志的写入盘。

正文

Redis突然变慢了,如何排查呢

问题认定

如何判断Redis是不是真的变慢了?通过Redis的响应延迟

  • 大部分时候,Redis延迟很低,某些时刻,Redis实例会出现几秒到十几秒延迟,基本就可以断定Redis变慢了
  • 不同的软硬件环境下,Redis判断延迟的标准不同,所以需要通过当前环境下的Redis基线性能做判断
    • Redis基线性能:一个系统在低压力、无干扰下的基本性能,这个性能只由当前的软硬件配置决定
    • 如何确定基线性能:redis-cli –intrinsic-latency 120 统计120s内的最大延迟作为基线性能
    • 基线性能和当前的操作系统、硬件配置相关,一般Redis运行时延时是其基线性能的2倍以上,就可以认定Redis变慢了。

对于在虚拟化环境下运行的 Redis 来说,判断基线性能非常重要。在虚拟化环境(例如虚拟机或容器)中,由于增加了虚拟化软件层,与物理机相比,虚拟机或容器本身就会引入一定的性能开销,所以基线性能会高一些。
在这里插入图片描述
此时的基线性能达到了 9.871ms,如果该 Redis 实例的运行时延迟为 10ms,这并不能算作性能变慢,因为此时,运行时延迟只比基线性能增加了 1.3%。

  • 为了避免网络对基线性能的影响, 这个命令需要在服务器端直接运行,只考虑服务器端软硬件环境的影响。
  • 网络对 Redis 性能的影响,一个简单的方法是用 iPerf 这样的工具,测量从 Redis 客户端到服务器端的网络延迟。
    • 如果这个延迟有几十毫秒甚至是几百毫秒,说明Redis 运行的网络环境中很可能有大流量的其他应用程序在运行,导致网络拥塞了
    • 需要协调网络运维,调整网络的流量分配

应对方案

首先需要知道影响Redis性能的三大因素

  • 自身的操作特性
  • 文件系统
  • 操作系统
    在这里插入图片描述

Redis自身操作特性

慢查询命令

了解不同操作的复杂度,可以参考命令复杂度

通过 Redis 日志,或者是 latency monitor 工具,可以定位查询变慢的请求,根据请求对应的具体命令以及官方文档,确认下是否采用了复杂度高的慢查询命令。

如果有,处理方式如下

  • 其他高效命令代替。比如返回Set里的所有成员,不用SMEMBERS,而用SSCAN多次迭代返回,避免一次返回大量数据造成线程阻塞
  • 需要执行排序、交集、并集操作时,可以在客户端完成,以免拖慢Redis实例
  • 如果业务逻辑就是要求使用慢查询命令,那你得考虑采用性能更好的 CPU,更快地 完成查询命令,避免慢查询的影响。

过期key操作

过期key会进行自动删除,是Redis用来回收内存空间的常用机制。算法如下

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

正常情况下,一秒内基本有 200 个过期 key 会被删除,并不会对 Redis 造成太大影响,但是如果触发第二条,Redis就会一直删除以释放空间。

删除操作是阻塞的(Redis 4.0 后可以用异步线程机制来减少阻塞影响),一旦该条件触发,Redis 的线程就会一直执行删除,这样一来,就没办法正常服务其他的键值操作,就会进一步引起其他键值操作的延迟增加,Redis 就会变慢。

频繁使用带有相同时间参数的 EXPIREAT 命令设置过期 key,就会触发第二条规则。

可以在过期时间参数上,加上一定大小范围内的随机数,这样,既保证 key 在一个邻近时间范围内被删除,又避免了同时过期造成的压力。

文件系统

Redis 会持久化保存数据到磁盘,这个过程要依赖文件系统来完成,所以,文件系统将数 据写回磁盘的机制,会直接影响到 Redis 持久化的效率。在持久化的过程中,Redis 也还在接收其他请求,持久化的效率高低又会影响到 Redis 处理请求的性能。

AOF

AOF 日志提供了三种日志写回策略:no、everysec、always。这三种写回策略依赖文件系统的 两个系统调用 write 和 fsync。

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

下面这张表展示了三种 写回策略所执行的系统调用。
在这里插入图片描述

  • everysec :Redis 允许丢失一秒的操作记录。Redis 主线程并不需要确保每个操作记录日志都写回磁盘。当写回策略配置为 everysec 时,Redis 会使用后台的子线程异步完成 fsync 的操作。
  • always :Redis 需要确保每个操作记录日志都写回磁盘,always 策略使用主线程来执行fsync操作。

Redis使用子进程来进行AOF重写,重写贵对磁盘进行大量IO操作,fsync又要求等到数据写到磁盘后才能返回,所以AOF重写压力比较大的时候,会导致fsync阻塞

虽然fsync是由后台子线程负责执行的,但主线程会监控fsync的执行进度

  • 当主线程使用后台子线程执行了一次 fsync,需要再次把新接收的操作记录写回磁盘时,如果主线程发现上一次的 fsync 还没有执行完,那么它就会阻塞。
  • 如果后台子线程执行的 fsync 频繁阻塞的话(比如 AOF 重写占用了大量的磁盘 IO 带宽),主线程也会阻塞,导致 Redis 性能变慢。
    在这里插入图片描述
    由于 fsync 后台子线程和 AOF 重写子进程的存在,主 IO 线程一般不会被阻塞。但是,如果在重写日志时,AOF 重写子进程的写入量比较大, fsync 线程也会被阻塞,进而阻塞主线程,导致延迟增加。

解决方案

  • 如果 AOF 写回策略使用了 everysec 或 always 配置,请先确认下业务方对数据可靠性的 要求,明确是否需要每一秒或每一个操作都记日志。

  • 如果业务应用对延迟非常敏感,但同时允许一定量的数据丢失,那么,可以把配置项 no- appendfsync-on-rewrite 设置为 yes

    • 这个配置项设置为 yes 时,表示在 AOF 重写时,不进行 fsync 操作。也就是说,Redis 实 例把写命令写到内存后,不调用后台线程进行 fsync 操作,就可以直接返回了。当然,如 果此时实例发生宕机,就会导致数据丢失。反之,
    • 如果这个配置项设置为 no(也是默认配 置),在 AOF 重写时,Redis 实例仍然会调用后台线程进行 fsync 操作,这就会给实例带 来阻塞。
  • 如果的确需要高性能,同时也需要高可靠数据保证,我建议你考虑采用高速的固态硬盘作 为 AOF 日志的写入设备。

操作系统

Swap

Redis 是内存数据库,内存使用量大,如果没有控制好内存的使用量,或者和其他内存需求大的应用一起运行了,操作系统会启动 swap 机制,而导致性能变慢。

内存 swap 是操作系统里将内存数据在内存和磁盘间来回换入和换出的机制,涉及到磁盘的读写,一旦触发 swap,无论是被换入数据的进程,还是被换出数据的进程,其性能都会受到慢速磁盘读写的影响。

正常情况下,Redis 的操作是直接通过访问内存就能完成,一旦 swap 被触发了,Redis 的请求操作需要等到磁盘数据读写完成才行,swap 触发后影响的是 Redis 主 IO 线程,这会极大地增加 Redis 的响应时间。

触发 swap 的原因主要是物理机器内存不足,对于 Redis 而言,有两种常见的情况:

  • Redis 实例自身使用了大量的内存,导致物理机器的可用内存不足;
  • 和 Redis 实例在同一台机器上运行的其他进程,在进行大量的文件读写操作。文件读写本身会占用系统内存,这会导致分配给 Redis 实例的内存量变少,进而触发 Redis 发生 swap。

排查步骤
查看进程号

redis-cli info | grep process_id
  • 1
cd /proc/进程号id
cat smaps | egrep '^(Swap|Size)'
  • 1
  • 2

在这里插入图片描述

  • 每一行 Size 表示的是 Redis 实例所用的一块内存大小,而 Size 下方的 Swap 和它相对应,表示这块 Size 大小的内存区域有多少已经被换出到磁盘上了。如果这两个值相等,就 表示这块内存区域已经完全被换出到磁盘了。
  • 作为内存数据库,Redis 本身会使用很多大小不一的内存块,所以,你可以看到有很多 Size 行,有的很小,就是 4KB,而有的很大,例如 462044KB。不同内存块被换出到磁盘 上的大小也不一样,例如刚刚的结果中的第一个 4KB 内存块,它下方的 Swap 也是 4KB, 这表示这个内存块已经被换出了;另外,462044KB 这个内存块也被换出了 462008KB, 差不多有 462MB。

这里有个重要的地方,我得提醒你一下,当出现百 MB,甚至 GB 级别的 swap 大小时, 就表明,此时,Redis 实例的内存压力很大,很有可能会变慢。所以,swap 的大小是排查 Redis 性能变慢是否由 swap 引起的重要指标。

解决方案

  • 一旦发生内存 swap,最直接的解决方法就是增加机器内存。如果该实例在一个 Redis 切 片集群中,可以增加 Redis 集群的实例个数,来分摊每个实例服务的数据量,进而减少每 个实例所需的内存量。
  • 当然,如果 Redis 实例和其他操作大量文件的程序(例如数据分析程序)共享机器,你可 以将 Redis 实例迁移到单独的机器上运行,以满足它的内存需求量。如果该实例正好是Redis 主从集群中的主库,而从库的内存很大,也可以考虑进行主从切换,把大内存的从 库变成主库,由它来处理客户端请求。

内存大页

内存大页机制(Transparent Huge Page, THP),也会影响 Redis 性能。

Linux 内核从 2.6.38 开始支持内存大页机制,该机制支持 2MB 大小的内存页分配,而常规的内存页分配是按 4KB 的粒度来执行的

系统的设计通常是一个取舍过程,我们称之为 trade-off。很多机制通常都是优势和劣势并存的。Redis 使用内存大页就是一个典型的例子

  • 虽然内存大页可以给 Redis 内存减少分配次数,但是Redis 为了提供数据可靠性保证,需要将数据做持久化保存。这个写入过程由额外的线程执行,Redis 就会采用写时复制机制,也就是说,一旦有数据要被修 改,Redis 并不会直接修改内存中的数据,而是将这些数据拷贝一份,然后再进行修改。
  • 如果采用了内存大页,那么客户端请求只修改 100B 的数据,Redis 也需要拷贝 2MB 的大页。
  • 内存大页机制将导致大量的拷贝,这就会影响 Redis 正常的访存操作,最终导致性能变慢。

查看内存大页是否开启

cat /sys/kernel/mm/transparent_hugepage/enabled
  • 1
  • always:内存大页机制被启动
  • never : 内存大页机制被禁止

很简单,关闭内存大页,就行了。

CheckList

  • 获取 Redis 实例在当前环境下的基线性能。
  • 是否用了慢查询命令?如果是的话,就使用其他命令替代慢查询命令,或者把聚合计算 命令放在客户端做。
  • 是否对过期 key 设置了相同的过期时间?对于批量删除的 key,可以在每个 key 的过期 时间上加一个随机数,避免同时删除。
  • 是否存在 bigkey? 对于 bigkey 的删除操作,如果你的 Redis 是 4.0 及以上的版本, 可以直接利用异步线程机制减少主线程阻塞;如果是 Redis 4.0 以前的版本,可以使用 SCAN 命令迭代删除;对于 bigkey 的集合查询和聚合操作,可以使用 SCAN 命令在客 户端完成。
  • Redis AOF 配置级别是什么?业务层面是否的确需要这一可靠性级别?如果我们需要高 性能,同时也允许数据丢失,可以将配置项 no-appendfsync-on-rewrite 设置为 yes,避免 AOF 重写和 fsync 竞争磁盘 IO 资源,导致 Redis 延迟增加。当然, 如果既 需要高性能又需要高可靠性,最好使用高速固态盘作为 AOF 日志的写入盘。
  • Redis 实例的内存使用是否过大?发生 swap 了吗?如果是的话,就增加机器内存,或 者是使用 Redis 集群,分摊单机 Redis 的键值对数量和内存压力。同时,要避免出现 Redis 和其他内存需求大的应用共享机器的情况。
  • 在 Redis 实例的运行环境中,是否启用了透明大页机制?如果是的话,直接关闭内存大 页机制就行了。
  • 是否运行了 Redis 主从集群?如果是的话,把主库实例的数据量大小控制在 2~4GB, 以免主从复制时,从库因加载大的 RDB 文件而阻塞。
  • 是否使用了多核 CPU 或 NUMA 架构的机器运行 Redis 实例?使用多核 CPU 时,可以 给 Redis 实例绑定物理核;使用 NUMA 架构时,注意把 Redis 实例和网络中断处理程 序运行在同一个 CPU Socket 上。

与[转帖]如何应对变慢的Redis-波动的响应延迟相似的内容:

[转帖]如何应对变慢的Redis-波动的响应延迟

Redis突然变慢了,如何排查呢 文章目录 问题认定应对方案Redis自身操作特性慢查询命令过期key操作 文件系统AOF解决方案 操作系统Swap内存大页 CheckList 问题认定 如何判断Redis是不是真的变慢了?通过Redis的响应延迟 大部分时候,Redis延迟很低,某些时刻,Redi

[转帖]perf学习-linux自带性能分析工具

存储技术为满足层出不穷应用的海量数据存储需求,从物理介质到技术架构也同样发生了天翻地覆的变革。无论技术如何更新换代,其目的都是为了更好的提供高性能,高容量,高可用的数据服务。本系列文章会对存储系统的测试和调试工具做一个介绍。 dd - Linux世界中的搬运工 FIO – IO压力测试工具 vdbe

[转帖]Intel PAUSE指令变化如何影响MySQL的性能

https://zhuanlan.zhihu.com/p/581200704 导读 x86、arm指令都很多,无论是应用程序员还是数据库内核研发大多时候都不需要对这些指令深入理解,但是 Pause 指令和数据库操作太紧密了,本文通过一次非常有趣的性能优化来引入对 Pause 指令的理解,期望可以事半

[转帖]shell命令替换~date用法~如果被替换命令的输出内容包括多行或有多个连续的空白符,输出变量时应该将变量用双引号包围

https://www.cnblogs.com/mianbaoshu/p/12069458.html Shell 命令替换是指将命令的输出结果赋值给某个变量。比如,将使用ls命令查看到的某个目录中的内容保存到某个变量中,这就需要使用命令替换。 Shell 中有两种方式可以完成命令替换,一种是反引号`

【转帖】JVM 元数据区的内存泄漏之谜

https://www.infoq.cn/article/Z111FLot92PD1ZP3sbrS 一、问题描述 某天,SRE 部门观察到一个非常重要的应用里面有一台服务器的业务处理时间(Transaction time)在某个时间点变为平时的 3 倍。虽然只持续了短暂的 2 秒,但是如果观察其一周

[转帖]s-systemtap工具使用图谱(持续更新)

整体的学习思维导图如下,后续持续更新完善文章目录​​安装​​​​简介​​​​执行流程​​​​执行方式​​​​stap脚本语法​​​​探针语法​​​​API函数​​​​探针举例​​​​变量使用​​​​基本应用​​​​1. 定位函数位置​​​​2. 查看文件能够添加探针的位置​​​​3. 打印函数参数(

[转帖]s-systemtap工具使用图谱(持续更新)

整体的学习思维导图如下,后续持续更新完善文章目录​​安装​​​​简介​​​​执行流程​​​​执行方式​​​​stap脚本语法​​​​探针语法​​​​API函数​​​​探针举例​​​​变量使用​​​​基本应用​​​​1. 定位函数位置​​​​2. 查看文件能够添加探针的位置​​​​3. 打印函数参数(

[转帖]TCP 半连接队列和全连接队列满了会发生什么?又该如何应对?

https://www.jianshu.com/p/072ed535b1dc 原文地址:TCP 半连接队列和全连接队列满了会发生什么? 一个端口上面的tcp连接创建,基本都只用一个线程处理。如果大并发连接请求过来,处理不了,那么会放入“待处理队列”。为什么不用多线程呢?因为创建连接基本都是内存操作,

[转帖]如何在CentOS 7上使用Barman备份,恢复和迁移PostgreSQL数据库

http://www.manongjc.com/detail/52-bdglcaimnhmjvkm.html 本文章向大家介绍如何在CentOS 7上使用Barman备份,恢复和迁移PostgreSQL数据库,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的

[转帖]如何理解 iowait

Linux中,%iowait 过高可能是个问题,严重的时候,它能使服务停止, 但问题是,多高才算高? 什么时候应该担心呢? 本文将讨论 iowait 的含义、相关的统计数据、原理以及 iowait的瓶颈问题 什么是 iowait Linux 中的解释 Show the percentage of t