Redis原理: List BRPOP分析

在前面的文章中,有提到Redis的命令执行线程是单线程的,而这个主要体现在EventLoop的循环是在主线程中执行的,而我们也知道在 Redis list中可以使用 BLPOP 可以进行阻塞式的获取列表的数据,也就是当获取的列表是空的,客户端会阻塞等待,直到对应的list有数据,或是达到了超时时间,如下图

BLPOP的使用方式: BLPOP list1 list2 ... listn timeout

那如果redis是单线程的,为什么当一个客户调用BLPOP时,不会影响其他的客户端访问呢?

接下来我们看下,BLPOP的源码是如何处理的?

从前面的文章中,知道 BLPOP的命令是从 redisCommandTable中获取的

以上的代码逻辑是当处理的key数组中,只要有一个key对应的列表有值(如 list1 list2 list3,list1 没有列表,list2 与list3 有值,则只会返回 list2对应的值),则会直接返回对应的数据,如果对应的key不是list类型,则会返回异常,这里的逻辑比较好理解,再来看下当没有数据时的处理逻辑,会继续往下调用 blockForKeys.

从上面可以看出,当有客户端进来,相应的key数组对应的列表都为空时,redis服务器会将客户端信息加入到block_lists列表中,如果有设置timeout,也会将客户端加入到超时列表中,如果是有多个客户端同时block时,会按先阻塞先服务的原则进行服务。

那block_lists的数据又是什么时候被发现的呢?

还记得在blockClient的函数中,会设置server.blocked_clients 这个字段,这里会记录当前有多少个客户发起了阻塞的请求,因为Redis是单线程,使用IO多路复用的方式来进行监听,从redis的启动分析篇知道,接收命令的处理器是 readQueryFromClient 函数,执行命令最终会调用到 processCommand, 这里有一个逻辑是在处理完命令,会调用handleClientsBlockedOnKeys,

在 server 中有两个字段,一个是 blocked_clients,一个是ready_keys,当调用push方法添加数据时,会判断对应的key是否有blocked_clients,如果有会将对应的key移至 ready_keys列表中

接着就会调用 handleClientsBlockedOnKeys 进行处理向阻塞的客户端回写数据的过程了。

所以这里其实对于客户端在发起 BLPOP命令时,如果没有数据,是直接返回的,来看下客户端调用的情况,以jedis为例

其实客户端是发了两个请求,一个是发送blpop的请求,再发一了一个获取结果的请求,调用第二个时,如果对应的key为空或是不存在,则会加入阻塞队列,下面的请求就会等待结果,而这里会设置client.setTimeoutInfinite 来配置socket的超时时间为无限,就会一直等下去。

至此,也就清楚当发起BLPOP时,即使是单线程的redis服务端,为什么不会影响其他的客户请求了。

这里留一个问题:如果这个客户端一直阻塞,会带来什么问题,需要怎么处理呢?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值