天天看點

RegionServer與OOM不得不說的一些事兒

RegionServer程序運作中,可能會突然挂掉,RegionServer日志中看不到任何錯誤提示,也不會生成hs_err_pid.log之類的提示。相信許多同學遭遇過這種場景,此時,你應該想到罪魁禍首是OOM(OutOfMemory)。

對于OOM問題,我認為首要問題是:搞清楚RegionServer是被主動還是被動kill的?

1. 先說說何為主動和被動?

主動是指:如果RegionServer發現自己OOM,則自身主動請求去被kill;被動是指:RegionServer沒有OOM,但是作業系統記憶體不夠用了,于是OS會選擇kill一些程序,那麼記憶體大戶RegionServer就可能被動的kill了。

2. 再說說為何要區分主動和被動?

如果是主動,那就說明是RegionServer方的原因。但是,你應該明白絕大部分是因為使用不當hbase引起的,而不是RegionServer的bug之類的問題。比如:應用中put一個超大的cell可能引發OOM(我在測試中就這麼搞過......)。是以,你接下來的任務就是如何優化操作hbase的應用了。

如果是被動,說明機器中存在其它記憶體大戶。此時,你需要考慮記憶體劃分是否合理。如何合理,那就是某些應用的記憶體使用存在問題,這個更需要你來好好尋找了。比如在我遭遇的OOM場景下,就是這種情況,詳細過程可以參考另一篇博文:clouera-scm-agent程序記憶體高漲的一個案例。

3. 最後說說怎麼區分主動和被動?

3.1. 主動kill

其實RegionServer程序啟動時,已經告訴JVM如何處理OOM了。

./jps -v|grep "Region"
HRegionServer -Dproc_regionserver -XX:OnOutOfMemoryError=kill -9 %p -Xmx1000m -Djava.net.preferIPv4Stack=true -Xms16106127360 -Xmx16106127360 -XX:+UseG1GC -XX:MaxGCPauseMillis=6000 -XX:OnOutOfMemoryError=/usr/lib64/cmf/service/common/killparent.sh -Dhbase.log.dir=/data14/log/hbase -Dhbase.log.file=hbase-cmf-hbase-REGIONSERVER-cb8.log.out -Dhbase.home.dir=/opt/cloudera/parcels/CDH-5.2.0-1.cdh5.2.0.p0.36/lib/hbase -Dhbase.id.str= -Dhbase.root.logger=INFO,RFA -Djava.library.path=/opt/cloudera/parcels/CDH-5.2.0-1.cdh5.2.0.p0.36/lib/hadoop/lib/native -Dhbase.security.logger=INFO,RFAS
           

通過上述的jps指令,可以看到RegionServe告訴JVM:我要使用的最大記憶體為16106127360B,如果我出現了OOM,你就去執行/usr/lib64/cmf/service/common/killparent.sh吧。

killparent.sh腳本的主要代碼就一行:kill -9 $PPID。$PPID表示父程序号,也就是JVM的程序号。

是以JVM監測到RegionServe的OOM後,将會fork一個子程序去執行這個腳本,于是,JVM就被kill了,當然RegionServer也就被kill了。

此時,你檢視RegionServer的out檔案,将會看到類似如下的提示:

# java.lang.OutOfMemoryError: Java heap space
# -XX:OnOutOfMemoryError="kill -9 %p
/usr/lib64/cmf/service/common/killparent.sh"
#   Executing /bin/sh -c "kill -9 9192
/usr/lib64/cmf/service/common/killparent.sh"...
           

此處說明一個小問題:上述snippet不是出現在RegionServer的日志檔案裡,而是在out檔案裡。不同的hbase封裝版本,可能對這兩類檔案有不同的定義方式。比如CDH裡面,就是/var/run/cloudera-scm-agent/process/*-hbase-REGIONSERVER/logs/stdout.log,其中的*為一個數字。

3.2. 被動kill

在linux的message日志中,可以看到類似如下的提示:

kernel: Out of memory: Kill process 38551 (java) score 501 or sacrifice child
kernel: Killed process 38551, UID 483, (java) total-vm:17538500kB, anon-rss:16420056kB, file-rss:28kB
kernel: java invoked oom-killer: gfp_mask=0x201da, order=0, oom_adj=0, oom_score_adj=0
           

上述日志表明:RegionServer程序(38551)被kill了。注意:total-vm:17538500kB, anon-rss:16420056kB應該是它占用的記憶體,而不是已經使用的記憶體。如果沒有搞清楚這個差別,你可能會以為RegionServer已經超過max-heap-size了,那麼kill就應該變成主動了。

此處說明一個小問題:如何知道38551就是之前運作的RegionServer程序呢?RegionServer程序啟動後,在其日志中可以看到如下類似的日志:

INFO org.apache.hadoop.hbase.util.ServerCommandLine: env:HBASE_ZNODE_FILE=/var/run/cloudera-scm-agent/process/5644-hbase-REGIONSERVER/znode38551
           

其中的38551就是程序号。

另附在本文探索過程中發現的一個小問題:如果/proc/sys/vm/overcommit_memory設為0,則為-Xmx參數指定一個較大值時,可能會出現錯誤:

Error occurred during initialization of VM
Failed to allocate initial heap.
           

此時,修改/proc/sys/vm/overcommit_memory為1即可。原因就是因為在overcommit(過度配置設定)時,0是一種相當保守的政策,而1是一種相當開放的政策......這裡描述比較朦胧,較長的描述,大家可以百度一下。

繼續閱讀