歡迎關注微信公衆號:石杉的架構筆記(id:shishan100)編程
個人新課**《C2C 電商系統微服務架構120天實戰訓練營》在公衆號儒猿技術窩**上線了,感興趣的同窗,能夠點擊下方連接瞭解詳情:微信
《C2C 電商系統微服務架構120天實戰訓練營》markdown
「 這篇文章,給你們聊一個生產環境的實踐經驗:線上系統部署的時候,JVM堆內存大小是越大越好嗎?架構
先說明白一個前提,本文主要討論的是Kafka和Elasticsearch兩種分佈式系統的線上部署狀況,不是普通的Java應用系統。併發
先說明一點,不論是咱們本身開發的Java應用系統,仍是一些中間件系統,在實現的時候都須要選擇是否基於本身Java進程的內存來處理數據。app
你們應該都知道,Java、Scala等編程語言底層依賴的都是JVM,那麼只要是使用JVM,就能夠考慮在JVM進程的內存中來放置大量的數據。elasticsearch
仍是給你們舉個例子,你們應該還記得以前聊過消息中間件系統。編程語言
好比說系統A能夠給系統B發送一條消息,那麼中間須要依賴一個消息中間件,系統A要先把消息發送到消息中間件,而後系統B從這個消息中間件消費到這條消息。分佈式
你們看下面的示意圖。微服務
你們應該都知道,一條消息發送到消息中間件以後,有一種處理方式,就是把這條數據先緩衝在本身的JVM內存裏。
而後過一段時間以後,再從本身的內存刷新到磁盤上去,這樣能夠持久化保存這條消息,以下圖。
若是用相似上述的方式,依賴Java系統自身內存處理數據,好比說設計一個內存緩衝區,來緩衝住高併發寫入的大量消息,那麼是有其缺陷的。
最大的缺陷,其實就是JVM的GC問題,這個GC就是垃圾回收,這裏簡單說一下他是怎麼回事。
你們能夠想一下,若是一個Java進程裏總是塞入不少的數據,這些數據都是用來緩衝在內存裏的,可是過一下子這些數據都會寫入磁盤。
那麼寫入磁盤以後,這些數據還須要繼續放在內存裏嗎?
明顯是不須要的了,此時就會依託JVM垃圾回收機制,把內存裏那些不須要的數據給回收掉,釋放掉那些內存空間騰出來。
可是JVM垃圾回收的時候,有一種狀況叫作stop the world,就是他會中止你的工做線程,就專門讓他進行垃圾回收。
這個時候,他在垃圾回收的時候,有可能你的這個中間件系統就運行不了了。
好比你發送請求給他,他可能都無法響應給你,由於他的接收請求的工做線程都停了,如今人家後臺的垃圾回收線程正在回收垃圾對象。
你們看下圖。
雖說如今JVM的垃圾回收器一直在不斷的演進和發展,從CMS到G1,儘量的在下降垃圾回收的時候的影響,減小工做線程的停頓。
可是你要是徹底依賴JVM內存來管理大量的數據,那在垃圾回收的時候,或多或少老是有影響的。
因此特別是對於一些大數據系統,中間件系統,這個JVM的GC(Garbage Collector,垃圾回收)問題,真是最頭疼的一個問題。
因此相似Kafka、Elasticsearch等分佈式中間件系統,雖然也是基於JVM運行的,可是他們都選擇了依賴OS Cache來管理大量的數據。
也就是說,是操做系統管理的內存緩衝,而不是依賴JVM自身內存來管理大量的數據。
具體來講,好比說Kafka吧,若是你寫一條數據到Kafka,他實際上會直接寫入磁盤文件。
可是磁盤文件在寫入以前其實會進入os cache,也就是操做系統管理的內存空間,而後過一段時間,操做系統本身會選擇把他的os cache的數據刷入磁盤。
而後後續在消費數據的時候,其實也會優先從os cache(內存緩衝)裏來讀取數據。
至關於寫數據和讀數據都是依託於os cache來進行的,徹底依託操做系統級別的內存區域來進行,讀寫性能都很高。
此外,還有另一個好處,就是不要依託自身JVM來緩衝大量的數據,這樣能夠避免複雜並且耗時的JVM垃圾回收操做。
你們看下面的圖,其實就是一個典型的Kafka的運行流程。
而後好比Elasticsearch,他做爲一個如今最流行的分佈式搜索系統,也是採用類相似的機制。
大量的依賴os cache來緩衝大量的數據,而後在進行搜索和查詢的時候,也能夠優先從os cache(內存區域)中讀取數據,這樣就能夠保證很是高的讀寫性能。
因此如今就能夠進入咱們的主題了,那麼好比就以上述說的kafka、elasticsearch等系統而言,在線上生產環境部署的時候,你知道他們是大量依賴於os cache來緩衝大量數據的。
那麼,給他們分配JVM堆內存大小的時候是越大越好嗎?
明顯不是的,假如說你有一臺機器,有32GB的內存,如今你若是在搞不清楚情況的狀況下,要是傻傻的認爲仍是給JVM分配越大內存越好,此時好比給了16G的堆內存空間給JVM,那麼os cache剩下的內存,可能就不到10GB了,由於自己其餘的程序還要佔用幾個GB的內存。
那若是是這樣的話,就會致使你在寫入磁盤的時候,os cache能容納的數據量頗有限。
好比說一共有20G的數據要寫入磁盤,如今就只有10GB的數據能夠放在os cache裏,而後另外10GB的數據就只能放在磁盤上。
此時在讀取數據的時候,那麼起碼有一半的讀取請求,必須從磁盤上去讀了,無法從os cache裏讀,誰讓你os cache裏就只能放的下10G的一半大小的數據啊,另一半都在磁盤裏,這也是沒辦法的,以下圖。
那此時你有一半的請求都是從磁盤上在讀取數據,必然會致使性能不好。
因此不少人在用Elasticsearch的時候就是這樣的一個問題,總是以爲ES讀取速度慢,幾個億的數據寫入ES,讀取的時候要好幾秒。
那能不花費好幾秒嗎?你要是ES集羣部署的時候,給JVM內存過大,給os cache留了幾個GB的內存,致使幾億條數據大部分都在磁盤上,不在os cache裏,最後讀取的時候大量讀磁盤,耗費個幾秒鐘是很正常的。
因此說,針對相似Kafka、Elasticsearch這種生產系統部署的時候,應該要給JVM好比6GB或者幾個GB的內存就能夠了。
由於他們可能不須要耗費過大的內存空間,不依賴JVM內存管理數據,固然具體是設置多少,須要你精準的壓測和優化。
可是對於這類系統,應該給os cache留出來足夠的內存空間,好比32GB內存的機器,徹底能夠給os cache留出來20多G的內存空間,那麼此時假設你這臺機器總共就寫入了20GB的數據,就能夠所有駐留在os cache裏了。
而後後續在查詢數據的時候,不就能夠所有從os cache裏讀取數據了,徹底依託內存來走,那你的性能必然是毫秒級的,不可能出現幾秒鐘才完成一個查詢的狀況。
整個過程,以下圖所示:
因此說,建議你們在線上生產系統引入任何技術的時候,都應該先對這個技術的原理,甚至源碼進行深刻的理解,知道他具體的工做流程是什麼,而後針對性的合理設計生產環境的部署方案,保證最佳的生產性能。
END