Redis高性能IO模型

Redis高性能IO模型

关于Redis单线程

Redis的网络IO和键值对读写都是由一个线程来完成的,这也是Redis对外提供键值服务的主要流程。但Redis的其他功能,比如:持久化、异步删除、集群数据同步等功能都需要额外的线程去完成。

为什么Redis要使用单线程

多线程下会有共享资源并发访问控制问题,会给系统带来额外的开销,从而无法提高系统的吞吐率。

基本IO模型

以 Get 请求为例,SimpleKV 为了处理一个 Get 请求,需要监听客户端请求(bind/listen),和客户端建立连接(accept),从 socket 中读取请求(recv),解析客户端发送请求(parse),根据请求类型读取键值数据(get),最后给客户端返回结果,即向 socket 中写回数据(send)。

jsidZF.md.jpg

但是,在这里的网络 IO 操作中,有潜在的阻塞点,分别是 accept() 和 recv()。当 Redis 监听到一个客户端有连接请求,但一直未能成功建立起连接时,会阻塞在 accept() 函数这里,导致其他客户端无法和 Redis 建立连接。类似的,当 Redis 通过 recv() 从一个客户端读取数据时,如果数据一直没有到达,Redis 也会一直阻塞在 recv()。

基于多路复用的Redis IO模型

Linux系统中的IO多路复用模型是指一个线程可以处理多个IO流,即select/epoll机制。它允许Linux内核同时存在多个监听套接字和已连接套接字,内核会一直监听这些套接字的连接请求或者数据请求,一旦有请求到达,就会交给Redis处理,这样就实现了一个Redis线程处理多个IO流的效果。

下图就是基于多路复用的 Redis IO 模型。图中的多个 FD 就是刚才所说的多个套接字。Redis 网络框架调用 epoll 机制,让内核监听这些套接字。此时,Redis 线程不会阻塞在某一个特定的监听或已连接套接字上,也就是说,不会阻塞在某一个特定的客户端请求处理上。正因为此,Redis 可以同时和多个客户端连接并处理请求,从而提升并发性。

jseykT.md.jpg

为了在请求到达时能通知到 Redis 线程,select/epoll 提供了基于事件的回调机制,即针对不同事件的发生,调用相应的处理函数。

Author: Aaron
Link: https://xjsir.cn/2022/11/12/Redis高性能IO模型/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.