redis--listブロックの詳細


redisではblpopがチェーンテーブルのブロック操作を実現し,クライアント接続がlistにデータがない場合にブロックされる.これは、redis自体が単一スレッドサービスであり、ブロッククライアントがサーバへのリンクを維持している場合、他のコマンドの実行をブロックするのではないかという疑問を抱かせた.
答えは明らかにできない.これはredisブロック命令の実現原理にかかわる.RedisサーバにはIOループとタイミングイベントの2つのループがあることを知っています.IOサイクルでは、redisがクライアント接続応答、コマンドリクエスト処理、コマンド処理結果返信などを完了し、タイミングサイクルではredisが期限切れkeyの検出などを完了する.redis一次接続処理のプロセスは、IO多重検出ソケット状態、ソケットイベント割り当て、リクエストイベント処理のいくつかの重要なステップを含む.
redisはblpopコマンド処理プロセスの場合、まずkeyに対応するlistを検索し、存在する場合、popはクライアントにデータ応答する.そうでなければ対応するkey pushをblocking_keysデータ構造では,対応するvalueはブロックされたclientである.次のpushコマンドが発行されると、サーバはblocking_をチェックします.keysに対応するkeyが存在するかどうか、存在する場合はready_にkeyを追加keysチェーンテーブルにvalueを挿入し、クライアントに応答します.
サービス側は、各イベントサイクルでクライアント要求を処理した後、ready_を巡回する.keysチェーンテーブル、blocking_keysチェーンテーブルには対応するclientが見つかり、応答し、プロセス全体がイベントループの実行をブロックしない.だから、総じて言えばredis serverはready_を通じてkeysとblocking_keysの2つのチェーンテーブルとイベントループは、ブロックされたイベントを処理する.
ステップ1:pushコマンドの処理時にkeyをready_に追加keys中
1つのリストの要素がnullの場合、そのキーも存在しないので、1つのキーに要素を追加すると必ず1つのキーが追加され、dbAdd()関数が呼び出されるので、この関数でvalueがリストタイプであると判断した場合、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_にkeyを追加します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);
}

第2部:いずれかのクライアントのコマンド要求を処理した後、順次ready_を巡回するkeysチェーンテーブルは、対応するクライアントと対応するkeyを応答します.
readQueryFromClient -> processCommand-> handleClientsBlockedOnLists -> serveClientBlockedOnList
https://www.jianshu.com/p/xsMzfn