文章对Redis线程模型、文件事件处理器做了简要总结。
Redis线程模型
Redis基于Reactor模式开发了自己的网络事件处理器:这个处理器被称为文件事件处理器。
它的组成结构为4部分:多个套接字、IO多路复用程序、文件事件分派器、事件处理器。因为文件事件分派器队列的消费是单线程的,所以Redis才叫单线程模型。
消息处理过程
- 文件事件处理器使用I/O多路复用(multiplexing)程序来同时监听多个套接字,并根据套接字目前执行的任务来为套接字关联不同的事件处理器。
- 当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。
文件事件是对套接字操作的抽象, 每当一个套接字准备好执行连接应答(accept)、写入、读取、关闭等操作时, 就会产生一个文件事件。 因为一个服务器通常会连接多个套接字, 所以多个文件事件有可能会并发地出现。
I/O 多路复用程序负责监听多个套接字, 并向文件事件分派器传送那些产生了事件的套接字。
尽管多个文件事件可能会并发地出现,但I/O多路复用程序总是会将所有产生事件的套接字都推到一个队列里面,然后通过这个队列,以有序、同步、每次一个套接字的方式向文件事件分派器传送套接字:当上一个套接字产生的事件被处理完毕之后, I/O多路复用程序才会继续向文件事件分派器传送下一个套接字。
文件事件处理器
I/O 多路复用程序可以监听多个套接字的 ae.h/AE_READABLE 事件和 ae.h/AE_WRITABLE 事件。如果一个套接字又可读又可写的话, 那么服务器将先读套接字, 后写套接字。
服务器最常用的要数与客户端进行通信的连接应答处理器、 命令请求处理器和命令回复处理器。
客户端与服务器连接事件示例
当 Redis 服务器进行初始化的时候, 程序会将这个连接应答处理器和服务器监听套接字的 AE_READABLE 事件关联起来。
当有客户端用 sys/socket.h/connect 函数连接服务器监听套接字的时候, 套接字就会产生 AE_READABLE 事件, 引发连接应答处理器执行, 并执行相应的套接字应答操作。
当一个客户端通过连接应答处理器成功连接到服务器之后, 服务器会将客户端套接字的 AE_READABLE 事件和命令请求处理器关联起来, 当客户端向服务器发送命令请求的时候, 套接字就会产生 AE_READABLE 事件, 引发命令请求处理器执行, 并执行相应的套接字读入操作。
当服务器有命令回复需要传送给客户端的时候, 服务器会将客户端套接字的 AE_WRITABLE 事件和命令回复处理器关联起来, 当客户端准备好接收服务器传回的命令回复时, 就会产生 AE_WRITABLE 事件, 引发命令回复处理器执行, 并执行相应的套接字写入操作。
Redis高性能的三个因素
- 纯内存存储
- 非阻塞I/O:采用epoll作为IO多路复用技术的实现,同时Redis内部采用事件处理模型,将连接、读写转换为了事件,不会在IO上浪费过多事件。
- 单线程架构,避免线程切换与竞态条件引发的消耗
- 采用C语言实现
由于单线程架构,每个命令需要快速执行完,否则可能会阻塞Redis,对于复杂度高的命令keys、hgetall、sembers、zrange等操作,需要考虑数据规模的影响。
参考资料
- http://redisbook.com/preview/event/file_event.html
- https://www.jianshu.com/p/8f2fb61097b8