学习总结录 学习总结录
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
  • Java基础

  • Java集合

  • MySQL

  • Redis

    • Redis核心技术01-基础数据结构
    • Redis核心技术02-线程IO模型
    • Redis核心技术03-持久化
    • Redis核心技术04-数据同步
    • Redis核心技术05-哨兵机制
    • Redis核心技术06-哨兵集群
    • Redis核心技术07-切片集群
    • Redis核心技术08-String
    • Redis核心技术09-keys统计案例与方案
    • Redis核心技术10-GEO
    • Redis核心技术11-时间序列数据存储
    • Redis核心技术12-消息队列
    • Redis核心技术13-异步机制
    • Redis核心技术14-CPU结构对Redis性能影响
    • Redis核心技术15-应对变慢的Redis
      • Redis核心技术15-应对变慢的Redis
      • 如何确定Redis真的变慢?
      • 如何应对Redis变慢
        • Redis自身操作特性的影响
        • 文件系统
        • 内存系统
      • 参考
    • Redis核心技术16-删除数据后内存占用率还是很高
    • Redis核心技术17-缓冲区
    • Redis核心技术18-Redis缓冲是如何工作的
    • Redis核心技术19-缓冲替换策略
    • Redis核心技术20-缓冲异常
    • Redis核心技术21-缓存污染
    • Redis核心技术22-无锁原子操作
    • Redis核心技术23-分布式锁
    • Redis核心技术24-事务机制
    • Redis核心技术25-主从同步与故障切换的坑
    • Redis核心技术26-脑裂问题
    • Redis核心技术27-Redis在秒杀场景的关键技术
  • JVM

  • 多线程

  • 计算机网络

  • Spring

  • Kafka

  • Elasticsearch

  • Python

  • 面试专题

  • 知识库
  • Redis
旭日
2023-03-31
目录

Redis核心技术15-应对变慢的Redis

# Redis核心技术15-应对变慢的Redis

现在假设应用服务器(App Server)要完成一个事务性操作,包括在 MySQL 上执行一个写事务,在 Redis 上插入一个标记位,并通过一个第三方服务给用户发送一条完成消息。

这三个操作需要保证事务原子性,如果Redis的延迟增加,就会拖累整个事务的执行。而事务完成不了,又会导致MySQL上写事务占用的资源无法释放,进而导致MySQL的其他请求被阻塞。因此,Redis的变慢会导致一系列的连锁反应。

image-20220817094002170

# 如何确定Redis真的变慢?

方法一:查看Redis的响应延迟

当发现Redis命令的执行时间突然增长到了几秒,基本就可以判断Redis变慢了。

方法二:基于当前环境下的 Redis 基线性能做判断

所谓的基线性能呢,也就是一个系统在低压力、无干扰下的基本性能,这个性能只由当前的软硬件配置决定。

redis-cli 命令提供了–intrinsic-latency 选项,可以用来监测和统计测试期间内的最大延迟,这个延迟可以作为 Redis 的基线性能。

./redis-cli --intrinsic-latency 120

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

# 如何应对Redis变慢

image-20220817094923908

针对Redis架构图,主要从Redis自身的操作特性、文件系统和操作系统进行分析,并提供相应的方案。

# Redis自身操作特性的影响

慢查询命令

慢查询命令,就是指在 Redis 中执行速度慢的命令,这会导致 Redis 延迟增加。不同的操作指令复杂度不同,因此我们需要对某一些复杂的操作指令进行处理。

  • 用其他高效命令代替。比如说,如果你需要返回一个 SET 中的所有成员时,不要使用 SMEMBERS 命令,而是要使用 SSCAN 多次迭代返回,避免一次返回大量数据,造成线程阻塞。
  • 需要执行排序、交集、并集操作时,可以在客户端完成,而不要用 SORT、SUNION、SINTER 这些命令,以免拖慢 Redis 实例。

KEYS指令它用于返回和输入模式匹配的所有 key,因为 KEYS 命令需要遍历存储的键值对,所以操作延时高,所以一般不被建议用于生产环境中。

过期key操作

过期key的自动删除机制是Redis用来回收内存空间的常用机制,它本身就会引起Redis操作阻塞,导致性能变慢。

Redis 键值对的 key 可以设置过期时间。默认情况下,Redis 每 100 毫秒会删除一些过期 key,具体的算法如下:

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

ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 是 Redis 的一个参数,默认是 20,那么,一秒内基本有 200 个过期 key 会被删除。

但是算法的第二条,Redis 就会一直删除以释放内存空间,而删除操作是阻塞的,Redis线程一直执行删除,就没办法正常服务其他的键值操作了,就会进一步引起其他键值操作的延迟增加,Redis 就会变慢。

而算法的第二条就是因为频繁使用带有相同时间参数的EXPIREAT 命令设置过期 key,这就会导致,在同一秒内有大量的 key 同时过期。

# 文件系统

为了保证数据可靠性,Redis采用AOF 日志或 RDB 快照。其中,AOF 日志提供了三种日志写回策略:no、everysec、always。这三种写回策略依赖文件系统的两个系统调用完成,也就是 write 和 fsync。

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

image-20220817103650914

  • 对于everysec:Redis 允许丢失一秒的操作记录,所以,Redis 主线程并不需要确保每个操作记录日志都写回磁盘。而且,fsync 的执行时间很长,如果是在 Redis 主线程中执行 fsync,就容易阻塞主线程。所以,当写回策略配置为 everysec 时,Redis 会使用后台的子线程异步完成 fsync 的操作。
  • 对于always:Redis 需要确保每个操作记录日志都写回磁盘,如果用后台子线程异步完成,主线程就无法及时地知道每个操作是否已经完成了,这就不符合 always 策略的要求了。所以,always 策略并不使用后台子线程来执行。

另外AOF 重写会对磁盘进行大量 IO 操作,同时,fsync 又需要等到数据写到磁盘后才能返回,所以,当 AOF 重写的压力比较大时,就会导致 fsync 被阻塞。

当主线程使用后台子线程执行了一次 fsync,需要再次把新接收的操作记录写回磁盘时,如果主线程发现上一次的 fsync 还没有执行完,那么它就会阻塞。所以,如果后台子线程执行的 fsync 频繁阻塞的话(比如 AOF 重写占用了大量的磁盘 IO 带宽),主线程也会阻塞,导致 Redis 性能变慢。

针对上述情况,如果对数据可靠性要求不高,允许一定量的数据丢失,可以把配置项 no-appendfsync-on-rewrite 设置为 yes。


no-appendfsync-on-rewrite yes

这个配置项设置为 yes 时,表示在 AOF 重写时,不进行 fsync 操作。也就是说,Redis 实例把写命令写到内存后,不调用后台线程进行 fsync 操作,就可以直接返回了。当然,如果此时实例发生宕机,就会导致数据丢失。反之,如果这个配置项设置为 no(也是默认配置),在 AOF 重写时,Redis 实例仍然会调用后台线程进行 fsync 操作,这就会给实例带来阻塞。

# 内存系统

swap

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

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

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

而应对这个问题最好的方案就是增加机械的内存。

内存大页面

虽然内存大页可以给 Redis 带来内存分配方面的收益,但是由于Redis会把数据进行持久化操作,客户端的写请求可能会修改正在执行持久化的数据。Redis在这一过程中,会采用写时复制机制,也就是说,一旦有数据要被修改,Redis 并不会直接修改内存中的数据,而是将这些数据拷贝一份,然后再进行修改。

但是这因为如此,如果采用了内存大页,那么,即使客户端请求只修改 100B 的数据,Redis 也需要拷贝 2MB 的大页。也就是说内存机制将导致大量的拷贝,这就会影响 Redis 正常的访存操作,最终导致性能变慢。所以在实际生产环境中,建议不要使用内存大页机制。

# 参考

Redis核心技术与实战 (opens new window)

#Redis
上次更新: 2024/06/29, 15:13:44
Redis核心技术14-CPU结构对Redis性能影响
Redis核心技术16-删除数据后内存占用率还是很高

← Redis核心技术14-CPU结构对Redis性能影响 Redis核心技术16-删除数据后内存占用率还是很高→

最近更新
01
基础概念
10-31
02
Pytorch
10-30
03
Numpy
10-30
更多文章>
Theme by Vdoing | Copyright © 2021-2024 旭日 | 蜀ICP备2021000788号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式