Redis 使用管道(Pipeline)方式提升操作性能
Redis 是一個非常流行的 key-value 存儲系統,而作爲其官方推薦的 Java 版客戶端 Jedis 也非常強大和穩定。
在單個客戶端中,如果需要讀寫大量數據,可以考慮採用管道(Pipeline)方式。如果採用管道方式,那麼多條命令可以通過批量的方式一次性地發送到服務器,而結果也會一次性返回到客戶端。
本文將介紹 Redis 使用管道(Pipeline)方式提升操作性能。
一、管道(Pipeline)
未使用管道方式執行 N 條命令,如圖所示:
管道(Pipeline):一次向 Redis 發送多條命令。
客戶端可以一次性發送多個請求而不用等待服務器的響應,待所有命令都發送完後再一次性讀取服務的響應,這樣可以極大的降低多條命令執行的網絡傳輸開銷,管道執行多條命令的網絡開銷實際上只相當於一次命令執行的網絡開銷。
需要注意到是用 Pipeline 方式打包命令發送,Redis 必須在處理完所有命令前先緩存起所有命令的處理結果。打包的命令越多,緩存消耗內存也越多。
所以並不是打包的命令越多越好。pipeline 中發送的每個 Command 都會被 Server 立即執行,如果執行失敗,將會在此後的響應中得到信息;也就是 Pipeline 並不是表達 “所有 Command 都一起成功” 的語義,管道中前面命令失敗,後面命令不會有影響,繼續執行。
二、管道執行示例代碼
創建示例項目,測試一下管道執行的性能。
PipelineApp 示例代碼如下所示:
public class PipelineApp { public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
jedis.auth("123456"); // 開始時間
long startTime = System.currentTimeMillis(); for(int i = 0; i<10000; i++) {
jedis.set("key_" + i, String.valueOf(i));
jedis.get("key_" + i);
} // 結束時間
long endTime = System.currentTimeMillis();
System.out.println("正常執行時間(ms):" + (endTime-startTime));
startTime = System.currentTimeMillis();
Pipeline pipeline = jedis.pipelined(); for (int i = 0; i < 10000; i++) {
pipeline.set("key_" + i, String.valueOf(i));
pipeline.get("key_" + i);
}
pipeline.sync();
endTime = System.currentTimeMillis();
System.out.println("管道執行時間(ms):" + (endTime-startTime));
}
}
啓動應用,輸出結果如下所示:
正常執行時間 (ms):1802
管道執行時間 (ms):78
可以看到以管道方式運行的耗時會遠小於非管道方式運行的耗時,特別是客戶端與服務端的網絡延遲越大,性能體能越明顯。所以,在項目中如果需要大批量向 Redis 服務器讀寫數據,那麼建議使用管道方式。
三、Pipeline 正確使用方式
使用 pipeline 組裝的命令個數不能太多,不然數據量過大,增加客戶端的等待時間,還可能造成網絡阻塞,可以將大量命令的拆分多個小的 pipeline 命令完成。
管道不會管所有的命令是否都執行成功,只是逐條地執行命令。管道不能保證原子性,不支持事務。可以使用 lua 腳本來實現原子性。
來源:
https://www.toutiao.com/article/7123376220187656738/?log_from=fe5f51b202bb6_1658798399058
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/j5ITcem7zSdq6b3mIRam3A