Hive調優 | HiveServer2 效能優化與GC優化

語言: CN / TW / HK

一、問題描述

開發者利用jdbc連線hiveserver2(或者利用jdbc連線 spark HiveThriftServer2,由於兩者都是提供jdb c連線到hive,因此,後面都統一稱為利用jdbc連線hiveserver2),執行簡單查詢、複雜分析、超複雜分析等不同的sql任務,session併發量還很高(五六百甚至上千的並 發),本質上要求大資料平臺同時 具備oltp的高併發與olap的高分析能力。對於hiveserver2這一類基於hadoop平臺的jdbc server而言,非常不適合這種高併發的應用。

最近發現hiveserver2(本質上是提供jdbc連線的driver程序)經常發生嚴重卡死故障。而且卡死分成兩種現象:

故障現象1:

通過jdbc無法正常連線到hiveserver2;

故障現象2:

能夠很順利通過jdbc連線到hiveserver2,但是無法執行任何sql任務。

每次jdbc連線hiveserver2出現卡死,就必須重啟hiveserver2才能解決。無休無止的重啟,在生產環境是非常致命的糟糕體驗。

二、問題分析

找到hiveserver2卡死的真正原因,才能夠徹底解決該問題。經過與公司內熟悉hiveserver2和spark HiveThriftServer2的同事溝通,之前在公司內部環境也經常遇到卡死的情況,定位原因主要是兩類:

(1)主要是由於jdbc連線hiveserver2的併發量非常高,而且某些sql任務會嚴重消耗hiveserver2的記憶體,導致hiveserver2壓力巨大,比如:reducetask獲取mapOutputStatus的時候。這種情況是由於hiveserver2自身的複雜壓力大,記憶體損耗嚴重,嚴重GC進而導致hiveserver2故障。這種故障對應於上面介紹的“故障現象1”,通過jdbc無法正常連線到hiveserver2。為了解決該故障,可以通過優化記憶體GC可以緩解hiveserver2的GC卡死問題。

(2)由於執行某個大型sql任務,把資源池資源消耗殆盡,且長時間不釋放,導致所有通過hiveserver2提交的sql任務都無法執行。這種故障對應於上面介紹的“故障現象2”,能夠很順利通過jdbc連線到hiveserver2,但是無法執行任何sql任務。為了解決此類故障,只能讓開發者減少複雜任務執行,或者將不同型別的任務,提交到不同的資源佇列執行。

三、復現問題

3.1 復現jdbc無法連線到hiveserver2故障

根據同事的指導,我們也首先從記憶體GC角度入手。通過jstat 命令,每隔10秒獲取一次hiveserver2程序的GC情況,最終復現該問題。以下是hiveserver2發生卡死,jdbc無法連線到hiveserver2的時候,統計GC的結果:

可以看到,當hiveserver2發生嚴重卡死時,也就是hiveserver2 程序發生嚴重GC的時候。因此,可以通過優化hiveserver2的記憶體GC來優化hiveserver2,使之支援更高的併發、能夠執行更復雜的sql任務。

3.2 復現通過hiveserver2提交sql任務無法執行故障

我們通過jdbc連線到hiveserver2,提交三個表之間的join複雜聯合查詢。三個表的資料量分別在 10億、5億和1億,三個表做join查詢。執行結果如下如所示:

可以看到,三個表之間做複雜的關聯查詢任務,sql執行最終會卡在reduce階段,一直把資源佔據。而後通過hiveserver2提交的其它任務sql任務,都會因為無法獲取到資源被卡住無法執行。

這種情況,只能讓開發者將大型任務提交到單獨的資源佇列,防止某個大型任務一直佔據資源,使得其它任務無法執行。

四、問題解決

4.1 擴大hiveserver2啟動的記憶體引數

既然出現了嚴重GC,首先需要做的就是將hiveserver2轉移,重新部署到一臺CPU和記憶體資源非常豐富的伺服器。我們檢測到原來部署hiveserver2的伺服器上面還部署了HDFS nemanode、hbase master、zookeeper、yarn resourcemanager,資源嚴重不足。因此,將hiveserver2遷移到資源非常空閒的另外一臺伺服器。

4.2 採用優化GC機制和引數

之前hiveserver2程序的啟動引數沒有新增GC引數,也就是說採用系統預設的GC機制。這一次,我們結合公司內部的使用情況,採用cms GC機制。

同時為了更方便觀察GC情況,我們在啟動命令裡面新增jconsle。具體的引數如下所示:

-Xms49152m 
-Xmx49152m
-Djava.rmi.server.hostname=xxx.xxx.xxx.xxx
-Dcom.sun.management.jmxremote.port=8999
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-XX:+UseParNewGC
-XX:ParallelGCThreads=30
-XX:MaxTenuringThreshold=10
-XX:TargetSurvivorRatio=70
-XX:+UseConcMarkSweepGC
-XX:+CMSConcurrentMTEnabled
-XX:ParallelCMSThreads=30
-XX:+UseCMSInitiatingOccupancyOnly
-XX:+CMSClassUnloadingEnabled
-XX:+DisableExplicitGC
-XX:CMSInitiatingOccupancyFraction=70
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=1
-verbose:gc
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:GCLogFileSize=512M
-Xloggc:/data/log/tbds/spark/gc-sparkthrift.log-${timenow}

其中,有幾個引數需要根據伺服器的自身資源量來決定。

(1)-Xms49152m -Xmx49152m 這兩個引數需要考慮伺服器實際的可用記憶體資源來設定;

(2)-XX:ParallelGCThreads=30 和 -XX:ParallelCMSThreads=30 這兩個引數需要考慮伺服器實際的CPU核數來決定。切記不要超過CPU核數。

經過上面兩種優化方法之後,hiveserver2目前非常穩定。當然基於hadoop平臺的hiveserver2本身支援的jdbc併發連線數有限,不可能做到關係型資料庫那樣的oltp高併發效能。當hiveserver2 的 jdbc session連線數達到極端情況(超過上千的併發),還是可能發生嚴重GC。此時,需要重啟hiveserver2,並且控制併發量。