Redis 系列 线程模型

开启 redis 探索新篇章

Posted by lichao modified on December 24, 2019

Redis 将所有数据都放在内存,用一个单线程对外提供服务,单个节点在跑满一个 CPU 核心的情况下可以达到了 10w/s 的超高 QPS。

Redis线程模型

Redis 内部使用文件事件处理器file event handler,这个文件事件处理器是单线程的,所以才称 Redis 为单线程模型。它采用 IO 多路复用机制同时监听多个 socket,将产生事件的 socket 压入内存队列中,事件分派器根据 socket 上的事件类型来选择对应的事件处理器进行处理。Redis 的单线程模型避免了线程切换和锁竞争的开销,并且Redis是内存数据库,这两者奠定了 Redis 高性能的基础。 存储概览

注:Redis6.0 引入了多线程,但是事件处理器还是单线程的。因为Redis主要的性能瓶颈在于IO而不是cpu,所以Redis6.0引入了多个IO线程。具体来讲就是事件处理器检测到读事件后,通过RR算法将这些事件分配给IO线程执行,此时IO线程与socket绑定,事件处理器阻塞等待读完毕。IO 线程读取完命令后交给事件处理器执行。事件处理器执行完毕将结果放到缓冲区。检测到可写事件后通知IO线程写,事件处理器阻塞等待。写完毕后IO线程解除与socket绑定。如下图所示。 多线程模型

非阻塞IO

采用 NIO 多路复用进行处理

指令队列

Redis 会将每个客户端套接字关联一个指令队列。客户端的指令通过队列来排队进行顺序处理,先到先服务。

响应队列

Redis 同样也会为每个客户端套接字关联一个响应队列。Redis 服务器通过响应队列来将指令的返回结果回复给客户端。 如果队列为空,那么意味着连接暂时处于空闲状态,不需要去获取写事件,也就是可以将当前的客户端描述符从 write_fds 里面移出来。等到队列有数据了,再将描述符放进去。避免 select 系统调用立即返回写事件,结果发现没什么数据可以写。出这种情况的线程会飙高 CPU。

定时任务

Redis 定时任务会记录在一个称为最小堆的数据结构中。这个堆中,最快要执行的任务排在堆的最上方。在每个循环周期,Redis 都会将最小堆里面已经到点的任务立即进行处理。处理完毕后,将最快要执行的任务还需要的时间记录下来,这个时间就是 select 系统调用的 timeout 参数。因为 Redis 知道未来 timeout 时间内,没有其它定时任务需要处理,所以可以安心睡眠 timeout 的时间。

参考文献

Redis事务详解