Redis 为什么使用单线程?

老生常谈的一件事:为什么使用单线程的 Redis 还那么快?

其实这里的单线程是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的,这也是 Redis 对外提供键值存储服务的主要流程。但 Redis 的其他功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的。当然也会涉及到多路复用机制,接着我们来谈谈何为多路复用?

Redis 为何不用多线程
通常对于一个多线程的应用来说,在有合理的资源分配的情况下,多线程可以增加系统中处理请求操作的资源实体,进而提升系统能够同时处理的请求数,即吞吐率。
但是往往在多线程下会遇到一些问题:共享资源的并发访问控制。 当有多个线程要修改这个共享资源时,为了保证共享资源的正确性,就需要有额外的机制进行保证,而这个额外的机制,就会带来额外的开销。所以为了避免这些问题,Redis 直接采用了单线程模式。
当然上面也是举了一个例子。

单线程 Redis 为什么那么快
第一、Redis 的大部分操作在内存上完成,再加上它采用了高效的数据结构,例如哈希表和跳表。
第二、Redis 采用了多路复用机制,使其在网络 IO 操作中能并发处理大量的客户端请求,实现高吞吐率。

多路复用的高性能 I/O 模型
其实 Redis 是利用上Linux 中的 IO 多路复用机制, Linux 中的 IO 多路复用机制是指一个线程处理多个 IO 流。简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听套接字和已连接套接字。内核会一直监听这些套接字上的连接请求或数据请求。一旦有请求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。
如图:

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

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

回调机制指 select/epoll 一旦监测到 FD 上有请求到达时,就会触发相应的事件。这些事件会被放进一个事件队列,Redis 单线程对该事件队列不断进行处理。这样一来,Redis 无需一直轮询是否有请求实际发生,这就可以避免造成 CPU 资源浪费。同时,Redis 在对事件队列中的事件进行处理时,会调用相应的处理函数,这就实现了基于事件的回调。因为 Redis 一直在对事件队列进行处理,所以能及时响应客户端请求,提升 Redis 的响应性能。

总结 Redis 单线程是指它对网络 IO 和数据读写的操作采用了一个线程,而采用单线程的一个核心原因是避免多线程开发的并发控制问题。单线程的 Redis 也能获得高性能,跟多路复用的 IO 模型密切相关,因为这避免了 accept() 和 send() recv() 潜在的网络 IO 操作阻塞点。

猜你喜欢

转载自blog.csdn.net/m0_51504545/article/details/109170790