ElasticSearch中的JVM性能調優

ElasticSearch中的JVM性能調優

前一段時間被人問了個問題:在使用ES的過程當中有沒有作過什麼JVM調優措施?html

在我搭建ES集羣過程當中,參照important-settings官方文檔來的,並無對JVM參數作過多的調整。其實談JVM配置參數,少不了操做系統層面上的一些配置參數,好比 page cache。同時ES進程須要打開大量文件,文件描述符的個數(/etc/security/limits.conf)也要配置得大一些。這裏簡要介紹一下關於ES JVM參數的配置:算法

  • 將 xms 和 xmx 設置成同樣大 避免JVM堆的動態調整給應用進程帶來"不穩定"sql

  • 預留足夠的內存空間給page cache。後面會重點討論爲何要這麼作?緩存

  • 禁用內存交換,後面解釋爲何要禁用內存交換?併發

  • 配置JVM參數:-XX:+AlwaysPreTouch 減小新生代晉升到老年代時停頓。app

    啓動時就把參數裏說好了的內存所有舔一遍,可能令得啓動時慢上一點,但後面訪問時會更流暢,好比頁面會連續分配,好比不會在晉升新生代到老生代時纔去訪問頁面使得GC停頓時間加長less

  • -XX:CMSInitiatingOccupancyFraction 設置成75%。主要是由於CMS是併發收集,垃圾回收線程和用戶線程同時運行,老年代使用到75%就回收減小OOM異常。異步

  • -XX:MaxTenuringThreshold 設置成6。默認Survivor區對象經歷15次Young GC後進入老年代,設置成6就只需6次YGC就晉升到老年代了。由於ES新生代採用 -XX:+UseParNewGC,關於這個參數的調優說明,可參考:關鍵業務系統的JVM參數推薦(2018仲夏版)jvm

    Young GC是最大的應用停頓來源,而新生代裏GC後存活對象的多少又直接影響停頓的時間,因此若是清楚Young GC的執行頻率和應用裏大部分臨時對象的最長生命週期,能夠把它設的更短一點,讓其實不是臨時對象的新生代對象趕忙晉升到年老代elasticsearch

  • -Xss 配置爲1M。線程佔用棧內存,默認每條線程爲1M。從這個參數可看出一個進程下可建立的線程數量是有限制的,可視爲建立線程的開銷。

page cache 與 應用程序內存

Linux內存可分紅2種類型:Page cache和應用程序內存。應用程序內存會被Linux的swap機制交換出去,而page cache則是由Linux後臺的異步flush策略刷盤。當OS內存滿了時,就須要把一部份內存數據寫入磁盤,所以就須要決定是swap應用程序內存呢?仍是清理page cache?OS有個系統參數/proc/sys/vm/swappiness默認值60,通常將之設置成0,表示優先刷新page cache而不是將應用程序的內存交換出去。

那Linux的page cache的清除策略是什麼呢?--優化了的LRU算法。LRU存在缺點:那些新讀取的但卻只使用一次的數據佔滿了LRU列表,反而把熱點數據給evict 到磁盤上去了,所以還須要考慮數據的訪問次數(頻率)

不少存儲系統針對LRU作了一些優化,好比Redis的鍵過時策略是基於LRU算法的思想,用若干個位記錄每一個key的idle time(空閒時間),將空閒時間較大的key存入pool,從pool中選擇key evict出去,具體可參考:Redis的LRU算法。 再好比Mysql innodb 緩衝池管理page也是基於LRU,當新讀入一頁數據時不是當即放到LRU鏈表頭,而是設置mid point(默認37%),即放到鏈表37%位置處 。關於如何理解page cache 與應用程序內存之間的區別,可參考這篇文章:從Apache Kafka 重溫文件高效讀寫

Linux總會把系統中還沒被應用使用的內存挪來給Page Cache,在命令行輸入free,或者cat /proc/meminfo,"Cached"的部分就是Page Cache。

當Linux系統內存不足時,要麼就回收page cache,要麼就內存交換(swap),而內存交換就有可能把應用程序的數據換出到磁盤上去了,這就有可能形成應用的長時間停頓了。參考:在你的代碼以外,服務時延過長的三個追查方向(上)

Linux有個很怪的癖好,當內存不足時,有很大機率不是把用做IO緩存的Page Cache收回,而是把冷的應用內存page out到磁盤上。當這段內存從新要被訪問時,再把它從新page in回內存(所謂的主缺頁錯誤),這個過程進程是停頓的。增加緩慢的老生代,池化的堆外內存,均可能被認爲是冷內存,用 cat /proc/[pid]/status 看看 VmSwap的大小, 再dstat裏看看監控page in發生的時間。

一個JVM長時間停頓的示例

隨着系統的運行,JVM堆內存會被使用,引用不可達對象就是垃圾對象,而操做系統有可能會把這些垃圾對象交換到磁盤上去。當JVM堆使用到必定程度時,觸發FullGC,FullGC過程當中發現這些未引用的對象都被交換到磁盤上去了,因而JVM垃圾回收進程得把它們從新讀回來到內存中,然而戲劇性的是:這些未引用的對象自己就是垃圾,讀到內存中的目的是回收被丟棄它們!而這種來回讀取磁盤的操做致使了FullGC 消耗了大量時間,(有可能)發生長時間的stop the world。所以,須要禁用內存交換以免這種現象,這也是爲何在部署Kafka和ES的機器上都應該要禁用內存交換的緣由吧。具體可參考這篇文章:Just say no to swapping!

總結

本文以ES使用的JVM配置參數爲示例,記錄了一些關於JVM調優的參數理解,以及涉及到的一些關於page cache、應用程序內存區別,LRU算法思想等,它們在Mysql、Kafka、ElasticSearch都有所應用。文中給出的參考連接都很是好,對深刻理解系統底層運行原理有幫助。

原文:http://www.javashuo.com/article/p-awjabcnp-dg.html

相關文章
相關標籤/搜索