Redis单线程
redis是以socket方式通信,socket服务端可同时接受多个客户端请求连接,也就是说,redis服务同时面对多个redis客户端连接请求,而redis服务本身是单线程运行。
假设,现在有A,B,C,D,E五个客户端同时发起redis请求,A优先稍微一点点第一个到达,然后是B,C,D,E依次到达,此时redis服务端开始处理A请求,建立连接需要30秒,获取请求数据需要10秒,然后处理数据需要0.1秒,回送数据给客户端需要5秒,总共大概需要45秒。也就是说,下一个B请求需要等待45秒,这里注意,也许这五个几乎同时请求,由于socket可以同时处理多个请求,所以建立网络连接阶段时间差可忽略,但是在第二阶段,服务端需要什么事都不干,坐等10秒中,对于CPU和客户端来说是无法忍受的。所以说单线程效率非常,非常低,但是正是因为这些类似问题,Redis单线程本质上并不是如此运行。接下来讨论redis真正的单线程运行方式。
客户端与服务端建立连接交由socket,可以同时建立多个连接(这里应该是多线程/多进程),建立的连接redis是知道的(为什么知道,去看socket编程,再次强调基础很重要),
然后redis会基于这些建立的连接去探测哪个连接已经接收完了客户端的请求数据(注意:不是探测哪个连接建立好了,而是探测哪个接收完了请求数据),
而且这里的探测动作就是单线程的开始,一旦探测到则基于接收到的数据开始数据处理阶段,然后返回数据,再继续探测下一个已经接收完请求数据的网络连接。
注意,从探测到数据处理再到数据返回,全程单线程。这应该就是所谓的redis单线程。至于内部有多复杂我们无需关心,我们追求的是理解流程,苛求原理,但不能把内脏都挖出来。
I/O多路复用
为什么 Redis 中要使用 I/O 多路复用这种技术呢?因为 Redis 是跑在「单线程」中的,所有的操作都是按照顺序线性执行的,但是「由于读写操作等待用户输入 或 输出都是阻塞的」,所以 I/O 操作在一般情况下往往不能直接返回,这会导致某一文件的 I/O 阻塞导,致整个进程无法对其它客户提供服务。而 I/O 多路复用就是为了解决这个问题而出现的。「为了让单线程(进程)的服务端应用同时处理多个客户端的事件,Redis 采用了 IO 多路复用机制。」
这里**“多路”「指的是多个网络连接客户端,」“复用”**指的是复用同一个线程(单进程)。
I/O 多路复用其实是使用一个线程来检查多个 Socket 的就绪状态,在单个线程中通过记录跟踪每一个 socket(I/O流)的状态来管理处理多个 I/O 流。
如下图是 Redis 的 I/O 多路复用模型: