redis中multi與pipeline介紹分析

Walker發表於2018-07-09

背景

由於對redis快取中資料有批量操作,例如預熱快取資料,或者在列表頁批量去獲取快取資料,在使用了multi批量提交事務後,發現redis壓力高居不下,而使用了pipeline之後壓力回落了平常,也因為這個案例,特在此寫個分析與筆記。

multi

簡介

標記一個事務塊的開始。 事務塊內的多條命令會按照先後順序被放進一個佇列當中,最後由 EXEC 命令原子性(atomic)地執行。

實現原理

我用php擴充套件調起redis服務,執行,程式碼如下:

$redis = new redis();
$redis->connect('127.0.0.1',6379);
$handle = $redis->multi();
$handle->incr('a');
$handle->incr('b');
$handle->exec();
複製程式碼

為了檢視這期間具體的連線過程,用wireshark監聽迴環地址埠6379,抓包請求如下圖所示:

redis中multi與pipeline介紹分析

redis客戶端與服務端建立連線後,multi標記事務開始,之後每次執行,服務端返回queued佇列標誌。檢視redis原始碼src/multi.c檔案:

void queueMultiCommand(client *c) {
    multiCmd *mc;
    int j;

    c->mstate.commands = zrealloc(c->mstate.commands,
            sizeof(multiCmd)*(c->mstate.count+1));
    mc = c->mstate.commands+c->mstate.count;
    mc->cmd = c->cmd;
    mc->argc = c->argc;
    mc->argv = zmalloc(sizeof(robj*)*c->argc);
    memcpy(mc->argv,c->argv,sizeof(robj*)*c->argc);
    for (j = 0; j < c->argc; j++)
        incrRefCount(mc->argv[j]);
    c->mstate.count++;
}
複製程式碼

在上述原始碼中可以看到redis服務端每次會把事務塊中的命令儲存到記憶體中,上述簡介已經解釋過最後通過exec命令執行,再看下面示例圖的返回結果可以瞭解到redis服務端一次性返回所有命令執行返回結果。

redis中multi與pipeline介紹分析

pipeline

簡介

客戶端將執行的命令寫入到緩衝中,最後由exec命令一次性傳送給redis執行返回。

實現原理

同樣,用相關程式碼呼叫redis抓包;

$redis = new redis();
$redis->connect('127.0.0.1',6379);
$handle = $redis->pipeline();
$handle->incr('a');
$handle->incr('b');
$handle->exec();
複製程式碼

繼續用wireshark抓包,如下圖所示

  • pipeline 客戶端請求包示例圖

redis中multi與pipeline介紹分析

  • pipeline 服務端返回包示例圖

redis中multi與pipeline介紹分析

這上面的圖片簡要分析一下,pipeline管道操作是需要客戶端與服務端的支援,客戶端將命令寫入緩衝,最後再通過exec命令傳送給服務端,服務端通過命令拆分,逐個執行返回結果。

兩者的區別

由上面的請求也可以看出了兩者最明顯的區別是客戶端傳送請求的方式不一樣,具體相關區別如下:

  • pipeline選擇客戶端緩衝,multi選擇服務端緩衝;
  • 請求次數的不一致,multi需要每個命令都傳送一次給服務端,pipeline最後一次性傳送給服務端,請求次數相對於multi減少
  • multi/exec可以保證原子性,而pipeline不保證原子性

個人部落格地址:blog.walkerx.cn

相關文章