網站首頁 編程語言 正文
redis | pipeline(管道)
背景
Redis是一種基于客戶端-服務端模型以及請求/響應的TCP服務。這意味著通常情況下一個請求會遵循以下步驟:
- 客戶端向服務端發送一個查詢請求,并監聽 Socket 返回,通常是以阻塞模式,等待服務端響應。
- 服務端處理命令,并將結果返回給客戶端。
Redis 客戶端與 Redis 服務器之間使用 TCP 協議進行連接,一個客戶端可以通過一個 socket 連接發起多個請求命令。每個請求命令發出后 client 通常會阻塞并等待 redis 服務器處理,redis 處理完請求命令后會將結果通過響應報文返回給 client,因此當執行多條命令的時候都需要等待上一條命令執行完畢才能執行。
Redis本身是基于一個Request一個Response方式的同步請求,正常情況下,客戶端發送一個命令,等待Redis服務器返回結果,Redis服務器接收到命令,處理后響應結果給客戶端。
無論網絡延如何延時,數據包總是能從客戶端到達服務器,并從服務器返回數據回復客戶端。 這個時間被稱之為 RTT (Round Trip Time - 往返時間)。
如果同時需要執行大量的命令,那么就要等待上一條命令應答后再執行,這中間不僅僅多了RTT(Round Time Trip),而且還頻繁調用系統IO,發送網絡請求,同時需要redis調用多次read() 和write()系統方法,系統方法會將數據從用戶態轉移到內核態,這樣就會對進程上下文有比較大的影響了。
什么是流水線(pipeline)
官網:https://redis.io/docs/manual/pipelining/
管道(pipeline)可以一次性發送多條命令并在執行完后一次性將結果返回,pipeline 通過減少客戶端與 redis 的通信次數來實現降低往返延時時間,而且 Pipeline 實現的原理是隊列,而隊列的原理是時先進先出,這樣就保證數據的順序性。
通俗點:pipeline就是把一組命令進行打包,然后一次性通過網絡發送到Redis。同時將執行的結果批量的返回回來。
pipeline,將多個命令一次執行,一次發送出去,節省網絡時間。 pipeline技術最顯著的優勢是提高了 redis 服務的性能。
管道技術并不是Redis特有的技術,管道技術往往需要客戶端-服務器的共同配合,大部分工作任務其實是在客戶端完成,很顯然Redis支持管道技術,按照官網的意思,Redis的最低版本就考慮了管道技術的支持性設計。
如下圖,多個連續的incr指令,使用pipeline(管道)后,多個連續的incr指令只會花費一次網絡來回開銷,這個開銷會隨著n數值的增大,大幅減少網絡io開銷,從而提升整體服務的性能。管道技術優化的是網絡傳輸的耗時時間。
總結:使用管道技術可以解決多個命令執行時的網絡等待,它是把多個命令整合到一起發送給服務器端處理之后統一返回給客戶端,這樣就免去了每條命令執行后都要等待的情況,從而有效地提高了程序的執行效率,但使用管道技術也要注意避免發送的命令過大,或管道內的數據太多而導致的網絡阻塞。
適用場景
如果出現集中大批量的請求時,因為每個請求都要經歷先請求再響應的過程,這就會造成網絡資源浪費,此時就需要管道技術來把所有的命令整合一次發給服務端,再一次響應給客戶端,這樣就能大大的提升了 Redis 的響應速度。
要求實時性也沒那么高,但是最求高性能,這時候用 pipeline 最好了。
benchmark壓測pipeline
使用Redis提供的benchmark對Redis進行性能測試,
如過你是Windows下的Redis,在安裝目錄下有個redis-benchmark.exe,進入cmd命令模式測試即可。
如果你是在Linux下的redis,在安裝目錄的src目錄下有個redis-benchmark
通過普通方式測試set指令和pipeline方式測試set指令,可以看到Redis服務不同的QPS:
普通set方式,Redis QPS 大概在5.3萬左右
當使用pipeline set時,隨著管道內并行請求數量的增加,Redis QPS可以達到100萬以上
代碼測試-python: StrictRedis
#引入模塊
#這個模塊中提供了StrictRedis對象,?于連接redis服務器,并按照不同類型提供 了不同?法,進?交互操作
from redis import StrictRedis
我們使用 StrictRedis客戶端提供的 Pipeline 對象來實現管道技術。首先先獲取 Pipeline 對象,再為 Pipeline 對象設置需要執行的命令,最后再使用excute() 方法來統一執行這些命令,代碼如下:
from redis import StrictRedis
redis_cli = StrictRedis(host="xx", port=xx, password="xx", db=xx, decode_responses=True)
import time
def main():
t1 = time.time()
pipe = redis_cli.pipeline()
num = 1
for i in range(100):
pipe.set("name_" + str(num), num)
pipe.delete("name_" + str(num))
num += 1
pipe.execute()
t2 = time.time()
print(t2-t1)
接下來我們用普通的命令執行此循環,看下程序的執行時間,代碼如下:
def test():
t1 = time.time()
num = 10000
for i in range(100):
redis_cli.set("test_" + str(num), num)
redis_cli.delete("test_" + str(num))
num += 10
t2 = time.time()
print(t2 - t1)
從結果可以看出,管道的執行時間是0.165秒,而普通命令執行時間是9.09秒,管道技術要比普通的執行快了 56 倍。
代碼測試-java:Jedis使用pipeline
package com.liziba.redis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import java.io.IOException;
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");
}
}
pipeline注意事項
管道技術雖然有它的優勢,但在使用時還需注意以下幾個細節:
- 每次pipeline攜帶數量不推薦過大,否則會影響網絡性能
- 如果管道的數據過多可能會導致客戶端的等待時間過長,導致網絡阻塞
- 發送的命令數量不會被限制,但輸入緩存區也就是命令的最大存儲體積為 1GB,當發送的命令超過此限制時,命令不會被執行,并且會被 Redis 服務器端斷開此鏈接
- pipeline每次只能作用在一個Redis節點上
- 部分客戶端自己本身也有緩存區大小的設置,如果管道命令沒有沒執行或者是執行不完整,可以排查此情況
參考資料
分布式緩存Redis之Pipeline(管道)
URL: https://blog.csdn.net/u011489043/article/details/78769428
【推薦】Redis精通系列——Pipeline(管道)
參考URL: https://blog.csdn.net/qq_41125219/article/details/120298689
Redis的批量操作是什么?怎么實現的延時隊列?以及訂閱模式、LRU
參考URL: https://baijiahao.baidu.com/s?id=1687918953043523907
原文鏈接:https://blog.csdn.net/inthat/article/details/127030314
相關推薦
- 2022-06-28 python反轉單鏈表算法題_python
- 2022-12-09 C#中async和await的深入分析_C#教程
- 2022-08-28 Python異步發送日志到遠程服務器詳情_python
- 2022-09-07 詳解C語言結構體,枚舉,聯合體的使用_C 語言
- 2022-11-24 Flutter開發setState能否在build中直接調用詳解_Android
- 2022-07-25 C++超詳細講解內存空間分配與this指針_C 語言
- 2022-09-16 python?playwrigh框架入門安裝使用_python
- 2022-11-11 python貪吃蛇核心功能實現下_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支