单线程的 Redis 为什么那么快
Redis 服务器端只需要单线程可以达到非常高的处理能力,每秒可以达到数万 QPS 的高处理能力。如此高性能的程序其实就是对 Linux 提供的多路复用机制 epoll 的一个较为完美的运用而已。
在 Redis 源码中,核心逻辑其实就是两个,一个是 initServer 启动服务,另外一个就是 aeMain 事件循环。把这两个函数弄懂了,Redis 就吃透一大半了。
//file: src/server.c
int main(int argc, char **argv) {
......
// 启动初始化
initServer();
// 运行事件处理循环,一直到服务器关闭为止
aeMain(server.el);
}
在 initServer 这个函数内,Redis 做了这么三件重要的事情。
创建一个 epoll 对象
对配置的监听端口进行 listen
把 listen socket 让 epoll 给管理起来
在 aeMain 函数中,是一个无休止的循环,它是 Redis 中最重要的部分。在每一次的循环中,要做的事情可以总结为如下图。
通过 epoll_wait 发现 listen socket 以及其它连接上的可读、可写事件
若发现 listen socket 上有新连接到达,则接收新连接,并追加到 epoll 中进行管理
若发现其它 socket 上有命令请求到达,则读取和处理命令,把命令结果写到缓存中,加入写任务队列
每一次进入 epoll_wait 前都调用 beforesleep 来将写任务队列中的数据实际进行发送
其实事件分发器还处理了一个不明显的逻辑,那就是如果 beforesleep 在将结果写回给客户端的时候,如果由于内核 socket 发送缓存区过小而导致不能一次发送完毕的时候,也会注册一个写事件处理器。等到 epoll_wait 发现对应的 socket 可写的时候,再执行 write 写处理。