单线程的redis如何实现阻塞队列
从redis的API可以了解到lpop,rpop可以实现一个阻塞式队列。那疑问就来了,redis不是单线程的吗,如果阻塞了,那其他操作就执行不了呀。事实不是这样的
redis的线程模型,是接收客户端命令的线程时 I/O 多路复用的,再通过文件事件分配器单线程执行的。如下图,程序总是会将所有产生事件的套接字都入队到一个队列里面, 然后通过这个队列, 以有序(sequentially)、同步(synchronously)、每次一个套接字的方式向文件事件分派器传送套接字: 当上一个套接字产生的事件被处理完毕之后(该套接字为事件所关联的事件处理器执行完毕), I/O 多路复用程序才会继续向文件事件分派器传送下一个套接字
那实际上我们关心的BLPOP 命令的执行就是在文件事件分派器分派后是怎么执行的了。
对BLPOP命令的处理流程是这样的:
redis先找到对应的key的list,如果list不为空则pop一个数据返回给客户端;
如果list为空,或者list不存在,就将该key添加到一个blockling_keys的字典中,value就是想订阅该key的client链表。此时对应的client的为block状态
当有PUSH 类型的命令进来的时候,先从blocking_keys中查找是否存在对应的key,如果存在就往ready_keys这个链表中添加该key;同时将value插入到对应的list中,并响应客户端。
每次处理完客户端命令后都会遍历ready_keys,并通过blocking_keys找到对应的client,依次将对应list的数据pop出来并响应对应的client;同时检查是否需要再次block。
整个阻塞执行过程相当于是分散开的,每次请求结束后都判断之前的阻塞列表是否满足执行条件,类似我们用轮询来实现长连接的功能。所以看似阻塞的命令对其他命令的执行时不会有影响的,它们依然是单线程的。
参考:https://blog.****.net/u013041642/article/details/98606804