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