我的公衆號:石杉的架構筆記(ID:shishan100)
面試
目錄服務器
一、Kafka的客戶端緩衝機制網絡
二、內存緩衝形成的頻繁GC問題架構
三、Kafka設計者實現的緩衝池機制性能
四、總結一下學習
「 這篇文章,一樣給你們聊一個硬核的技術知識,咱們經過Kafka內核源碼中的一些設計思想,來看你設計Kafka架構的技術大牛,是怎麼優化JVM的GC問題的?優化
首先,先得給你們明確一個事情,那就是在客戶端發送消息給kafka服務器的時候,必定是有一個內存緩衝機制的。線程
也就是說,消息會先寫入一個內存緩衝中,而後直到多條消息組成了一個Batch,纔會一次網絡通訊把Batch發送過去。設計
整個過程以下圖所示:cdn
那麼這種內存緩衝機制的本意,其實就是把多條消息組成一個Batch,一次網絡請求就是一個Batch或者多個Batch。
這樣每次網絡請求均可以發送不少數據過去,避免了一條消息一次網絡請求。從而提高了吞吐量,即單位時間內發送的數據量。
可是問題來了,你們能夠思考一下,一個Batch中的數據,會取出來而後封裝在底層的網絡包裏,經過網絡發送出去到達Kafka服務器。
那麼而後呢?這個Batch裏的數據都發送過去了,如今Batch裏的數據應該怎麼處理?
你要知道,這些Batch裏的數據此時可還在客戶端的JVM的內存裏啊!那麼此時從代碼實現層面,必定會嘗試避免任何變量去引用這些Batch對應的數據,而後嘗試觸發JVM自動回收掉這些內存垃圾。
這樣不斷的讓JVM回收垃圾,就能夠不斷的清理掉已經發送成功的Batch了,而後就能夠不斷的騰出來新的內存空間讓後面新的數據來使用。
這種想法很好,可是實際線上運行的時候必定會有問題,最大的問題,就是JVM GC問題。
你們都知道一點,JVM GC在回收內存垃圾的時候,他會有一個「Stop the World」的過程,也就是垃圾回收線程運行的時候,會致使其餘工做線程短暫的停頓,這樣能夠便於他本身安安靜靜的回收內存垃圾。
這個也很容易想明白,畢竟你要是在回收內存垃圾的時候,你的工做線程還在不斷的往內存裏寫數據,製造更多的內存垃圾,那你讓人家JVM怎麼回收垃圾?
這就比如在大馬路上,若是地上有不少垃圾,如今要把垃圾都掃乾淨,最好的辦法是什麼?你們都讓開,把馬路空出來,而後清潔工就是把垃圾清理乾淨。
可是若是清潔工在清掃垃圾的時候,結果一幫人在旁邊不停的嗑瓜子扔瓜子殼,吃西瓜扔西瓜皮,不停的製造垃圾,你以爲清潔工心裏啥感覺?固然是很憤慨了,照這麼搞,地上的垃圾永遠的都搞不乾淨了!
經過了上面的語言描述,咱們再來一張圖,你們看看就更加清楚了
如今JVM GC是愈來愈先進,從CMS垃圾回收器到G1垃圾回收器,核心的目標之一就是不斷的縮減垃圾回收的時候,致使其餘工做線程停頓的時間。
因此如今越是新款的垃圾回收器致使工做線程停頓的時間越短,可是再怎麼短,他也仍是存在啊!
因此說,如何儘量在本身的設計上避免JVM頻繁的GC就是一個很是考驗水平的事兒了。
在Kafka客戶端內部,對這個問題實現了一個很是優秀的機制,就是緩衝池的機制
簡單來講,就是每一個Batch底層都對應一塊內存空間,這個內存空間就是專門用來存放寫入進去的消息的。
而後呢,當一個Batch被髮送到了kafka服務器,這個Batch的數據再也不須要了,就意味着這個Batch的內存空間再也不使用了。
此時這個Batch底層的內存空間不要交給JVM去垃圾回收,而是把這塊內存空間給放入一個緩衝池裏。
這個緩衝池裏放了不少塊內存空間,下次若是你又有一個新的Batch了,那麼不就能夠直接從這個緩衝池裏獲取一塊內存空間就ok了?
而後若是一個Batch發送出去了以後,再把內存空間給人家還回來不就行了?以此類推,循環往復。
一樣,聽完了上面的文字描述,再來一張圖,看完這張圖相信大夥兒就明白了:
一旦使用了這個緩衝池機制以後,就不涉及到頻繁的大量內存的GC問題了。
爲何呢?由於他能夠上來就佔用固定的內存,好比32MB。而後把32MB劃分爲N多個內存塊,好比說一個內存塊是16KB,這樣的話這個緩衝池裏就會有不少的內存塊。
而後你須要建立一個新的Batch,就從緩衝池裏取一個16KB的內存塊就能夠了,而後這個Batch就不斷的寫入消息,可是最多就是寫16KB,由於Batch底層的內存塊就16KB。
接着若是Batch被髮送到Kafka服務器了,此時Batch底層的內存塊就直接還回緩衝池就能夠了。
下次別人再要構建一個Batch的時候,再次使用緩衝池裏的內存塊就行了。這樣就能夠利用有限的內存,對他不停的反覆重複的利用。由於若是你的Batch使用完了之後是把內存塊還回到緩衝池中去,那麼就不涉及到垃圾回收了。
若是沒有頻繁的垃圾回收,天然就避免了頻繁致使的工做線程的停頓了,JVM GC問題是否是就獲得了大幅度的優化?
沒錯,正是這個設計思想讓Kafka客戶端的性能和吞吐量都很是的高,這裏蘊含了大量的優秀的機制。
那麼此時有人說了,若是我如今把一個緩衝池裏的內存資源都佔滿了,如今緩衝池裏暫時沒有內存塊了,怎麼辦呢?
很簡單,阻塞你的寫入操做,不讓你繼續寫入消息了。把你給阻塞住,不停的等待,直到有內存塊釋放出來,而後再繼續讓你寫入消息。
這篇文章咱們從Kafka內存緩衝機制的設計思路開始,一直分析到了JVM GC問題的產生緣由以及惡劣的影響。
接着談到了Kafka優秀的緩衝池機制的設計思想以及他是如何解決這個問題的,分析了不少Kafka做者在設計的時候展示出的優秀的技術設計思想和能力。
但願你們多吸收這裏的精華,在之後面試或者工做的時候,能夠把這些優秀的思想納爲己用。
歡迎長按下圖關注公衆號:石杉的架構筆記!
公衆號後臺回覆資料,獲取做者獨家祕製學習資料
石杉的架構筆記,BAT架構經驗傾囊相授