【Redis】Redis线程与IO模子—(三)
https://img-blog.csdnimg.cn/9633f3bb7c3643d0a6989e51c0470ac6.gif#pic_center#pic_center#pic_center#pic_center#pic_center#pic_center#pic_center#pic_center#pic_center#pic_center#pic_centerhttps://img-blog.csdnimg.cn/img_convert/7b0d6ba5dcce6ce6b2e732fdffde6496.gif#pic_center#pic_center#pic_center#pic_center#pic_center#pic_center
一、Redis 单线程
通常说 Redis 是单线程,主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的,其他功能,好比持久化、异步删除、集群数据同步等,是由额外的线程执行的,所以严格来说,Redis 并不是单线程。
多线程开辟会不可避免的带来并发控制和资源开销的问题,如果没有良好的体系设计往往会适得其反,为了避免这些问题,Redis 直接采取了单线程模式。
Redis 单线程模子能到达每秒数十万级别的处理能力,一方面是大部门操作在内存上完成 + 高效的数据布局,例如哈希表和跳表。另一方面,就是采取了多路复用机制,使其在网络 IO 操作中能并发处理大量的客户端哀求,实现高吞吐率。
在了解多路复用之前,要先明白网络操作的基本 IO 模子和潜伏的阻塞点。如果单线程被阻塞了,就无法举行多路复用了。以 Get 哀求为例如下图,bind/listen、accept、recv、parse 和 send 属于网络 IO 处理,get 属于键值数据操作。
https://i-blog.csdnimg.cn/direct/ef5a105f9a5249f8aeaeba3012b40a82.png
这里的网络 IO 操作中,潜伏的阻塞点分别是 accept() 和 recv()。当 Redis 监听到一个客户端有连接哀求,但一直未能成功建立起连接时,会阻塞在 accept() 函数这里,导致其他客户端无法和 Redis 建立连接。雷同的,当 Redis 通过 recv() 从一个客户端读取数据时,如果数据一直没有到达,Redis 也会一直阻塞在 recv(),这就导致 Redis 整个线程阻塞,无法处理其他客户端哀求,效率很低。不外,Socket 网络模子可以设置非阻塞模式,基于此 Linux 中的 IO 多路复用机制就要登场了。
二、多路复用机制
Linux 中的 IO 多路复用机制是指一个线程处理多个 IO 流,就是我们经常听到的 select/epoll 机制。简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听套接字和已连接套接字。内核会一直监听这些套接字上的连接哀求或数据哀求。一旦有哀求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的结果。
https://i-blog.csdnimg.cn/direct/0555bc5bc3894341a7df33f42bf2e5df.png
图中的多个 FD 就是指多个套接字,Redis 网络框架调用 epoll 机制,让内核监听这些套接字。此时,Redis 线程不会阻塞在某一个特定的监听或已连接套接字上,所以,Redis 可以同时和多个客户端连接并处理哀求,从而提升并发性。
为了在哀求到达时能关照到 Redis 线程,select/epoll 提供了基于事件的回调机制,即针对不同事件的发生,调用相应的处理函数,select/epoll 一旦监测到 FD 上有哀求到达时,就会触发相应的事件。这些事件会被放进一个事件队列,Redis 单线程对该事件队列不断举行处理。这样一来,Redis 无需一直轮询是否有哀求实际发生,这就可以避免造成 CPU 资源浪费。同时,Redis 在对事件队列中的事件举行处理时,会调用相应的处理函数,这就实现了基于事件的回调。由于 Redis 一直在对事件队列举行处理,所以能及时响应客户端哀求,提升 Redis 的响应性能。
三、Redis 6.0 多线程特性
Redis 6.0 之前,固然有些命令操作可以用后台线程或子进程执行(好比数据删除、快照天生、AOF 重写),但是,从网络 IO 处理到实际的读写命令处理,都是由单个线程完成的,有时会成为 Redis 的性能瓶颈。Redis 6.0 之后采取多个 IO 线程来处理网络哀求,进步网络哀求处理的并行度,对于读写命令,仍旧利用单线程来处理。
详细流程:
(1)主线程吸收到客户端连接哀求后创建连接,将 Socket 放入全局等待队列中,通过轮询分配给 IO 线程。
(2)分配后主线程就会进入阻塞状态,等待 IO 线程完成客户端哀求读取和解析,多个 IO 线程在并行处理,嗖嗖嗖。
(3)IO 线程解析完哀求,主线程还是会以单线程的方式执行这些命令操作。
https://i-blog.csdnimg.cn/direct/4e711089b5bd4d8abc7a2c9d4320891a.png
(4)主线程执行完哀求操作后,把返回结果写入缓冲区,主线程阻塞等待 IO 线程把这些结果回写到 Socket 中,并返回给客户端。
https://i-blog.csdnimg.cn/direct/70b43b26909440e794c1514ba7a061c5.png
和 IO 线程读取和解析哀求一样,IO 线程回写 Socket 时,也是有多个线程在并发执行,所以回写 Socket 的速度也很快。等到 IO 线程回写 Socket 完毕,主线程会清空全局队列,等待客户端的后续哀求。
四、IO 多线程设置
在实际应用中,如果 Redis 实例的 CPU 开销不大,吞吐量却没有提升,可以考虑利用多线程机制提升吞吐量,redis.conf 中设置:
[*]设置 io-thread-do-reads 设置项为 yes,表现启用多线程
io-threads-do-reads yes
[*]设置线程个数要小于 Redis 实例所在机器的 CPU 核个数,例如,对于一个 8 核的机器来说,Redis 官方发起设置 6 个 IO线程
io-threads6
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]