阻塞分析
客户端
复杂度高的增删改查操作
1、集合全量查询和聚合操作
2、bigkey 删除
3、清空数据库
磁盘
1、AOF 日志同步写
主从节点
1、从库接收 RDB 文件后、清空数据库、加载 RDB 文件;
切片集群
向其他实例传输哈希槽信息,数据迁移时遇到big key。
小结
关键路径:集合全量查询和聚合操作和从库加载 RDB 文件
非关键路径: bigkey 删除,清空数据库,以及 AOF 日志同步写。
解决方案
异步的子线程机制
Redis 主线程启动后,会使用操作系统提供的 pthread_create 函数创建 3 个子线程,分别负责 AOF 日志写操作、键值对删除以及文件关闭的异步执行。
主线程通过一个链表形式的任务队列和子线程进行交互。
- 当收到键值对删除和清空数据库的操作时,主线程会把这个操作封装成一个任务,放入到任务队列中,然后给客户端返回一个完成信息,表明删除已经完成(惰性删除)。
- 当 AOF 日志配置成 everysec 选项后,主线程会把 AOF 写日志操作封装成一个任务,也放到任务队列中。后台子线程读取任务后,开始自行写入 AOF 日志,这样主线程就不用一直等待 AOF 日志写完了。
异步的键值对删除和数据库清空操作是 Redis 4.0 后提供的功能。
之前的版本Big key删除可以先使用集合类型提供的 SCAN 命令读取数据,然后再进行删除。因为用 SCAN 命令可以每次只读取一部分数据并进行删除,这样可以避免一次性删除大量 key 给主线程带来的阻塞。
分批读取
集合全量查询和聚合操作:可以使用 SCAN 命令,分批读取数据,再在客户端进行聚合计算
控制RBD大小
从库加载 RDB 文件:把主库的数据量大小控制在 2~4GB 左右,以保证 RDB 文件能以较快的速度加载。