文章目录
Redis学习笔记-避免Redis单线程阻塞
我们都知道 Redis
中的增删改查操作使用的是单线程模型(对于读写操作,Redis 6.0
也是单线程),既然 Redis
是单线程就需要注意其潜在阻塞点,这篇文章学习一下 Redis
有哪些可能造成单线程阻塞的原因,这样可以提前避免性能问题。
1.笔记图
2.影响 Redis 性能的因素
- 内部阻塞操作
CPU
内核和NUMA
架构Redis
关键系统配置Redis
内存碎片Redis
缓冲区
3.和 Redis 实例的交互方式
-
客户端:网络
IO
,键值对增删改查操作,数据库操作 -
磁盘:生成
RDB
快照,记录AOF
日志,AOF
日志重写 -
主从节点:主库生成、传输
RDB
文件,从库接收RDB
文件、清空数据库、加载RDB
文件 -
切片集群实例:向其他实例传输哈希槽信息,数据迁移
4.Redis 潜在阻塞点
-
和客户端交互时的阻塞点:
-
第一个阻塞点:集合全量查询和聚合操作,如
HGETALL
、SMEMBERS
,其原因是一次性操作数据量大的聚合操作会阻塞Redis
的主线程,导致其他操作无法进行
-
第二个阻塞点:删除占用内存较大的键值对,如
del key
(删除bigkey
),其原因是删除元素操作时,操作系统需要把释放掉的内存块插入一个空闲内存块的链表,以便后续进行管理和再分配,若一次性释放大量的内存,会导致空闲内存块链表操作时间增加,阻塞Redis
主线程 -
第三个阻塞点:清空数据,当删除所有键值对,需要释放内存空间,这个过程会阻塞
Redis
主线程 -
和磁盘交互时的阻塞点:
AOF
日志同步写,其原因是AOF
日志采用同步写回策略时,若有大量写入会阻塞Redis
主线程(而生成RDB
快照采用的是子进程不会阻塞Redis
主线程) -
主从节点交互时的阻塞点:从库在第一次全量同步的时候需要清空当前所有数据,从库同步主库的
RDB
快照文件,清空数据删除所有键值对,需要释放内存空间,这个过程会阻塞Redis
主线程,加载的主库RDB
快照文件越大,从库Redis
主线程阻塞时间越长 -
切片集群实例交互时的阻塞点:
Redis Cluster
集群中迁移bigkey
,如果使用了Redis Cluster
方案,且同时正好迁移的是bigkey
的话,就会造成主线程的阻塞
5.潜在阻塞点优化(执行异步操作)
5.1 关键路径上的操作
客户端把请求发送给 Redis
后,等着 Redis
返回数据结果的操作,不适合使用异步操作
- 操作
A
并不用给客户端返回具体的数据,主线程可以把它交给后台子线程来完成,可以使用异步操作 - 操作
B
需要把结果返回给客户端,它就是关键路径上的操作,不适合使用异步操作 - 读操作:典型的关键路径操作,因为客户端发送了读操作之后,就会等待读取的数据返回,它不适合使用异步操作
- 从库加载 RDB 文件:从库要想对客户端提供数据存取服务,就必须把
RDB
文件加载完成,必须让从库的主线程来执行
5.2 非关键路径上的操作
- 删除元素:删除操作并不需要给客户端返回具体的数据结果,所以不算是关键路径操作,可以使用异步操作,若要异步删除键值对,可使用
UNLINK
命令 - 清空数据操作:清空数据不需要返回给客户端结果,可以使用异步操作
- AOF日志同步写回策略:它并不会返回具体的数据结果,可以使用异步操作
6.异步子线程机制
-
Redis
主线启动后,会使用操作系统提供的pthread_create
函数创建3
个子线程,分别负责AOF
日志写操作、键值对删除、文件关闭的异步执行 -
主线程通过一个链表形式的任务队列和子线程进行交互
-
键值对删除:若要异步删除键值对,可使用
UNLINK
命令 -
清空数据库:可以在
FLUSHDB
和FLUSHALL
命令后加上ASYNC
选项:
FLUSHDB ASYNC
FLUSHDB ASYNC
扫码关注