Redis 是个单线程程序 这点必须铭记。
理解Redis单线程
Redis客户端对服务端的每次调用都经历了发送命令,执行命令,返回结果三个过程。其中执行命令阶段,由于Redis是单线程来处理命令的,所有到达服务端的命令都不会立刻执行,所有的命令都会进入一个队列中,然后逐个执行,并且多个客户端发送的命令的执行顺序是不确定的,但是可以确定的是不会有两条命令被同时执行,不会产生并发问题,这就是Redis的单线程基本模型。
也许你会怀疑高并发的Redis中间件怎么可能是单线程。很抱歉,它就是单线程,你的怀疑暴露了你的基础知识的不足,莫要瞧不起单线程,除了Redis之外,Node.js也是单线程。Nginx也是单线程,但是它们都是服务器高性能的典范。
Redis单线程为什么还能这么快?
因为它的所有数据都在内存中,所有的运算都是内存级别的运算。正因为Redis是单线程,所以要小心使用Redis指令。对于那些时间复杂度为O(n)级别的指令,一定要谨慎使用,否则一不小心就可能会导致Redis卡顿。
Redis 既然是单线程,如何能处理那么多的并发客户端连接呢?
非堵塞IO
当我们调用套接字的读写方法,默认它们是堵塞的,比如read 方法要传递进去一个参数n,表示最多读取n个字节后再返回,如果一个字节都没有,线程就会卡在那里,直到新的数据到来或者连接关闭,read 方法才可以返回,线程才能继续处理。
write 方法一般来说不会堵塞,除非内核为套接字分配的写缓存区已经满了,write方法就会堵塞,直到缓存区中有空间空闲出来,如图下呈现了套接字读写的细节过程。
非堵塞IO在套接字对象上提供了一个选项Non_Blocking,当这个选项打开时,读写方法不会堵塞,而是能读多少读多少,能写多少写多少。能读多少取决于内核为套接字分配的读缓存区内部的数据字节数,能写多少取决于内核套接字分配的写缓存区的空闲字节数,读方法和写方法都会通过返回值来告知程序实际读写了多少字节。
有了非堵塞IO意味着线程在读写IO时可以不必再堵塞了,读写可以瞬间完成,然后线程就可以继续干别的事了。
待续…