1. 和客户端交互时的阻塞点
- Redis通过IO多路复用,避免了主线程等待请求(网络IO不是阻塞原因)
- 复杂度高的怎删改查操作会阻塞Redis
- 集合全量查询操作(HGETALL,SMEMBERS),聚合统计
- bigkey删除(释放的内存快放入空闲内存块链表)
- 清空数据库
2. 和磁盘交互时的阻塞点
- AOF日志同步写
3. 主从节点交互时的阻塞点
- 加载 RDB 文件就成为了 Redis 的第五个阻塞点。
4. 异步的子线程机制
- Redis 主线程启动后,会使用操作系统提供的 pthread_create 函数创建 3 个子线程,分别由它们负责 AOF 日志写操作、键值对删除以及文件关闭的异步执行。
- 主线程通过一个链表形式的任务队列和子线程进行交互。当收到键值对删除和清空数据库的操作时,主线程会把这个操作封装成一个任务,放入到任务队列中,然后给客户端返回一个完成信息,表明删除已经完成。(惰性删除)
- 当 AOF 日志配置成 everysec 选项后,主线程会把 AOF 写日志操作封装成一个任务,也放到任务队列中。后台子线程读取任务后,开始自行写入 AOF 日志,这样主线程就不用一直等待 AOF 日志写完了。
- 键值对删除可以使用 UNLINK命令
- 清空数据库在FLUSHDB和FLUSHALL 加上ASYNC选项,子线程异步删除
- lazy-free是4.0新增的功能,但是默认是关闭的,需要手动开启。
- 手动开启lazy-free时,有4个选项可以控制,分别对应不同场景下,要不要开启异步释放内存机制:
a) lazyfree-lazy-expire:key在过期删除时尝试异步释放内存
b) lazyfree-lazy-eviction:内存达到maxmemory并设置了淘汰策略时尝试异步释放内存
c) lazyfree-lazy-server-del:执行RENAME/MOVE等命令或需要覆盖一个key时,删除旧key尝
试异步释放内存
精选留言 (45)
d) replica-lazy-flush:主从全量同步,从库清空数据库时异步释放内存 - 即使开启了lazy-free,如果直接使用DEL命令还是会同步删除key,只有使用UNLINK命令
才会可能异步删除key。 - 除了replica-lazy-flush之外,其他情况都只是可能去异步释放key的内存,并不是每次必定异步释放内存的。
- 开启lazy-free后,Redis在释放一个key的内存时,首先会评估代价,如果释放内存的代价很
小,那么就直接在主线程中操作了,没必要放到异步线程中执行(和key的类型、编码方式、元素数量都有关系) - a) 当Hash/Set底层采用哈希表存储(非ziplist/int编码存储)时,并且元素数量超过64个
b) 当ZSet底层采用跳表存储(非ziplist编码存储)时,并且元素数量超过64个
c) 当List链表节点数量超过64个(注意,不是元素数量,而是链表节点的数量,List的实现是
在每个节点包含了若干个元素的数据,这些元素采用ziplist存储) - String(不管内存占用多大)、List(少量元素)、Set(int编码存储)、Hash/ZSet(ziplist编码存储)这些情况下的key在释放内存时,依旧在主线程中操作。
- 开启lazy-free后,Redis在释放一个key的内存时,首先会评估代价,如果释放内存的代价很
CPU对redis的影响
单 CPU
多 CPU Socket 架构
非统一内存访问架构(Non-Uniform Memory Access,NUMA 架构):在多 CPU 架构下,一个应用程序访问所在 Socket 的本地内存和访问远端内存的延迟并不一致。
- 将redis实例绑定一个CPU核,可以减少redis在不同核的切换
taskset -c 0 ./redis-server
将redis实例绑定在0号核上。
- 为了提升 Redis 的网络性能,把操作系统的网络中断处理程序和 CPU 核绑定。这个做法可以避免网络中断处理程序在不同核上来回调度执行,的确能有效提升 Redis 的网络处理性能。
- 如果网络中断处理程序和 Redis 实例各自所绑的 CPU 核不在同一个CPU Socket 上,那么,Redis 实例读取网络数据时,就需要跨 CPU Socket 访问内存,这个过程会花费较多时间。
- 在 CPU 的 NUMA 架构下,对 CPU 核的编号规则,并不是先把一个CPU Socket 中的所有逻辑核编完,再对下一个 CPU Socket 中的逻辑核编码,而是先给每个 CPU Socket 中每个物理核的第一个逻辑核依次编号,再给每个 CPU Socket 中的物理核的第二个逻辑核依次编号。
绑核的风险和解决方案
- 当我们把 Redis 实例绑到一个 CPU 逻辑核上时,就会导致子进程、后台线程和 Redis 主线程
竞争 CPU 资源,一旦子进程或后台线程占用 CPU 时,主线程就会被阻塞,导致 Redis 请求
延迟增加。- 一个 Redis 实例对应绑一个物理核
- 优化 Redis 源码(把子进程和后台线程绑到不同的 CPU 核上)
+