首页 - 信息 - 三万字介绍Redis是什么(4)

三万字介绍Redis是什么(4)

2023-09-29 09:34

大家好,我是Leo

继上篇文章Redis技术总结三,我们继续聊聊Redis相关技术!

我们在上一篇文章中介绍了

  1. 主要介绍Redis类型的底层实现和技术,以及类型选择的依据
  2. 通过时间序列数据介绍各类使用思路,拓展RedisTimeSeries模块的使用。
  3. Redis作为消息队列也是面试常见问题。这道题延伸了List的优缺点和Streams的应用

本文主要介绍Redis中阻塞的原因

推荐阅读

30,000 字介绍 MySQL 是什么

30,000 字介绍 Redis 是什么 (1)

30,000 字介绍 Redis 是什么 (2)

30,000 字介绍 Redis 是什么 (3)

单线程模型阻塞

说到阻塞的原因,这应该是单线程的噩梦。在日常使用中,想要了解Redis阻塞的原因,就要从它的交互对象开始。下面我列出了Redis常见的交互场景

  • 客户
  • 磁盘
  • 主从节点
  • 切片集群实例

客户

客户端主要有网络IO开销,键值对增删改查操作,数据库操作等。

Redis 使用 IO 复用机制来防止主线程等待网络连接或请求到达,因此网络 IO 并不是导致 Redis 阻塞的因素。

查询:键值对查询,可以通过时间复杂度来判断。使用集合类型时,一般时间复杂度为O(n)。因此,集合类型的列表查询和聚合统计操作将是Redis的第一个阻塞点。

删除:删除也是Redis阻塞的重要因素之一。很多人不明白,删除是指直接删除指针的索引吗?事实上,事实并非如此。它与MySQL 有点不同。为了保证Redis中高效的内存管理,操作系统需要将释放的内存插入到空闲内存块中,以便后续管理和分配。因此,如果一次性释放大量内存,就会降低插入空闲内存块的效率。这也可以称为bigkey删除,这也是第二个阻塞点

数据库:如果说删除bigkey是阻塞Redis的因素之一,那么清除数据库也是第三个阻塞点

磁盘

带磁盘,主要生成RDB快照并保存在本地,记录AOFlog、AOFlog重写等。

Redis 意识到磁盘 IO 带来的阻塞影响,因此它使用子线程生成 RDB 快照并使用子线程执行 AOF 重写操作。

唯一的阻碍点是Redis在记录AOF日志时,会根据不同的写入策略来保存数据。 AOF日志同步写入

主从节点

与从库数据同步的主要目的是主库需要生成RDB快照并发送给从库,从从库接收,从从库清除数据库,加载RDB文件等等

通过子线程生成RDB不会阻塞。上面已将清除数据库列为阻塞点。主从节点主要讲加载RDB文件。如果RDB文件太大,也会阻塞。所以加载RDB文件就成了阻塞点之一

切片集群实例

切片集群的主要目的是查询一条数据。如果当前数据不在本实例上,则将哈希槽信息转移到其他实例上进行数据迁移。哈希槽中的信息量不会太大,数据迁移也不会太大。这是渐进的。因此,哈希槽和数据迁移对Redis阻塞影响不大。

但是,如果使用Redis Cluster方案,同时迁移bigkey,就会造成阻塞。

调整计划

如何调音?我们可以将所有不需要等待的操作改为异步执行。

大型查询和聚合查询显然必须完成才能继续,所以这是无法调优的。我们只能从数据类型入手,或者使用其他解决方案。

Bigkey和清库不需要等待返回才继续,所以这两个阻塞点可以优化为异步执行。

加载RDB文件时,必须等待以确保从数据库接收数据完成。严格来说,从库会向主库发送ack消息。

AOF日志同步写入也可以异步操作。它不需要将结果返回到实例。

子螺纹机构

上面我们谈到了五个阻塞点。所有三个阻塞点都可以异步优化Redis 的整体性能。我们来说一下子线程机制。

Redis主线程启动后,会使用操作系统提供的pthread_create函数创建三个子线程。它们负责同步写入 AOF 日志、bigkey 删除、清除数据库以进行异步执行。 (下图来自蒋德君老师)

客户端请求Redis实例。 Redis通过链表存储一系列异步任务。任务列表与子线程交互,异步执行AOF日志同步写入、bigkey删除、文件关闭(清空数据库)操作。

Redis 会立即将执行完成返回给客户端。表示删除已经完成。

CPU结构阻碍Redis性能

很多人在谈论CPU时都会感到困惑。他们问为什么CPU会影响性能?

对不起大家,我实在是不懂CPU类的相关知识。光有计算机组成原理还不够。这些知识我们稍后会输出!

Redis 变慢排查思路

Redis 突然变慢,你会如何排查?一定不要急于求医,因为代码就像自来水。一块已修补,另一块缺失。最后坑可能会越来越大

咱们言归正传吧!

第一步,检查Redis的响应延迟。大多数 Redis 延迟非常低,但某些实例的延迟非常高。

Redis 的延迟与硬件有很大关系,

第二步,根据当前环境下的Redis基线进行判断。所谓基线性能,就是系统在低压、无干扰的情况下的基本性能。这个性能只能由当前的软件和硬件来决定。

我们可以使用redis-cli命令提供的intrinsic-latency选项来监控和统计测试期间的最大延迟。该延迟可以用作基准性能。

第三步,使用iPef等工具测试客户端到服务器的网络延迟。如果延迟为几十毫秒甚至上百毫秒,则说明Redis运行的网络环境中有大量其他应用程序的流量。程序正在运行并导致阻塞

如何解决Redis速度变慢

Redis变慢应该是T0级事故。为什么这么说?

Redis一旦出现延迟,将会在业务系统中引起一系列的连锁反应。让我们举个例子。

我目前负责的千万级跨境电商中,使用Redis访问来生成订单号。我的逻辑是今天的第一笔订单,当Redis中没有定义当前日期的key时,我会在程序中通过当前时间戳+雪花算法+随机函数+当天的订单数生成一串数字并写入到Redis。

下次生成订单号时,如果当前订单号存在于Redis中,则直接获取该值,并执行incrdy命令将其加1。示例如下。

订单号:2021120121523033473

如果Redis阻塞或延迟,订单系统就无法正常提供服务,因为它必须等待订单号插入数据表。积分模块、用户模块、信息通知模块、产品库存模块都会受到多付或少付的影响。

那么如何解决Redis速度变慢的问题呢?我们需要了解Redis本身的工作原理,并结合与其交互的操作系统机制,然后利用一些辅助工具来定位原因,然后指定有效的解决方案。

自我影响

无论做什么,先反省一下自己!

Redis中的慢查询会导致实例延迟,例如查询数据量较大的集合列表。请求量不大的话还可以。一旦请求量很大,就必须优化操作命令。

有两种解决方案

  • 替换为其他高效命令
  • 执行列表聚合统计时,为了不影响整个系统,可以选择在客户端执行。

按键命令

尽量少用keys命令,因为它需要遍历存储的键值对,所以操作延迟较高。一般不建议在生产环境中使用keys命令。

按键操作过期

说到过期key,我们先来了解一下Redis的过期删除机制

过期删除机制是Redis回收内存空间的常用机制。它可以设置键值对的过期时间。默认情况下,Redis 会每 100 毫秒删除一些过期的键。具体算法如下:

  • 采样ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP数量的key并删除所有过期的key;
  • 如果超过 25% 的密钥已过期,则会重复删除过程,直到过期密钥的比例降至 25% 以下。

ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 默认为20。毫秒的概念可能不太明显。我们将其转换为每秒删除 200 个过期密钥(20/100 毫秒)=(200/秒)

如果按照第一种方法,不会有太大影响。如果击中第二种,就会导致大面积的密钥失效。如果过期密钥超过25%,它们将被删除,直到下降到25%。在删除期间,会释放大量的内存空间,并插入大量的链表来填充。 Redis 变得更慢。