使用批量消息提升服務(wù)端處理能力
? 批量處理是一種非常有效的提升系統(tǒng)吞吐量的方法。在 Kafka 內(nèi)部,消息都是以“批”為單位處理的。一批消息從發(fā)送端到接收端,是如何在 Kafka 中流轉(zhuǎn)的呢?
Producer(發(fā)送端)
Kafka 的 Producer 只提供了單條發(fā)送的 send() 方法,并沒(méi)有提供任何批量發(fā)送的接口。
kafka 根本就沒(méi)有提供單條發(fā)送的功能,是的,你沒(méi)有看錯(cuò),雖然它提供的 API 每次只能發(fā)送一條消息,但實(shí)際上,Kafka 的客戶(hù)端 SDK 在實(shí)現(xiàn)消息發(fā)送邏輯的時(shí)候,采用了異步批量發(fā)送的機(jī)制。
? 當(dāng)你調(diào)用 send() 方法發(fā)送一條消息之后,無(wú)論你是同步發(fā)送還是異步發(fā)送,Kafka 都不會(huì)立即就把這條消息發(fā)送出去。它會(huì)先把這條消息,存放在內(nèi)存中緩存起來(lái),然后選擇合適的時(shí)機(jī)把緩存中的所有消息組成一批,一次性發(fā)給 Broker。簡(jiǎn)單地說(shuō),就是攢一波一起發(fā)。
Broker(服務(wù)端)
? Kafka 不會(huì)把一批消息再還原成多條消息,再一條一條地處理,這樣太慢了。Kafka 這塊兒處理的非常聰明,每批消息都會(huì)被當(dāng)做一個(gè)“批消息”來(lái)處理。也就是說(shuō),在 Broker 整個(gè)處理流程中,無(wú)論是寫(xiě)入磁盤(pán)、從磁盤(pán)讀出來(lái)、還是復(fù)制到其他副本這些流程中,批消息都不會(huì)被解開(kāi),一直是作為一條“批消息”來(lái)進(jìn)行處理的。
? 比如說(shuō),你在客戶(hù)端發(fā)送 30 條消息,在業(yè)務(wù)程序看來(lái),是發(fā)送了 30 條消息,而對(duì)于 Kafka 的 Broker 來(lái)說(shuō),它其實(shí)就是處理了 1 條包含 30 條消息的“批消息”而已。顯然處理 1 次請(qǐng)求要比處理 30 次請(qǐng)求要快得多。
? 打包批量消息和解開(kāi)批量消息,分別在Producer和Consumer完成,不僅減輕了Broker的壓力,最重要的是減少了Broker處理請(qǐng)求的次數(shù),提升了總體的處理能力。
對(duì)比于網(wǎng)絡(luò)傳輸和內(nèi)存,磁盤(pán)IO是速度最慢的,對(duì)于消息隊(duì)列的服務(wù)端來(lái)說(shuō),性能的瓶頸主要在磁盤(pán)IO這一塊。
使用順序讀寫(xiě)來(lái)提升磁盤(pán)IO性能
? 對(duì)于磁盤(pán)來(lái)說(shuō),它有一個(gè)特性,就是順序讀寫(xiě)的性能要遠(yuǎn)遠(yuǎn)好于隨機(jī)讀寫(xiě)。在 SSD(固態(tài)硬盤(pán))上,順序讀寫(xiě)的性能要比隨機(jī)讀寫(xiě)快幾倍,如果是機(jī)械硬盤(pán),這個(gè)差距會(huì)達(dá)到幾十倍。為什么呢?
? 操作系統(tǒng)每次從磁盤(pán)讀寫(xiě)數(shù)據(jù)的時(shí)候,需要先尋址,也就是先要找到數(shù)據(jù)在磁盤(pán)上的物理位置,然后再進(jìn)行數(shù)據(jù)讀寫(xiě)。如果是機(jī)械硬盤(pán),這個(gè)尋址需要比較長(zhǎng)的時(shí)間,因?yàn)樗苿?dòng)磁頭,這是個(gè)機(jī)械運(yùn)動(dòng),機(jī)械硬盤(pán)工作的時(shí)候會(huì)發(fā)出咔咔的聲音,就是移動(dòng)磁頭發(fā)出的聲音。
? 順序讀寫(xiě)相比隨機(jī)讀寫(xiě)省去了大部分的尋址時(shí)間,它只要尋址一次,就可以連續(xù)地讀寫(xiě)下去,所以說(shuō),性能要比隨機(jī)讀寫(xiě)要好很多。
? Kafka 就是充分利用了磁盤(pán)的這個(gè)特性。它的存儲(chǔ)設(shè)計(jì)非常簡(jiǎn)單,對(duì)于每個(gè)分區(qū),它把從 Producer 收到的消息,順序地寫(xiě)入對(duì)應(yīng)的 log 文件中,一個(gè)文件寫(xiě)滿了,就開(kāi)啟一個(gè)新的文件這樣順序?qū)懴氯?。消費(fèi)的時(shí)候,也是從某個(gè)全局的位置開(kāi)始,也就是某一個(gè) log 文件中的某個(gè)位置開(kāi)始,順序地把消息讀出來(lái)。
利用 PageCache 加速消息讀寫(xiě)
? 在 Kafka 中,它會(huì)利用 PageCache 加速消息讀寫(xiě)。
PageCache 是現(xiàn)代操作系統(tǒng)都具有的一項(xiàng)基本特性。通俗地說(shuō),PageCache 就是操作系統(tǒng)在內(nèi)存中給磁盤(pán)上的文件建立的緩存。無(wú)論我們使用什么語(yǔ)言編寫(xiě)的程序,在調(diào)用系統(tǒng)的 API 讀寫(xiě)文件的時(shí)候,并不會(huì)直接去讀寫(xiě)磁盤(pán)上的文件,應(yīng)用程序?qū)嶋H操作的都是 PageCache,也就是文件在內(nèi)存中緩存的副本
PageCache 中有數(shù)據(jù),那就直接讀取,這樣就節(jié)省了從磁盤(pán)上讀取數(shù)據(jù)的時(shí)間;另一種情況是,PageCache 中沒(méi)有數(shù)據(jù),這時(shí)候操作系統(tǒng)會(huì)引發(fā)一個(gè)缺頁(yè)中斷,應(yīng)用程序的讀取線程會(huì)被阻塞,操作系統(tǒng)把數(shù)據(jù)從文件中復(fù)制到 PageCache 中,然后應(yīng)用程序再?gòu)?PageCache 中繼續(xù)把數(shù)據(jù)讀出來(lái),這時(shí)會(huì)真正讀一次磁盤(pán)上的文件,這個(gè)讀的過(guò)程就會(huì)比較慢。
用戶(hù)的應(yīng)用程序在使用完某塊 PageCache 后,操作系統(tǒng)并不會(huì)立刻就清除這個(gè) PageCache,而是盡可能地利用空閑的物理內(nèi)存保存這些 PageCache,除非系統(tǒng)內(nèi)存不夠用,操作系統(tǒng)才會(huì)清理掉一部分 PageCache。清理的策略一般是 LRU 或它的變種算法,這個(gè)算法我們不展開(kāi)講,它保留 PageCache 的邏輯是:優(yōu)先保留最近一段時(shí)間最常使用的那些 PageCache。
Kafka 在讀寫(xiě)消息文件的時(shí)候,充分利用了 PageCache 的特性。一般來(lái)說(shuō),消息剛剛寫(xiě)入到服務(wù)端就會(huì)被消費(fèi),按照 LRU 的“優(yōu)先清除最近最少使用的頁(yè)”這種策略,讀取的時(shí)候,對(duì)于這種剛剛寫(xiě)入的 PageCache,命中的幾率會(huì)非常高。
也就是說(shuō),大部分情況下,消費(fèi)讀消息都會(huì)命中 PageCache,帶來(lái)的好處有兩個(gè):一個(gè)是讀取的速度會(huì)非???,另外一個(gè)是,給寫(xiě)入消息讓出磁盤(pán)的 IO 資源,間接也提升了寫(xiě)入的性能。
可以這么理解即使什么都沒(méi)做,那么kafka的機(jī)制或者說(shuō)消息隊(duì)列的機(jī)制就已經(jīng)默認(rèn)用到了PageCache的機(jī)制,因?yàn)樽x寫(xiě)的頻率很高。
LRU算法(Least Recently Used)
LRU算法與算法實(shí)現(xiàn)
LRU-least recently used-最近最少使用算法,是一種內(nèi)存數(shù)據(jù)淘汰策略,使用常見(jiàn)是當(dāng)內(nèi)存不足時(shí),需要淘汰最近最少使用的數(shù)據(jù)。LRU常用語(yǔ)緩存系統(tǒng)的淘汰策略。
ZeroCopy:零拷貝技術(shù)
Kafka 的服務(wù)端在消費(fèi)過(guò)程中,還使用了一種“零拷貝”的操作系統(tǒng)特性來(lái)進(jìn)一步提升消費(fèi)的性能。
- 首先,從文件中找到消息數(shù)據(jù),讀到內(nèi)存中;
- 然后,把消息通過(guò)網(wǎng)絡(luò)發(fā)給客戶(hù)端。
這個(gè)過(guò)程中,數(shù)據(jù)實(shí)際上做了 2 次或者 3 次復(fù)制:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-500684.html
- 從文件復(fù)制數(shù)據(jù)到 PageCache 中,如果命中 PageCache,這一步可以省掉;
- 從 PageCache 復(fù)制到應(yīng)用程序的內(nèi)存空間中,也就是我們可以操作的對(duì)象所在的內(nèi)存;
- 從應(yīng)用程序的內(nèi)存空間復(fù)制到 Socket 的緩沖區(qū),這個(gè)過(guò)程就是我們調(diào)用網(wǎng)絡(luò)應(yīng)用框架的 API 發(fā)送數(shù)據(jù)的過(guò)程。
Kafka 使用零拷貝技術(shù)可以把這個(gè)復(fù)制次數(shù)減少一次,上面的 2、3 步驟兩次復(fù)制合并成一次復(fù)制。直接從 PageCache 中把數(shù)據(jù)復(fù)制到 Socket 緩沖區(qū)中,這樣不僅減少一次數(shù)據(jù)復(fù)制,更重要的是,由于不用把數(shù)據(jù)復(fù)制到用戶(hù)內(nèi)存空間,DMA 控制器可以直接完成數(shù)據(jù)復(fù)制,不需要 CPU 參與,速度更快。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-500684.html
總結(jié)
- 使用批量處理的方式來(lái)提升系統(tǒng)吞吐能力。
- 基于磁盤(pán)文件高性能順序讀寫(xiě)的特性來(lái)設(shè)計(jì)的存儲(chǔ)結(jié)構(gòu)。
- 利用操作系統(tǒng)的 PageCache 來(lái)緩存數(shù)據(jù),減少 IO 并提升讀性能。
- 使用零拷貝技術(shù)加速消費(fèi)流程。
到了這里,關(guān)于Kafka是如何實(shí)現(xiàn)高性能IO的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!