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