##1/2)HBase最佳實(shí)踐-CMS GC調(diào)優(yōu)

HBase最佳實(shí)踐-CMS GC調(diào)優(yōu) – 有態(tài)度的HBase/Spark/BigData http://hbasefly.com/2016/08/09/hbase-cms-gc/

//
CMS GC工作原理

  1. 整個(gè)對(duì)象生命周期簡(jiǎn)要說明(一定要爛熟于心,下文會(huì)一直用到):
    (1)Young區(qū):一個(gè)對(duì)象初始化之后,首先會(huì)進(jìn)入Eden區(qū),當(dāng)Eden區(qū)滿之后會(huì)觸發(fā)一次Minor GC,Minor GC會(huì)檢查Eden區(qū)所有對(duì)象是否依舊存活(是否有其他對(duì)象引用),如果存活,會(huì)將其從Eden區(qū)拷貝到Survivor區(qū),并將這些存活對(duì)象的age加一,而死亡的對(duì)象會(huì)被作為垃圾回收。此時(shí)Eden區(qū)又空閑出來,等新對(duì)象填充,填充滿之后再會(huì)觸發(fā)Minor GC,如此往復(fù)。需要注意的是,每執(zhí)行一次Minor GC,存活對(duì)象的age就會(huì)加一。
    (2)Tenured區(qū):一旦存活對(duì)象的age超多一定閾值就會(huì)晉升到Tenured區(qū),因此可以理解為Tenured區(qū)一般存放長(zhǎng)壽對(duì)象。很顯然,隨著時(shí)間流逝,Tenured區(qū)也會(huì)被填充滿,此時(shí)就會(huì)觸發(fā)CMS GC(old gc),這種GC相對(duì)比較復(fù)雜,由5個(gè)步驟組成,詳見參考文章。
  2. 無論是Minor GC還是CMS GC,都會(huì)’Stop-The-World’,即停止用戶的一切線程,只留下gc線程回收垃圾對(duì)象。其中Minor GC的STW時(shí)間主要耗費(fèi)在復(fù)制階段,CMS GC的STW時(shí)間主要耗費(fèi)在標(biāo)示垃圾對(duì)象階段。

//
同時(shí)也提到幾個(gè)對(duì)性能影響重大的參數(shù):Xmn、SurvivorRatio以及MaxTenuringThreshold,下面會(huì)通過理論推理+實(shí)驗(yàn)驗(yàn)證的方式對(duì)這幾個(gè)參數(shù)在HBase系統(tǒng)的設(shè)置進(jìn)行調(diào)優(yōu)。

//
GC調(diào)優(yōu)的最終目標(biāo)和基本原則:

  1. 平均Minor GC時(shí)間盡可能短。因?yàn)檎麄€(gè)Minor GC都處于STW,因此短時(shí)間Minor GC會(huì)使用戶讀寫更加平穩(wěn),延遲可控。
  2. CMS GC次數(shù)越少越好。時(shí)間越短越好。一方面是因?yàn)橐淮蜟MS GC一般都會(huì)引起至少秒級(jí)的應(yīng)用暫停,對(duì)用戶讀寫影響較大;另一方面頻繁的CMS GC會(huì)產(chǎn)生大量的內(nèi)存碎片,嚴(yán)重的時(shí)候會(huì)引起Full GC,導(dǎo)致RegionServer宕機(jī)。

//
Xmn設(shè)置過小會(huì)導(dǎo)致CMS GC性能較差,而設(shè)置過大會(huì)導(dǎo)致Minor GC性能較差,因此建議在JVM Heap為64g以上的情況下設(shè)置Xmn在1~3g之間,在32g之下設(shè)置為512m~1g;具體最好經(jīng)過簡(jiǎn)單的線上調(diào)試;需要特別強(qiáng)調(diào)的是,筆者在很多場(chǎng)合都看到很多HBase線上集群會(huì)把Xmn設(shè)置的很大,比如有些集群Xmx為48g,Xmn為10g,查看日志發(fā)現(xiàn)GC性能極差:?jiǎn)未蜯inor GC基本都在300ms~500ms之間,CMS GC更是很多超過1s。在此強(qiáng)烈建議,將Xmn調(diào)大對(duì)GC(無論Minor GC還是CMS GC)沒有任何好處,不要設(shè)置太大。

//
CMS調(diào)優(yōu)結(jié)論

  1. 緩存模式采用BucketCache策略O(shè)ffheap模式

  2. 對(duì)于大內(nèi)存(大于64G),采用如下配置:

-Xmx64g -Xms64g -Xmn2g -Xss256k -XX:MaxPermSize=256m -XX:+SurvivorRatio=2 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
-XX:+CMSParallelRemarkEnabled -XX:+MaxTenuringThreshold=15 -XX:+UseCMSCompactAtFullCollection -XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=75 -XX:-DisableExplicitGC
其中Xmn可以隨著Java分配堆內(nèi)存增大而適度增大,但是不能大于4g,取值范圍在1~3g范圍;SurvivorRatio一般建議選擇為2;MaxTenuringThreshold設(shè)置為15;

3 對(duì)于小內(nèi)存(小于64G),只需要將上述配置中Xmn改為512m-1g即可


HBase發(fā)展到當(dāng)下,對(duì)其進(jìn)行的各種優(yōu)化從未停止,而GC優(yōu)化更是其中的重中之重。從0.94版本提出MemStoreLAB策略、Memstore Chuck Pool策略對(duì)寫緩存Memstore進(jìn)行優(yōu)化開始,到0.96版本提出BucketCache以及堆外內(nèi)存方案對(duì)讀緩存BlockCache進(jìn)行優(yōu)化,再到后續(xù)2.0版本宣稱會(huì)引入更多堆外內(nèi)存,可見HBase會(huì)將堆外內(nèi)存的使用作為優(yōu)化GC的一個(gè)戰(zhàn)略方向。然而無論引入多少堆外內(nèi)存,都無法避免讀寫全路徑使用JVM內(nèi)存,就拿BucketCache中offheap模式來講,即使HBase數(shù)據(jù)塊是緩存在堆外內(nèi)存的,但是在讀取的時(shí)候還是會(huì)首先將堆外內(nèi)存中的block加載到JVM內(nèi)存中,再返回給用戶。可見,無論使用多少堆外內(nèi)存,對(duì)JVM內(nèi)存的使用終究是繞不過去,既然繞不過去,就還是需要落腳于GC本身,對(duì)GC本身進(jìn)行優(yōu)化。本文就將會(huì)介紹HBase應(yīng)用場(chǎng)景下CMS GC策略的調(diào)優(yōu)技巧,后續(xù)還會(huì)針對(duì)另一業(yè)界開始使用的GC策略-G1GC策略在HBase應(yīng)用場(chǎng)景下進(jìn)行調(diào)優(yōu)介紹。

CMS GC工作原理
如果看官已經(jīng)對(duì)CMS GC工作原理比較熟悉,完全可以跳過本節(jié)內(nèi)容,直接進(jìn)入下節(jié)。如果看官還對(duì)CMS GC不是很了解,可以參考筆者之前的另一篇文章《HBase GC的前生今生-身世篇》,文中對(duì)JVM的內(nèi)存結(jié)構(gòu)以及CMS GC進(jìn)行了相當(dāng)詳細(xì)的介紹。為了下文介紹方便,在此還是對(duì)其中的一些重要知識(shí)點(diǎn)進(jìn)行提煉:

  1. 整個(gè)JVM內(nèi)存由Young區(qū)、Tenured區(qū)和Perm區(qū)三部分組成,其中Young區(qū)又分為一個(gè)Eden區(qū)和兩個(gè)Survivor區(qū)

  2. 整個(gè)對(duì)象生命周期簡(jiǎn)要說明(一定要爛熟于心,下文會(huì)一直用到):
    (1)Young區(qū):一個(gè)對(duì)象初始化之后,首先會(huì)進(jìn)入Eden區(qū),當(dāng)Eden區(qū)滿之后會(huì)觸發(fā)一次Minor GC,Minor GC會(huì)檢查Eden區(qū)所有對(duì)象是否依舊存活(是否有其他對(duì)象引用),如果存活,會(huì)將其從Eden區(qū)拷貝到Survivor區(qū),并將這些存活對(duì)象的age加一,而死亡的對(duì)象會(huì)被作為垃圾回收。此時(shí)Eden區(qū)又空閑出來,等新對(duì)象填充,填充滿之后再會(huì)觸發(fā)Minor GC,如此往復(fù)。需要注意的是,每執(zhí)行一次Minor GC,存活對(duì)象的age就會(huì)加一。
    (2)Tenured區(qū):一旦存活對(duì)象的age超多一定閾值就會(huì)晉升到Tenured區(qū),因此可以理解為Tenured區(qū)一般存放長(zhǎng)壽對(duì)象。很顯然,隨著時(shí)間流逝,Tenured區(qū)也會(huì)被填充滿,此時(shí)就會(huì)觸發(fā)CMS GC(old gc),這種GC相對(duì)比較復(fù)雜,由5個(gè)步驟組成,詳見參考文章。

  3. 無論是Minor GC還是CMS GC,都會(huì)’Stop-The-World’,即停止用戶的一切線程,只留下gc線程回收垃圾對(duì)象。其中Minor GC的STW時(shí)間主要耗費(fèi)在復(fù)制階段,CMS GC的STW時(shí)間主要耗費(fèi)在標(biāo)示垃圾對(duì)象階段。

GC調(diào)優(yōu)目標(biāo)
上節(jié)簡(jiǎn)單介紹了Java虛擬機(jī)的內(nèi)存結(jié)構(gòu)以及Java GC的基本知識(shí),接下來會(huì)在此基礎(chǔ)上介紹HBase集群中GC的幾種參數(shù)調(diào)優(yōu)技巧。在介紹具體的調(diào)優(yōu)技巧之前,有必要先來看看GC調(diào)優(yōu)的最終目標(biāo)和基本原則:

  1. 平均Minor GC時(shí)間盡可能短。因?yàn)檎麄€(gè)Minor GC都處于STW,因此短時(shí)間Minor GC會(huì)使用戶讀寫更加平穩(wěn),延遲可控。
  2. CMS GC次數(shù)越少越好。時(shí)間越短越好。一方面是因?yàn)橐淮蜟MS GC一般都會(huì)引起至少秒級(jí)的應(yīng)用暫停,對(duì)用戶讀寫影響較大;另一方面頻繁的CMS GC會(huì)產(chǎn)生大量的內(nèi)存碎片,嚴(yán)重的時(shí)候會(huì)引起Full GC,導(dǎo)致RegionServer宕機(jī)。

下面對(duì)參數(shù)的調(diào)優(yōu)技巧都謹(jǐn)遵以上原則,尤其對(duì)于HBase這類延遲敏感性項(xiàng)目而言,在盡量避免嚴(yán)重影響用戶讀寫的情況下使得GC更加平穩(wěn)、暫停時(shí)間更短!

CMS GC優(yōu)化技巧
本節(jié)會(huì)針對(duì)HBase這一應(yīng)用場(chǎng)景對(duì)JVM的各種GC參數(shù)進(jìn)行分析,主要分三個(gè)階段進(jìn)行。第一階段會(huì)介紹適用于所有場(chǎng)景下的GC參數(shù)配置,這些參數(shù)不需要太多解釋讀者就可以輕松理解;第二階段和第三階段分別就兩組參數(shù)進(jìn)行調(diào)優(yōu)講解,這兩組參數(shù)一般會(huì)根據(jù)不同的應(yīng)用場(chǎng)景進(jìn)行設(shè)置才能使得GC效果最好,鑒于這兩組參數(shù)的復(fù)雜性,我們會(huì)通過理論+實(shí)驗(yàn)的方式一一進(jìn)行說明;

階段一:默認(rèn)推薦配置
在介紹具體的調(diào)優(yōu)技巧之前,先來看看CMS GC涉及到的所有相關(guān)參數(shù)及其對(duì)應(yīng)的意義,下面是最常見的參數(shù):

-Xmx -Xms -Xmn -Xss -XX:MaxPermSize= M -XX:+SurvivorRatio=S -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+MaxTenuringThreshold=N -XX:+UseCMSCompactAtFullCollection -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=C -XX:-DisableExplicitGC


通過上文對(duì)各個(gè)GC參數(shù)的說明,可以輕松得出第一階段推薦的參數(shù)設(shè)置如下,這樣的設(shè)置基本適用于所有的場(chǎng)景:

-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=75% -XX:-DisableExplicitGC

調(diào)優(yōu)預(yù)準(zhǔn)備
上文通過解釋各個(gè)GC參數(shù)意義給出了基本的推薦設(shè)置,同時(shí)也提到幾個(gè)對(duì)性能影響重大的參數(shù):Xmn、SurvivorRatio以及MaxTenuringThreshold,下面會(huì)通過理論推理+實(shí)驗(yàn)驗(yàn)證的方式對(duì)這幾個(gè)參數(shù)在HBase系統(tǒng)的設(shè)置進(jìn)行調(diào)優(yōu)。在深入介紹調(diào)優(yōu)技巧之前,需要額外針對(duì)三個(gè)相關(guān)部分預(yù)先做下講解,這樣可以更好地理解下文的實(shí)驗(yàn)數(shù)據(jù)分析。這三部分分別是:測(cè)試環(huán)境+測(cè)試基本條件,GC日志解釋,HBase場(chǎng)景內(nèi)存分析;
測(cè)試環(huán)境
首先就下文中實(shí)驗(yàn)測(cè)試的硬件拓?fù)?、軟件配置以及相關(guān)測(cè)試數(shù)據(jù)情況進(jìn)行說明:


需要強(qiáng)調(diào)的是HBase全部配置為BucketCache模式,而不是LruBlockCache。使用了大量堆外內(nèi)存作為讀緩存,在很大程度上優(yōu)化了GC,如下圖:

上圖是在兩種緩存策略下GC表現(xiàn)情況,可見BucketCache模式比LruBlockCache模式GC表現(xiàn)好很多,強(qiáng)烈建議線上配置BucketCache模式。可能很多童鞋都測(cè)試過這兩種模式下的GC、吞吐量、讀寫延遲等指標(biāo),看到測(cè)試結(jié)果都會(huì)很疑惑,BucketCache模式下的各項(xiàng)性能指標(biāo)都比LruBlockCache差了好多,筆者也疑惑過,后來才明白:測(cè)試肯定是在基本全內(nèi)存場(chǎng)景下進(jìn)行的,這種情況下確實(shí)會(huì)是如此。讀者可以想想為什么會(huì)如此,實(shí)在不明白可以參考之前一篇博文《BlockCache方案性能對(duì)比測(cè)試報(bào)告》。但是話又說回來,在大數(shù)據(jù)場(chǎng)景下又有多少業(yè)務(wù)會(huì)是全內(nèi)存操作呢?
GC日志分析
介紹完實(shí)驗(yàn)基本條件后,再對(duì)GC日志進(jìn)行簡(jiǎn)單的解釋,方便下文對(duì)日志進(jìn)行分析。需要注意只有在添加參數(shù)-XX:+PrintTenuringDistribution才能打印對(duì)應(yīng)日志,強(qiáng)烈建議線上集群開啟該參數(shù),日志片段如下:
2016-07-26T10:37:16.933+0800: 227753.150: [GC2016-07-26T10:37:16.933+0800: 227753.150: [ParNewDesired survivor size 268435456 bytes, new threshold 5 (max 15)- age 1: 57523184 bytes, 57523184 total- age 2: 80236520 bytes, 137759704 total- age 3: 73226496 bytes, 210986200 total- age 4: 50318392 bytes, 261304592 total- age 5: 63166384 bytes, 324470976 total- age 6: 240 bytes, 324471216 total: 1268903K->305311K(1572864K), 0.0840620 secs] 26598675K->25635082K(66584576K), 0.0844700 secs] [Times: user=1.82 sys=0.08, real=0.08 secs]
上述日志片段分三部分進(jìn)行解釋:
第一部分:基本信息區(qū),主要有兩點(diǎn)需要重點(diǎn)關(guān)注,其一是Desired survivor size 268435456 bytes,表示Survivor區(qū)大小為256M;其二是new threshold 5 (max 15),表示對(duì)象晉級(jí)老生代的最大閾值為15,但是因?yàn)镾urvivor區(qū)太小導(dǎo)致age大于5的對(duì)象會(huì)直接溢出晉級(jí)老生代(也有可能是閾值設(shè)置太大)。

第二部分:不同age對(duì)象分布區(qū),第一列表示該Young區(qū)共分布有age在1~6的對(duì)象;第二列表示所在age含有的對(duì)象集所占內(nèi)存大小,比如age為2的所有對(duì)象總大小為80236520 bytes;第三列表示小于對(duì)應(yīng)age的所有對(duì)象占用內(nèi)存的累加值,比如age2對(duì)應(yīng)第二列137759704 total表示age為1和age為2的所有對(duì)象總大??;

第三部分:內(nèi)存回收信息區(qū),第一列表示Young區(qū)的內(nèi)存回收情況,1268903K->305311K表示Young區(qū)回收前內(nèi)存為1268903K,回收后變?yōu)?05311K;第二列表示Jvm Heap的內(nèi)存回收情況,26598675K->25635082K(66584576K) 表示當(dāng)前Jvm總分配內(nèi)存為66584576K,回收前對(duì)象占用內(nèi)存為26598675K,回收后對(duì)象占用內(nèi)存為25635082K;第三列表示回收時(shí)間,其中real表示本次gc所消耗的STW時(shí)間,即用戶業(yè)務(wù)暫停時(shí)間。
HBase場(chǎng)景內(nèi)存分析
通常來講,每種應(yīng)用都會(huì)有自己的內(nèi)存對(duì)象特性,分類來說無非就兩種:一種是短壽對(duì)象(指存活對(duì)象較短的對(duì)象,比如臨時(shí)變量等)居多工程,比如大多數(shù)純HTTP請(qǐng)求處理工程,短壽對(duì)象可能占到所有對(duì)象的70%左右;另一種是長(zhǎng)壽對(duì)象(指存活對(duì)象較長(zhǎng)的對(duì)象,比如TTL設(shè)置較長(zhǎng)的緩存對(duì)象)居多工程,比如類似于HBase、Spark等這類大內(nèi)存工程。具體以HBase為例,來看看具體的內(nèi)存對(duì)象:

  1. RPC請(qǐng)求對(duì)象,比如Request對(duì)象和Response對(duì)象,一般這些對(duì)象會(huì)隨著短連接RPC的銷毀而消亡,這些對(duì)象可以認(rèn)為是短壽對(duì)象;
  2. Memstore對(duì)象,HBase中Memstore中對(duì)象一般會(huì)持續(xù)存活較長(zhǎng)時(shí)間,用戶寫入數(shù)據(jù)到Memstore中之后對(duì)象就一直存在,直至Memstore寫滿之后flush到HDFS。一般在寫入QPS較高的情況下寫滿memstore也通常需要一個(gè)小時(shí)左右,可見Memstore對(duì)象肯定是長(zhǎng)壽對(duì)象。另外,Memstore對(duì)象默認(rèn)比較大,2M大小。
  3. BlockCache對(duì)象,和Memstore對(duì)象一樣,BlockCache對(duì)象一般也會(huì)在內(nèi)存存活較長(zhǎng)時(shí)間,屬于長(zhǎng)壽對(duì)象。這種對(duì)象默認(rèn)64K大小。
    因此可以看出,HBase系統(tǒng)屬于長(zhǎng)壽對(duì)象居多的工程,因此GC的時(shí)候只需要將RPC這類短壽對(duì)象在Young區(qū)淘汰掉就可以達(dá)到最好的GC效果。

階段二:NewParSize調(diào)優(yōu)

理論分析
NewParSize表示young區(qū)大小,而young區(qū)大小直接決定minor gc的頻率。minor gc頻率一方面決定單次minor gc的時(shí)間長(zhǎng)短,gc越頻繁,gc時(shí)間就越短;一方面決定對(duì)象晉升到老年代的量,gc越頻繁,晉升到老年代的對(duì)象量就越大。解釋起來就是:

  1. 增大young區(qū)大小,minor gc頻率降低,單次gc時(shí)間會(huì)較長(zhǎng)(young區(qū)設(shè)置更大,一次gc就需要復(fù)制更多對(duì)象,耗時(shí)必然比較長(zhǎng)),業(yè)務(wù)讀寫操作延遲抖動(dòng)較大。反之,業(yè)務(wù)讀寫操作延遲抖動(dòng)較小,比較平穩(wěn)。
  2. 減小young區(qū)大小,minor gc頻率增快,但會(huì)加快晉升到老年代的對(duì)象總量(每gc一次,對(duì)象age就會(huì)加一,當(dāng)age超過閾值就會(huì)晉升到老年代,因此gc頻率越高,age就增加越快),潛在增加old gc風(fēng)險(xiǎn)。

因此設(shè)置NewParSize需要進(jìn)行一定的平衡,不能設(shè)置太大,也不能設(shè)置太小。

實(shí)驗(yàn)結(jié)果

實(shí)驗(yàn)條件:分為獨(dú)立對(duì)照試驗(yàn),三臺(tái)RegionServer分別設(shè)置Xmn為512m、2g、5g,Xmn越大,分配的Young區(qū)越大;SurvivorRatio和MaxTenuringThreshold取默認(rèn)值;
實(shí)驗(yàn)結(jié)果曲線圖:


結(jié)果分析

  1. 圖一是Xmn不同場(chǎng)景下總體的GC耗時(shí)曲線圖,其中橫坐標(biāo)表示GC次數(shù),縱坐標(biāo)表示GC耗時(shí)(STW),單位ms。需要特別說明的是,這3條曲線是在相同時(shí)間段統(tǒng)計(jì)的,也就是說在這段時(shí)間內(nèi)Xmn為512m的情況下GC次數(shù)最多,而相應(yīng)的Xmn為5的情況下GC次數(shù)最少。
  2. 圖一整體上來看綠線尖峰很多而且很高,表示CMS GC較頻繁,但綠線主體部分處于紅線與藍(lán)線之下,表示平均Minor GC耗時(shí)更短;藍(lán)線GC次數(shù)最少,尖峰也比較突出,另外Minor GC相比紅線和綠線耗時(shí)更長(zhǎng);紅線的Minor GC耗時(shí)介于藍(lán)線和綠線之間,尖峰比較平穩(wěn),表示CMS GC相對(duì)比較短暫;因此總體來看,紅線代表的Xmn為2的場(chǎng)景下CMS GC更加合理,平均Minor GC相對(duì)不高,而相比之下,另外兩種場(chǎng)景都有特別明顯的缺陷,Xmn=2是一個(gè)最優(yōu)的選擇;圖一只能直觀上看出這么多,更加精確結(jié)果需要接著看圖二和圖三。
  3. 圖二主要統(tǒng)計(jì)Minor GC的主要指標(biāo):總GC次數(shù)以及平均單次Minor GC耗時(shí)。兩者來看,更關(guān)注后者,因?yàn)楹笳邲Q定了業(yè)務(wù)讀寫的延遲以及穩(wěn)定度;由圖中可以看出,Xmn512m的平均單次Minor GC耗時(shí)最少,其次是Xmn2g,最差是Xmn5g,達(dá)到了130ms左右,意味著在其Minor GC過程中所有業(yè)務(wù)讀寫延遲至少為130ms;這個(gè)也很好理解,Young區(qū)越小,Minor GC頻率越高,單次Minor GC需要復(fù)制的對(duì)象數(shù)就越少,耗時(shí)越少;
  4. 圖三主要統(tǒng)計(jì)CMS GC(老年代GC)的主要指標(biāo):CMS GC次數(shù)以及平均單次老年代GC耗時(shí)(只算STW耗時(shí));由圖中可以看出,Xmn2g無論是GC次數(shù)還是GC耗時(shí)都更加優(yōu)秀,相比之下Xmn512m就是最差的選擇;解釋起來也很簡(jiǎn)單,因?yàn)閅oung區(qū)設(shè)置太小,Minor GC頻率高,對(duì)象age增加很快,很多對(duì)象就有可能因?yàn)閍ge超過閾值(默認(rèn)6)晉升到老年代,相對(duì)而言會(huì)更有可能引入大量短壽對(duì)象晉升老年代。而短壽對(duì)象相對(duì)而言會(huì)比較小,比如request、response等,大量小對(duì)象一旦進(jìn)入老年代,就會(huì)導(dǎo)致CMS GC的時(shí)候需要標(biāo)注更多對(duì)象,必然比較耗時(shí);

實(shí)驗(yàn)結(jié)論
可見,測(cè)試結(jié)果基本和理論分析一致,Xmn設(shè)置過小會(huì)導(dǎo)致CMS GC性能較差,而設(shè)置過大會(huì)導(dǎo)致Minor GC性能較差,因此建議在JVM Heap為64g以上的情況下設(shè)置Xmn在1~3g之間,在32g之下設(shè)置為512m~1g;具體最好經(jīng)過簡(jiǎn)單的線上調(diào)試;需要特別強(qiáng)調(diào)的是,筆者在很多場(chǎng)合都看到很多HBase線上集群會(huì)把Xmn設(shè)置的很大,比如有些集群Xmx為48g,Xmn為10g,查看日志發(fā)現(xiàn)GC性能極差:?jiǎn)未蜯inor GC基本都在300ms~500ms之間,CMS GC更是很多超過1s。在此強(qiáng)烈建議,將Xmn調(diào)大對(duì)GC(無論Minor GC還是CMS GC)沒有任何好處,不要設(shè)置太大。

階段三:增大Survivor區(qū)大?。p小SurvivorRatio) & 增大MaxTenuringThreshold


理論分析
上文講過,一次Minor GC會(huì)將存活對(duì)象從Eden區(qū)(以及survivor from區(qū))復(fù)制到Survivor區(qū)(to區(qū)),因此增大Survivor區(qū)可以容納更多的存活對(duì)象。這樣就會(huì)防止因?yàn)镾urvivor區(qū)太小導(dǎo)致很對(duì)存活對(duì)象還沒有達(dá)到MaxTenuringThreshold閾值就直接進(jìn)入老生代,潛在增大old gc的觸發(fā)頻率;但是Survivor區(qū)設(shè)置太大也會(huì)有一定的問題,Survivor設(shè)置較大會(huì)使得對(duì)象可以在Young區(qū)’待’的時(shí)間很長(zhǎng),但是對(duì)于一些長(zhǎng)壽對(duì)象較多的場(chǎng)景下(比如HBase),大量長(zhǎng)壽對(duì)象長(zhǎng)時(shí)間待在Young區(qū)做很多’無謂’的復(fù)制,一定程度上增加Minor GC開銷。

另外,增加MaxTenuringThreshold相當(dāng)于提高了進(jìn)入老年代的門檻,可以有效限制進(jìn)入老年代的對(duì)象數(shù)。和Survivor設(shè)置相似,調(diào)整MaxTenuringThreshold也需要做一個(gè)取舍,設(shè)置太小會(huì)增加CMS GC的觸發(fā)頻率以及耗時(shí),而設(shè)置太大則會(huì)在長(zhǎng)壽對(duì)象較多場(chǎng)景下增加Minor GC開銷。一般情況下,默認(rèn)MaxTenuringThreshold=15已經(jīng)相對(duì)比較大,不需要做任何調(diào)整。

實(shí)驗(yàn)結(jié)果
實(shí)驗(yàn)條件:分為獨(dú)立對(duì)照試驗(yàn),三臺(tái)RegionServer分別設(shè)置SurvivorRatio為2、8、15,SurvivorRatio越大,Survivor區(qū)大小越??;MaxTenuringThreshold取默認(rèn)值;其他:-Xmx64g,-Xmn2g;
實(shí)驗(yàn)結(jié)果曲線:

結(jié)果分析

  1. 圖一是SurvivorRatio在三種不同場(chǎng)景下對(duì)應(yīng)的GC性能曲線圖,大體可以看出藍(lán)線Minor GC次數(shù)最多,綠線尖峰太多,即CMS GC性能最差;具體細(xì)節(jié)再來看圖二和圖三。

  2. 圖二主要統(tǒng)計(jì)Minor GC主要指標(biāo):平均單次Minor GC耗時(shí)三者基本相當(dāng),SurvivorRatio:2場(chǎng)景下稍微較高,這是因?yàn)镾urvivorRatio=2對(duì)應(yīng)的Survivor區(qū)較大,可以使得對(duì)象在Young區(qū)’待’的時(shí)間很長(zhǎng),在HBase這種長(zhǎng)壽對(duì)象較多的情況下,可能會(huì)增加一些無謂的‘復(fù)制’開銷(下文會(huì)通過日志分析詳細(xì)解釋)。另外,SurvivorRatio=2場(chǎng)景下Minor GC頻率也比較高,可能的原因是因?yàn)樵诳俌oung大小確定的情況下,Survivor越大,Eden自然越小,Minor GC頻率就會(huì)增大??梢姡琒urvivorRatio=2場(chǎng)景下Minor GC性能相對(duì)稍微較差。

  3. 圖三主要統(tǒng)計(jì)CMS GC主要指標(biāo):三者CMS GC次數(shù)基本相當(dāng),SurvivorRatio=2場(chǎng)景下單次CMS GC耗時(shí)最少,相比SurvivorRatio=8的場(chǎng)景耗時(shí)減少30%左右,性能最好;而相比之下SurvivorRatio=15場(chǎng)景下耗時(shí)最長(zhǎng),性能相當(dāng)差;這是因?yàn)镾urvivorRatio=2場(chǎng)景下存活對(duì)象可以長(zhǎng)時(shí)間待在Young區(qū),可以得到充分的淘汰,晉升到老生代的短壽小對(duì)象會(huì)比較少,因而CMS GC性能較好;相比SurvivorRatio=15會(huì)因?yàn)镾urvivor區(qū)設(shè)置太小,很多短壽小對(duì)象因?yàn)榈貌坏匠浞值奶蕴蜁?huì)‘溢出’到老生代,導(dǎo)致CMS性能很差。
    實(shí)驗(yàn)結(jié)論

可見,測(cè)試結(jié)果基本和理論分析也基本一致,對(duì)于Minor GC來說,SurvivorRatio設(shè)置對(duì)其影響不是很大。而對(duì)于CMS GC來說,將SurvivorRatio設(shè)置過大簡(jiǎn)直就是災(zāi)難,性能極其差。而和默認(rèn)值SurvivorRatio=8相比,將SurvivorRatio調(diào)大有利于短壽小對(duì)象更充分地淘汰,因此建議將SurvivorRatio=2
CMS調(diào)優(yōu)結(jié)論

  1. 緩存模式采用BucketCache策略O(shè)ffheap模式
  2. 對(duì)于大內(nèi)存(大于64G),采用如下配置:

-Xmx64g -Xms64g -Xmn2g -Xss256k -XX:MaxPermSize=256m -XX:+SurvivorRatio=2 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+MaxTenuringThreshold=15 -XX:+UseCMSCompactAtFullCollection -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=75 -XX:-DisableExplicitGC

其中Xmn可以隨著Java分配堆內(nèi)存增大而適度增大,但是不能大于4g,取值范圍在1~3g范圍;SurvivorRatio一般建議選擇為2;MaxTenuringThreshold設(shè)置為15;
3 對(duì)于小內(nèi)存(小于64G),只需要將上述配置中Xmn改為512m-1g即可
總結(jié)
本文首先比較系統(tǒng)的介紹了CMS GC的相關(guān)知識(shí),之后分三個(gè)階段層層推進(jìn)對(duì)HBase集群中相關(guān)重要參數(shù)的調(diào)優(yōu)進(jìn)行了詳細(xì)說明,尤其后面兩階段通過理論推理以及實(shí)驗(yàn)驗(yàn)證的方式對(duì)兩組核心參數(shù)進(jìn)行了針對(duì)性調(diào)整,最終得出一個(gè)較為完整的CMS GC參數(shù)配置。讀者可以參考該參數(shù)配置對(duì)集群進(jìn)行調(diào)整,再通過日志查看調(diào)整效果~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容