16 | 异步机制:如何避免单线程模型的阻塞?

极客时间 | 《Redis核心技术与实战》学习笔记目录

原文

影响 Redis 性能的 5 大方面

  • Redis 内部的阻塞式操作;
  • CPU 核和 NUMA 架构的影响;
  • Redis 关键系统配置;
  • Redis 内存碎片;Redis 缓冲区。

Redis 实例有哪些阻塞点?

和 Redis 交互时会发生的操作

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

image

会引起阻塞的操作

1:集合全量查询和聚合操作(客户端交互)

  • 复杂度高的增删改查操作肯定会阻塞 Redis
    • 基本标准:操作复杂度为 O(N)
    • Redis 中涉及集合的操作复杂度通常为 O(N)
      • 例如集合元素全量查询操作 HGETALL、SMEMBERS
      • 集合的聚合统计操作,例如求交、并和差集
      • 集合自身的删除操作同样也有潜在的阻塞风险

2:bigkey 删除操作(客户端交互)

  • bigkey 删除:删除包含了大量元素的集合
  • 为了更加高效地管理内存空间,在应用程序释放内存时,操作系统需要把释放掉的内存块插入一个空闲内存块的链表,以便后续进行管理和再分配。这个过程本身需要一定时间,而且会阻塞当前释放内存的应用程序,所以,如果一下子释放了大量内存,空闲内存块链表操作时间就会增加,相应地就会造成 Redis 主线程的阻塞。

3:清空数据库(客户端交互)

  • FLUSHDB 和 FLUSHALL 操作
  • 涉及到删除和释放所有的键值对

4:AOF 日志同步写(磁盘相关)

5:加载 RDB 文件(主从节点交互)

切片集群实例交互时也可能产生阻塞点

哪些阻塞点可以异步执行?

不是关键路径上的操作可以异步执行

  • 关键路径:必须立刻返回结果的操作(不得到结果,客户端会一直等待)
  • 读操作是典型的关键路径操作

关键路径

  • 集合全量查询和聚合操作
  • 从库加载 RDB 文件

非关键路径

  • bigkey 删除操作
  • 清空数据库
  • AOF 日志同步写

异步的子线程机制

Redis 主线程启动后,会使用操作系统提供的 pthread_create 函数创建 3 个子线程,分别异步执行

  • AOF 日志写操作
  • 键值对删除
  • 文件关闭

image

异步的键值对删除和数据库清空操作是 Redis 4.0 后提供

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

小结

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

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

感悟

Reids 用 队列 让同步、异步切换的风生水起

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus