真厲害!1 秒寫入 10 萬(wàn)條消息,Kafka 寫得這么快,都是因?yàn)檫@些優(yōu)化!
大家好,我是樹義。
Kafka 作為消息隊(duì)列中的中堅(jiān)力量,基本上是每次面試必問的知識(shí)點(diǎn)。而說(shuō)到 Kafka,大家對(duì)它的印象就是快!異常地快!
因此,為什么 Kafka 這么快,也是每次面試必問的知識(shí)點(diǎn)。對(duì)于混跡 Java 技術(shù)圈多年的我來(lái)說(shuō),Kafka 這么快的特性已經(jīng)了然于胸。今天,就讓我?guī)е蠹冶P一盤!
Kafka 寫入速度非???,主要得益于其系統(tǒng)架構(gòu)設(shè)計(jì),包括:
- PageCache
- 批量壓縮傳輸
- 順序、批量寫磁盤
- 多 partition 分散存儲(chǔ)
PageCache
學(xué)過操作系統(tǒng)的同學(xué)都知道,內(nèi)存是易丟失的存儲(chǔ)介質(zhì),而磁盤則是不容易丟失的存儲(chǔ)介質(zhì)。但內(nèi)存讀寫速度快,而磁盤讀寫速度慢。操作系統(tǒng)為了能提高寫磁盤的速度,于是在內(nèi)存中開辟了一小塊,用來(lái)作為寫入磁盤的緩沖,提高寫磁盤的速度,這小塊內(nèi)存叫 PageCache。
Kafka 之所以這么快,其中一個(gè)很重要的點(diǎn)就是用了 PageCache。 Kafka broker 寫入消息的時(shí)候,其實(shí)并不是直接寫入文件,而是寫入系統(tǒng)的 PageCache 內(nèi)存,后續(xù)才有操作系統(tǒng)刷入文件中。通過這種方式,Kafka broker 就不直接寫文件,而是直接寫內(nèi)存,這樣就非??焖倭?!
因?yàn)橛?PageCache 的存在,也有了所謂的刷盤。簡(jiǎn)單來(lái)說(shuō),就是同步刷盤,還是異步刷盤。同步刷盤,可以理解成寫 PageCache 之后直接寫磁盤。
這樣的好處是消息不會(huì)丟失,但是壞處就是速度慢。異步刷盤則相反,寫 PageCache 之后就結(jié)束,等待操作系統(tǒng)異步刷盤。這里說(shuō)的「盤」指的就是「磁盤」。
Kafka 因此也提供了兩個(gè)參數(shù)來(lái)控制刷盤方式,分別是:log.flush.interval.messages? 和 log.flush.interval.ms。前者表示數(shù)據(jù)達(dá)到多少條就將消息刷到磁盤,如果你希望數(shù)據(jù)不丟失,那么必須設(shè)置為 1。后者表示多久將累積的消息刷到磁盤。這兩個(gè)參數(shù)任何一個(gè)達(dá)到指定值就觸發(fā)寫入。
批量壓縮傳輸
我們都知道 Kafka 消息都是由生產(chǎn)者發(fā)送給 Kafka 服務(wù)器,再由 Kafka 服務(wù)器存儲(chǔ)起來(lái)的。在很多情況下,系統(tǒng)的瓶頸不是 CPU 或磁盤,而是網(wǎng)絡(luò)帶寬,對(duì)于需要在廣域網(wǎng)上的數(shù)據(jù)中心之間發(fā)送消息的數(shù)據(jù)流水線尤其如此。
Kafka 之所以能這么快,其中有一個(gè)很重要的原因是采用了批量壓縮傳輸。在 Kafka 提供的客戶端里,其每次發(fā)送給 Kafka 服務(wù)器的時(shí)候,并不是一條消息一條消息發(fā)送,而是一批消息一批消息發(fā)送,并且還會(huì)啟用數(shù)據(jù)壓縮算法。通過這種方式,原本可能 1 秒只能發(fā)送 1 條的能力,瞬間提升到了 1 千條,甚至一萬(wàn)條。
順序、批量寫磁盤
當(dāng)消息到了 Kafka 服務(wù)器之后,Kafka 寫入內(nèi)存,最終還是需要寫入磁盤。我們知道現(xiàn)在的磁盤大多數(shù)都還是機(jī)械結(jié)構(gòu)(SSD 不在討論的范圍內(nèi))。
如果將消息以隨機(jī)寫的方式存入磁盤,就會(huì)按柱面、磁頭、扇區(qū)的方式進(jìn)行(尋址過程),緩慢的機(jī)械運(yùn)動(dòng)(相對(duì)內(nèi)存)會(huì)消耗大量時(shí)間,導(dǎo)致磁盤的寫入速度只能達(dá)到內(nèi)存寫入速度的幾百萬(wàn)分之一。
為了規(guī)避隨機(jī)寫帶來(lái)的時(shí)間消耗,Kafka 采取順序?qū)懙姆绞酱鎯?chǔ)數(shù)據(jù),這樣就減少了尋址的時(shí)間,極大地提高了寫入速度。因此順序?qū)懭氪疟P,是 Kafka 之所以這么快的一個(gè)關(guān)鍵原因。 其次,Kafka 也采用消息批量寫入磁盤的方式,每次寫入一批數(shù)據(jù),而不是只寫入一條消息,這樣就極大地提高了效率。
多 partition 分散存儲(chǔ)
我們知道磁盤的寫入是有物理極限的,如果同時(shí)有特別多的線程寫入,達(dá)到了物理極限,那么其他線程就只能等待了。而 Kafka 存儲(chǔ)的特點(diǎn)是小文件存儲(chǔ),并且切分成多個(gè) Partition,分散在多個(gè)機(jī)器。這樣讀取的時(shí)候就可以充分利用磁盤的 IO,從而達(dá)到高效讀取的目的。
試想,如果文件太大,并且只存在一個(gè)磁盤,那么該磁盤的壓力得有多大?
總結(jié)
Kafka 的寫入流程可以分為將數(shù)據(jù)傳輸?shù)?Kafka 服務(wù)器,之后將數(shù)據(jù)寫入磁盤。在數(shù)據(jù)傳輸階段,Kafka 利用批量加壓縮的方式,極大地提升了每次能發(fā)送的數(shù)據(jù)量,從而提高了寫入速度。
而在寫入磁盤環(huán)節(jié),通過存儲(chǔ)結(jié)構(gòu)的設(shè)計(jì),使得 Kafka 可以批量、順序?qū)懭?,從而減少磁盤尋道的時(shí)間。并且通過小文件的存儲(chǔ)方式,提高了整體磁盤的耐受力。
批量寫入、壓縮的傳輸方式,與磁盤順序?qū)懭?、小文件?partition 造就了 Kafka 強(qiáng)悍的寫入速度!