Redis学习笔记——异步机制:如何避免单线程模型的阻塞?

Posted qq_34132502

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis学习笔记——异步机制:如何避免单线程模型的阻塞?相关的知识,希望对你有一定的参考价值。

Redis 的网络 IO 和键值对读写是由主线程完成的,如果在主线程上执行的操作消耗的时间太长,就会引起主线程阻塞。但是,Redis 既有服务客户端请求的键值对增删改查操作,也有保证可靠性的持久化操作,还有进行主从复制时的数据同步操作,等等。操作这么多,究竟哪些会引起阻塞呢?

Redis实例有哪些阻塞点

与Redis交互的对象及其操作:

  • 客户端:网络 IO,键值对增删改查操作,数据库操作;
  • 磁盘:生成 RDB 快照,记录 AOF 日志,AOF 日志重写;
  • 主从节点:主库生成、传输 RDB 文件,从库接收 RDB 文件、清空数据库、加载 RDB 文件;
  • 切片集群实例:向其他实例传输哈希槽信息,数据迁移。

和客户端交互时的阻塞点

键值对的增删改查操作是 Redis 和客户端交互的主要部分,也是 Redis 主线程执行的主要任务。所以,复杂度高的增删改查操作肯定会阻塞 Redis。

那么,怎么判断操作复杂度是不是高呢?这里有一个最基本的标准,就是看操作的复杂度是否为 O ( N ) O(N) O(N)

所以集合全量查询和聚合操作是阻塞点。

在删除大量键值对数据(bigkey删除),释放大量内存时,也会阻塞主线程

同样的清空数据库也是一个阻塞点

和磁盘交互的阻塞点

因为生成 RDB 快照文件以及执行 AOF 日志重写操作都是是采用子进程的方式。所以慢速的磁盘 IO 就不会阻塞主线程了。

但是,Redis 直接记录 AOF 日志时,会根据不同的写回策略对数据做落盘保存。如果有大量的写操作需要记录在 AOF 日志中,并同步写回的话,就会阻塞主线程了。AOF 日志同步写是阻塞点。

主从节点交互时的阻塞点

主库在复制的过程中,创建和传输 RDB 文件都是由子进程来完成的,不会阻塞主线程。

如果需要清空数据库的话,这也是阻塞点。

清空完数据库之后,加载 RDB 文件时,RDB 文件越大,加载过程越慢,所以,加载 RDB 文件也是阻塞点。

切片集群实例交互时的阻塞点

如果使用了 Redis Cluster 方案,而且同时正好迁移的是 bigkey 的话,就会造成主线程的阻塞,因为 Redis Cluster 使用了同步迁移。

所以总共有五个阻塞点:

  • 集合全量查询和聚合操作;
  • bigkey 删除;
  • 清空数据库;
  • AOF 日志同步写;
  • 从库加载 RDB 文件。

哪些阻塞点可以异步执行

如果主线程并需要等待子线程返回的具体数据,那么它就是关键路径上的操作。

除了“集合全量查询和聚合操作”和“从库加载 RDB 文件”,其他三个阻塞点涉及的操作都不在关键路径上,所以,我们可以使用 Redis 的异步子线程机制来实现 bigkey 删除,清空数据库,以及 AOF 日志同步写。

因为集合全量查询和聚合操作、从库加载 RDB 文件是在关键路径上,无法使用异步操作来完成。对于这两个阻塞点:

  • 集合全量查询和聚合操作:可以使用 SCAN 命令,分批读取数据,再在客户端进行聚合计算;
  • 从库加载 RDB 文件:把主库的数据量大小控制在 2~4GB 左右,以保证 RDB 文件能以较快的速度加载。

异步的子线程机制

Redis 主线程启动后,会使用操作系统提供的 pthread_create 函数创建 3 个子线程,分别由它们负责 AOF 日志写操作、键值对删除以及文件关闭的异步执行。

主线程通过一个链表形式的任务队列和子线程进行交互。当收到键值对删除和清空数据库的操作时,主线程会把这个操作封装成一个任务,放入到任务队列中,然后给客户端返回一个完成信息,表明删除已经完成。

但实际上,这个时候删除还没有执行,等到后台子线程从任务队列中读取任务后,才开始实际删除键值对,并释放相应的内存空间。因此,我们把这种异步删除也称为惰性删除(lazy free)。此时,删除或清空操作不会阻塞主线程,这就避免了对主线程的性能影响。


Redis4.0之后,提供了新的命令执行键值对删除和数据库清空操作:

  • 键值对删除:当你的集合类型中有大量元素(例如有百万级别或千万级别元素)需要删除时,我建议你使用 UNLINK 命令。
  • 清空数据库:可以在 FLUSHDB 和 FLUSHALL 命令后加上 ASYNC 选项,这样就可以让后台子线程异步地清空数据库,如下所示:

以上是关于Redis学习笔记——异步机制:如何避免单线程模型的阻塞?的主要内容,如果未能解决你的问题,请参考以下文章

Redis 多线程网络模型全面揭秘

python学习笔记4-redis multi watch实现锁库存

API的理解和使用——单线程架构

redis 单线程

Redis 6.0引入的多线程机制简介

纯干货|深度解析Redis线程模型设计原理