Redis管道(Pipeline)详解
在講解管道前,我們首先來(lái)了解一下redis的交互,redis的一次交互是由客戶端發(fā)起,由服務(wù)端接收,那么我們連續(xù)操作一些指令,如下圖所示:
客戶端請(qǐng)求一個(gè)指令到服務(wù)器到服務(wù)器返回?cái)?shù)據(jù)這個(gè)過(guò)程非常復(fù)雜,既要保證數(shù)據(jù)能夠快速傳到也要保證不丟包,那么每次請(qǐng)求響應(yīng)這個(gè)過(guò)程中數(shù)據(jù)傳輸和客戶端接收數(shù)據(jù)的網(wǎng)絡(luò)消耗非常大,那么我們?cè)趺磥?lái)提升這個(gè)性能呢?
上面說(shuō)了,我們來(lái)回幾次消耗大,那么可以一次性請(qǐng)求,一次性接收嗎?當(dāng)然是可以的,redis可以利用管道來(lái)提高性能。
Redis客戶端與服務(wù)器之間使用TCP協(xié)議進(jìn)行通信,并且很早就支持管道(pipelining)技術(shù)了。Redis 管道 (Pipeline) 本身并不是 Redis 服務(wù)器直接提供的技術(shù),這個(gè)技術(shù)本質(zhì)上是由客戶端提供的,跟服務(wù)器沒(méi)有什么直接的關(guān)系。
這里值得注意的是,管道空間也有上限,合理利用才是最好的選擇。
管道壓力測(cè)試?
接下來(lái)我們測(cè)試一下管道的性能,Redis自帶了一個(gè)壓力測(cè)試工具redis-benchmark,使用這個(gè)工具就可以進(jìn)行管道測(cè)試。?
首先我們對(duì)一個(gè)普通的set指令進(jìn)行壓測(cè),QPS大約5w/s。?
>?redis-benchmark?-t?set?-q?SET:?53975.05?requests?per?second?我們加入管道選項(xiàng)-P參數(shù),它表示單個(gè)管道內(nèi)并行的請(qǐng)求數(shù)量,看下面 P=2,QPS達(dá)到了9w/s。?
>?redis-benchmark?-t?set?-P?2?-q?SET:?94240.88?requests?per?second?再看看 P=3,QPS達(dá)到了 10w/s。?
> redis-benchmark -t set -P 2 -q SET: 102354.15 requests per second但如果再繼續(xù)提升 P 參數(shù),發(fā)現(xiàn) QPS 已經(jīng)上不去了。這是為什么呢??
因?yàn)檫@里CPU處理能力已經(jīng)達(dá)到了瓶頸,Redis的單線程CPU已經(jīng)飆到了 100%,所以無(wú)法再繼續(xù)提升了
深入理解管道本質(zhì)?
接下來(lái)我們深入分析一個(gè)請(qǐng)求交互的流程
上圖就是一個(gè)完整的請(qǐng)求交互流程圖:?
? ? 1、客戶端進(jìn)程調(diào)用write將消息寫到操作系統(tǒng)內(nèi)核為套接字分配的發(fā)送緩沖send buffer。?
? ? 2、客戶端操作系統(tǒng)內(nèi)核將發(fā)送緩沖的內(nèi)容發(fā)送到網(wǎng)卡,網(wǎng)卡硬件將數(shù)據(jù)通過(guò)「網(wǎng)關(guān)路由」送到服務(wù)器的網(wǎng)卡。?
? ? 3、服務(wù)器操作系統(tǒng)內(nèi)核將網(wǎng)卡的數(shù)據(jù)放到內(nèi)核為套接字分配的接收緩沖 recv buffer。?
? ? ?4、服務(wù)器進(jìn)程調(diào)用read從接收緩沖中取出消息進(jìn)行處理。?
? ? 5、服務(wù)器進(jìn)程調(diào)用write將響應(yīng)消息寫到內(nèi)核為套接字分配的發(fā)送緩沖 send buffer。?
? ? 6、服務(wù)器操作系統(tǒng)內(nèi)核將發(fā)送緩沖的內(nèi)容發(fā)送到網(wǎng)卡,網(wǎng)卡硬件將數(shù)據(jù)通過(guò)「網(wǎng)關(guān)路由」送到客戶端的網(wǎng)卡。?
? ? 7、客戶端操作系統(tǒng)內(nèi)核將網(wǎng)卡的數(shù)據(jù)放到內(nèi)核為套接字分配的接收緩沖 recv buffer。?
? ? 8、客戶端進(jìn)程調(diào)用read從接收緩沖中取出消息返回給上層業(yè)務(wù)邏輯進(jìn)行處理。?
? ? 9、結(jié)束。?
我們開始以為write操作是要等到對(duì)方收到消息才會(huì)返回,但實(shí)際上不是這樣的。write操作只負(fù)責(zé)將數(shù)據(jù)寫到本地操作系統(tǒng)內(nèi)核的發(fā)送緩沖然后就返回了。剩下的事交給操作系統(tǒng)內(nèi)核異步將數(shù)據(jù)送到目標(biāo)機(jī)器。但是如果發(fā)送緩沖滿了,那么就需要等待緩沖空出空閑空間來(lái),這個(gè)就是寫操作IO操作的真正耗時(shí)。我們開始以為read操作是從目標(biāo)機(jī)器拉取數(shù)據(jù),但實(shí)際上不是這樣的。read操作只負(fù)責(zé)將數(shù)據(jù)從本地操作系統(tǒng)內(nèi)核的接收緩沖中取出來(lái)就了事了。
所以對(duì)于value=redis.get(key)這樣一個(gè)簡(jiǎn)單的請(qǐng)求來(lái)說(shuō),write操作幾乎沒(méi)有耗時(shí),直接寫到發(fā)送緩沖就返回,而read就會(huì)比較耗時(shí)了,因?yàn)樗却⒔?jīng)過(guò)網(wǎng)絡(luò)路由到目標(biāo)機(jī)器處理后的響應(yīng)消息,再回送到當(dāng)前的內(nèi)核讀緩沖才可以返回。這才是一個(gè)網(wǎng)絡(luò)來(lái)回的真正開銷。?而對(duì)于管道來(lái)說(shuō),連續(xù)的write操作根本就沒(méi)有耗時(shí),之后第一個(gè)read操作會(huì)等待一個(gè)網(wǎng)絡(luò)的來(lái)回開銷,然后所有的響應(yīng)消息就都已經(jīng)回送到內(nèi)核的讀緩沖了,后續(xù)的 read 操作直接就可以從緩沖拿到結(jié)果,瞬間就返回了。?
這就是管道的本質(zhì)了,它并不是服務(wù)器的什么特性,而是客戶端通過(guò)改變了讀寫的順序帶來(lái)的性能的巨大提升。?
?
?
一名正在搶救的coder
筆名:mangolove
CSDN地址:https://blog.csdn.net/mango_love
GitHub地址:https://github.com/mangoloveYu
總結(jié)
以上是生活随笔為你收集整理的Redis管道(Pipeline)详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java并发编程线程安全
- 下一篇: Django配置数据库读写分离