Kafka 如何最佳化記憶體緩衝機制造成的頻繁 GC 問題?
目錄
1、Kafka的客戶端緩衝機制
2、記憶體緩衝造成的頻繁GC問題
3、Kafka設計者實現的緩衝池機制
4、總結一下
“ 這篇文章,給大家聊一個硬核的技術知識,我們透過Kafka核心原始碼中的一些設計思想,來看你設計Kafka架構的技術大牛,是怎麼最佳化JVM的GC問題的?
首先,先得給大家明確一個事情,那就是在客戶端傳送訊息給kafka伺服器的時候,一定是有一個記憶體緩衝機制的。
也就是說,訊息會先寫入一個記憶體緩衝中,然後直到多條訊息組成了一個Batch,才會一次網路通訊把Batch傳送過去。
整個過程如下圖所示:
那麼這種記憶體緩衝機制的本意,其實就是把多條訊息組成一個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作者在設計的時候展現出的優秀的技術設計思想和能力。
希望大家多吸取這裡的精華,在以後面試或者工作的時候,可以把這些優秀的思想納為己用。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69901780/viewspace-2659417/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 線上排查:記憶體異常使用導致full gc頻繁記憶體GC
- project中的堆疊記憶體,記憶體地址引用,gc相關問題Project記憶體GC
- GC最佳化:棧記憶體、span、NativeMemory、指標、池化記憶體 筆記GC記憶體指標筆記
- jvm:記憶體模型、記憶體分配及GC垃圾回收機制JVM記憶體模型GC
- 調整緩衝區快取記憶體(Buffer Cache)的效能(轉)快取記憶體
- JVM記憶體-GC策略JVM記憶體GC
- 關於JVM 記憶體的 N 個高頻面試問題!JVM記憶體面試
- JVM記憶體GC的騙局JVM記憶體GC
- Chrome 再次最佳化記憶體佔用問題,新增記憶體釋放開關Chrome記憶體
- 頻繁GC (Allocation Failure)及young gc時間過長分析GCAI
- [React]setState呼叫過於頻繁的問題React
- Go記憶體分配和GC的理解Go記憶體GC
- 【高頻Java面試題】簡單說說JVM堆的記憶體結構和GC回收流程Java面試題JVM記憶體GC
- 排查Java的記憶體問題Java記憶體
- WPF頻繁更新UI卡頓問題UI
- 記一次生產頻繁發生FullGC問題GC
- 記憶體碎片與緩解記憶體
- DDR4記憶體頻率2400和3000的區別 高頻記憶體與低頻記憶體效能效能對比記憶體
- JVM GC 與 記憶體分配策略JVMGC記憶體
- JVM中記憶體和GC的介紹JVM記憶體GC
- 探究 iOS 記憶體問題iOS記憶體
- SQLServer記憶體問題分析SQLServer記憶體
- 開發小程式被問到最頻繁的問題(上)
- webGL 緩解記憶體壓力Web記憶體
- 如何解決JVM OutOfMemoryError記憶體洩漏問題?JVMError記憶體
- jvm堆記憶體和GC簡介JVM記憶體GC
- Go語言高併發與微服務實戰專題精講——遠端過程呼叫 RPC——最佳化RPC呼叫,緩解頻繁請求導致的GC壓力Go微服務RPC求導GC
- 史丹佛大學:研究發現頻繁的媒體多工操作影響記憶力
- 記憶體分配問題處理記憶體
- ThreadLocal記憶體洩漏問題thread記憶體
- 關於echarts+vue頻繁重新整理的造成的記憶體增長問題EchartsVue記憶體
- 解決golang 的記憶體碎片問題Golang記憶體
- JVM 自動記憶體管理機制及 GC 演算法JVM記憶體GC演算法
- win10如何檢視記憶體執行頻率_win10檢視記憶體執行頻率的方法Win10記憶體
- Java記憶體模型FAQ(五)舊的記憶體模型有什麼問題?Java記憶體模型
- Java記憶體模型及GC演算法Java記憶體模型GC演算法
- 告別記憶體OOM,解決MySQL記憶體增長問題記憶體OOMMySql
- 記憶體最佳化:Boxing記憶體