Redis 堵塞式操作

本文将介绍 Redis 中的堵塞式操作。

一、交互点

Redis 实例在运行时,需要和许多对象进行交互,这些交互点往往会发生阻塞。

列举交互点如下:

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

二、堵塞式操作

1. 客户端交互 - 网络 IO

Redis 使用了 IO 多路复用机制,避免了堵塞处理网络请求。因此,网络 IO 不是导致 Redis 堵塞的原因。

2. 客户端交互 - 键值对增删改查

  • 复杂度高的命令:在 Redis 中,集合全量查询和聚合操作的操作复杂度为 O(N),会导致堵塞

  • 大键值对的删除:在 Redis 中,大集合的删除操作会导致堵塞

    删除的本质是释放键值对占用的内存空间。对于操作系统来说,为了更加高效地管理内存空间,在应用程序释放内存时,需要把释放掉的内存块插入空闲内存块链表中,以便后续进行管理和再分配。这个过程需要一定时间,并且会堵塞当前应用程序。

    Redis 4.0 提供了 UNLINK 命令用于异步删除键值对

3. 客户端交互 - 数据库操作

清空数据库涉及到删除和释放所有的键值对,因此可能和 “客户端交互 - 键值对增删改查 - 大键值对的删除” 一样导致堵塞。

Redis 4.0 提供了 SLUSHALL ASYNC 命令用于异步清空数据库

4. 磁盘交互

Redis 支持非堵塞式生成 RDB 快照、记录 AOF 日志和 AOF 日志重写,但其中的 fork() 操作也会堵塞主线程。

5. 主从集群交互 - 加载 RDB

对于从库而言,需要首先清空当前数据库,该操作是 “客户端交互 - 数据库操作 - 清空数据库”,会导致堵塞。

此外,加载 RDB 时需要将其加载到内存中,这个过程的快慢和 RDB 文件的大小相关,会造成主线程堵塞。

6. 切片集群交互 - 数据迁移

Redis Cluster 使用了同步迁移的方案,如果迁移大键值对,会造成主线程堵塞。

参考