前言 

  在 Redis 的 列表(list) 命令中,有一些命令是阻塞模式的,比如:BRPOP,  BLPOP, BRPOPLPUSH, 这些命令都有可能造成客户端的阻塞。下面总结一下 Redis 实现阻塞和取消阻塞的过程。

阻塞过程

  当一个阻塞原语的处理目标为空键时, 执行该阻塞原语的客户端就会被阻塞。有以下步骤:

1:将客户端的状态设为“正在阻塞”, 并记录阻塞这个客户端的各个键,以及阻塞的最长时限(timeout) 等数据;

2:将客户端的信息记录到 server.db[i]->blocking_keys 中(其中 i 为客户端所使用的数据库号码);

3:继续维持客户端和服务器之间的网络连接,但不再向客户端传送任何信息,造成客户端阻塞;

note: step2 中 service.db[i]->blocking_keys 是一个字典,键是那些造成客户端阻塞的键, 值是一个链表,链表里保存了所有因这个键而被阻塞的客户端,如下图所示:

Redis 列表阻塞命令的实现

 

 

 阻塞的取消过程

  阻塞的取消有三种方法:

    【1】被动脱离:有其它客户端为造成阻塞的键推入了新元素;

    【2】主动脱离:到达执行阻塞原语时设定的最大阻塞时间(timeout);

    【3】强制脱离:客户端强制终止和服务端的连接,或者服务器停机;

 

被动脱离

    阻塞因 LPUSH, RPUSH, LINSERT 等添加命令而被取消,这三个添加新元素的命令,在底层都有一个 pushGenericCommand 的函数实现(在下方源码部分增加的 TODO 标志标识关键步骤):

void lpushCommand(redisClient *c) {
    pushGenericCommand(c,REDIS_HEAD);
}

void rpushCommand(redisClient *c) {
    pushGenericCommand(c,REDIS_TAIL);
}
调用 pushGenericCommand

相关文章: