影响 Redis 性能的 5 大方面
- Redis 内部的阻塞式操作;
- CPU 核和 NUMA 架构的影响;
- Redis 关键系统配置;
- Redis 内存碎片;Redis 缓冲区。
Redis 实例有哪些阻塞点?
和 Redis 交互时会发生的操作
- 客户端:网络 IO,键值对增删改查操作,数据库操作;
- 磁盘:生成 RDB 快照,记录 AOF 日志,AOF 日志重写;
- 主从节点:主库生成、传输 RDB 文件,从库接收 RDB 文件、清空数据库、加载 RDB 文件;
- 切片集群实例:向其他实例传输哈希槽信息,数据迁移。
会引起阻塞的操作
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 日志写操作
- 键值对删除
- 文件关闭
异步的键值对删除和数据库清空操作是 Redis 4.0 后提供
- 键值对删除:当你的集合类型中有大量元素(例如有百万级别或千万级别元素)需要删除时,建议使用 UNLINK 命令。
- 清空数据库:可以在 FLUSHDB 和 FLUSHALL 命令后加上 ASYNC 选项,这样就可以让后台子线程异步地清空数据库
小结
集合全量查询和聚合操作、从库加载 RDB 文件是在关键路径上,无法使用异步操作来完成。对于这两个阻塞点,两个小建议
- 集合全量查询和聚合操作:可以使用 SCAN 命令,分批读取数据,再在客户端进行聚合计算;
- 从库加载 RDB 文件:把主库的数据量大小控制在 2~4GB 左右,以保证 RDB 文件能以较快的速度加载。
感悟
Reids 用 队列 让同步、异步切换的风生水起