Redisのリストは、データのない、リスト内のクライアント接続がブロックされます、blpopブロッキング操作で実現することができます。これは私に質問をした、自身をRedisのシングルスレッドのサービスで、クライアントをブロックすると、サーバーとのつながりを維持している場合、それは他のコマンドの実行にそれをブロックしませんか?
明白な答えは、コマンドを遮断する原則のRedisの実現を伴う、ないです。IOサイクルと、時限イベント:我々はRedisのサーバーに2つのループがあることを知っています。IOサイクル、Redisのクライアント接続応答完了、コマンド要求の処理とコマンド処理応答、およびタイミングサイクルの結果では、検出は、Redisのキー等を有効期限が切れて達成されます。いくつかの重要な工程を含む接続処理手順をRedisの:IOマルチプレクサ状態は、ソケット、ソケット・イベントを検出し、要求イベント処理をディスパッチします。
存在する場合、最初のキーがクライアントにデータを飛び出さに応じて、対応するリストを検索しますRedisのコマンド処理手順をblpopとき。それ以外の場合はblocking_keysの間でキープッシュデータ構造に対応し、対応する値は、クライアントにブロックされています。次のプッシュコマンドが発行されると、blocking_keysうち対応するキーサーバチェックがあるかどうか存在する場合、リストready_keysに追加されるキーながらリンクリスト及びクライアントへの応答の値。
クライアント要求は、応答して、ready_keysリストをトラバースし、blocking_keysの中から対応するクライアントのリストを検索する各イベントループの終了時にサービスが終了した後、全体のプロセスは、イベント・ループを遮断する実行しないであろう。だから、一般的には、Redisのサーバーはready_keysとblocking_keys二つのリストとイベントループによって封鎖イベントに対処することです。
最初のステップ:ready_keysでプッシュコマンドに追加のキーを扱うには
要素のリストがnullの場合、それは、キーが存在しない要素がキーに追加されたときに、新しいキーでなければならないもの値が決定された場合、関数内ので、dbAdd()関数を呼び出しますリストタイプ、実行さsignalListAsReady()関数
void dbAdd(redisDb *db, robj *key, robj *val) {
sds copy = sdsdup(key->ptr); //复制key字符串
int retval = dictAdd(db->dict, copy, val); //将key-val添加到键值对字典
serverAssertWithInfo(NULL,key,retval == DICT_OK);
// 如果值对象是列表类型,有阻塞的命令,因此将key加入ready_keys字典中
if (val->type == OBJ_LIST) signalListAsReady(db, key);
// 如果开启了集群模式,则讲key添加到槽中
if (server.cluster_enabled) slotToKeyAdd(key);
}
キーデータはready_keysリストに追加されます
//如果有client因为等待一个key被push而被阻塞,那么将这个key放入ready_keys,key哈希表中
void signalListAsReady(redisDb *db, robj *key) {
readyList *rl;
/* No clients blocking for this key? No need to queue it. */
//如果在key不是正处于阻塞状态的键则返回
if (dictFind(db->blocking_keys,key) == NULL) return;
/* Key was already signaled? No need to queue it again. */
//key已经是ready_keys链表里的键,则返回
if (dictFind(db->ready_keys,key) != NULL) return;
/* Ok, we need to queue this key into server.ready_keys. */
//接下来需要将key添加到ready_keys中
//分配一个readyList结构的空间,该结构记录要解除client的阻塞状态的键
rl = zmalloc(sizeof(*rl));
rl->key = key; //设置要解除的键
rl->db = db; //设置所在数据库
incrRefCount(key);
//将rl添加到server.ready_keys的末尾
listAddNodeTail(server.ready_keys,rl);
/* We also add the key in the db->ready_keys dictionary in order
* to avoid adding it multiple times into a list with a simple O(1)
* check. */
//再讲key添加到ready_keys哈希表中,防止重复添加
incrRefCount(key);
serverAssert(dictAdd(db->ready_keys,key,NULL) == DICT_OK);
}
パートII:コマンド処理した後、任意のクライアント要求は、クライアントとの応答に対応するキーに対応してリンクリストを、横断、ready_keysあります
readQueryFromClient - > processCommand-> handleClientsBlockedOnLists - > serveClientBlockedOnList