天天看點

Redis精通系列——Pipeline(管道)

  本文已收錄于專欄

《Redis精通系列》

上千人點贊收藏,全套Redis學習資料,大廠必備技能!

目錄

1、簡介

2、深究pipeline

3、benchmark壓測pipeline

4、Jedis使用pipeline

Redis是一種基于用戶端-服務端模型以及請求/響應的TCP服務。一次Redis用戶端發起的請求,經過服務端的響應後,大緻會經曆如下的步驟:

用戶端發起一個(查詢/插入)請求,并監聽socket傳回,通常情況都是阻塞模式等待Redis伺服器的響應

服務端處理指令,并且傳回處理結果給用戶端

用戶端接收到服務的傳回結果,程式從阻塞代碼處傳回

Redis用戶端和服務端之間通過網絡連接配接進行資料傳輸,這個連接配接可以很快(loopback接口)或很慢(建立了一個多次跳轉的網絡連接配接)。無論網絡延如何延時,資料包總是能從用戶端到達伺服器,并從伺服器傳回資料回複用戶端,這個時間被稱之為RTT(Round Trip Time - 往返時間)。我們可以很容易就意識到,Redis在連續請求服務端時,即使Redis每秒能處理100k請求,但也會因為網絡傳輸花費大量時間,導緻整體性能的下降。

是以如果遇到大量的批處理,我們可以考慮使用Redis的pipeline(管道)。值得注意的是,管道技術并不是Redis特有的技術,管道技術往往需要用戶端-伺服器的共同配合,大部分工作任務其實是在用戶端完成,很顯然Redis支援管道技術,按照官網的意思,Redis的最低版本就考慮了管道技術的支援性設計。

如下圖,多個連續的incr指令,使用pipeline(管道)後,多個連續的incr指令隻會花費一次網絡來回開銷,這個開銷會随着n數值的增大,大幅減少網絡io開銷,進而提升整體服務的性能。

Redis精通系列——Pipeline(管道)
Redis精通系列——Pipeline(管道)

用戶端調用write将資料寫入作業系統核心(kernel)為socket連接配接配置設定的發送緩沖區(send buffer)

用戶端作業系統核心将發送緩沖區(send buffer)的資料發送到網卡(NIC)

網卡(NIC)将資料通過路由(route)将資料送到Redis伺服器機器網卡(NIC)

伺服器作業系統核心(kernel)将網卡(NIC)接收的資料,寫入核心為socket配置設定的接收緩沖區(recv buffer)

伺服器程序從接收緩沖區調用read讀取資料,并進行資料邏輯處理

資料處理完成之後,伺服器程序調用write将響應資料寫入作業系統核心為socket配置設定的發送緩沖區

作業系統核心将發送緩沖區的資料發送到伺服器網卡

伺服器網卡将響應資料通過路由發送到用戶端網卡

用戶端網卡接收響應資料

用戶端作業系統核心讀取網卡接收到的伺服器響應資料,并寫入作業系統為socket連接配接配置設定的介紹緩沖區

用戶端程序調用read從接收緩沖區中讀取伺服器響應資料

一次完整網絡請求來回過程結束

對于pipeline技術而言,就是将n * 12個步驟,合并成1 * 12,這樣服務請求響應的總體時間将會大大的減少。

有個值得注意的點:

在上述網絡請求來回中,可能出現我們經常說到的io阻塞:

當write操作發生,并且發送緩沖區(send buffer)滿時,就會導緻write操作阻塞

當read操作發生,并且接收緩沖區(recv buffer)滿時,就會導緻read操作阻塞

上述的這兩個阻塞如果出現,将會導緻整個請求時間變長,是以我們操作大批量指令的時候,比如10k個指令,我們可以合理的對指令分多次批量發送,這樣可以減少出現阻塞的情況,也可以避免伺服器響應一個過大的答複包,導緻用戶端記憶體負載過重。

使用Redis提供的benchmark對Redis進行性能測試,

如過你是Windows下的Redis,在安裝目錄下有個redis-benchmark.exe,進入cmd指令模式測試即可

Redis精通系列——Pipeline(管道)
Redis精通系列——Pipeline(管道)
Redis精通系列——Pipeline(管道)
Redis精通系列——Pipeline(管道)

package com.liziba.redis;
 
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
 
import java.io.IOException;
 
/**
 * <p>
 * 測試pipeline
 * </p>
 *
 * @Author: Liziba
 * @Date: 2021/9/14 22:43
 */
public class PipelineTest {
 
    public static void main(String[] args) throws IOException {
        Jedis client = new Jedis("127.0.0.1", 6379);
 
        long startPipe = System.currentTimeMillis();
        Pipeline pipe = client.pipelined();
        pipe.multi();
        for (int i = 0; i < 100000; i++) {
            pipe.set("pipe" + i, i + "" );
        }
        pipe.exec();
        pipe.close();
        long endPipe = System.currentTimeMillis();
        System.out.println("pipeline set cost time : " + (endPipe - startPipe) + "ms");
 
 
        for (int i = 0; i < 100000; i++) {
            client.set("normal" + i, i + "");
        }
        System.out.println("normal set cost time : " + (System.currentTimeMillis() - endPipe)+ "ms");
    }
 
}      
Redis精通系列——Pipeline(管道)
上一篇: markdown文法