Dr. Elephant是linkedin開源的mapreduce和spark作業(yè)的性能監(jiān)控及調(diào)優(yōu)工具, 它開發(fā)了可插拔式的啟發(fā)式規(guī)則來診斷mapreduce和spark作業(yè)運行中存在的問題, 并給出調(diào)優(yōu)的解決方案. 它也可以通過與其他調(diào)度器 (如Azakaban) 結(jié)合來分析作業(yè)流的歷史性能表現(xiàn).
用戶在上線新的hadoop和spark作業(yè)之前, 使用Dr. Elephant進(jìn)行診斷及調(diào)優(yōu)能夠優(yōu)化作業(yè)運行性能,提高集群資源使用效率.
本文主要介紹如何編譯、部署Dr. Elephant, 以及使用中的常見問題.
下載并編譯代碼,生成部署需要的包
- 從github上下載Dr. Elephant源碼
git clone https://github.com/linkedin/dr-elephant.git
-
本地安裝play框架,在環(huán)境變量PATH添加play命令路徑延蟹。play對Java版本要求,版本必須是Java 8以上叶堆。(從官網(wǎng)下載traditional play,不是activator)
# play framework的環(huán)境變量配置 export JAVA_HOME=/usr/jdk64/jdk1.8.0_60/ export PLAY_HOME=/opt/play-2.2.6 PATH=$PATH:$PLAY_HOME:$JAVA_HOME/bin # 能運行play命令即為配置成功
修改源碼中編譯時用到的配置文件阱飘,app-conf/compile.conf,將hadoop_version和spark_version修改成對應(yīng)的版本虱颗。(如果不修改沥匈,是否會遇到問題,我沒有嘗試)忘渔。
運行源碼中編譯命令./compile.sh [./app-conf/compile.conf]高帖,請將中括號中路徑修改為相應(yīng)文件的路徑。編譯過程會下載很多需要用到的jar包和文件畦粮,請耐心等待散址。我前兩次編譯都因為部分文件下載失敗而導(dǎo)致編譯失敗乖阵。如果有問題,繼續(xù)嘗試編譯预麸,已經(jīng)下載過的文件會自動跳過瞪浸,就不用再次下載了。
編譯完成后吏祸,會有SUCCESS的提示对蒲。這時可以看到在源碼文件夾中,多了一個目錄dist犁罩,進(jìn)入這個目錄可以看到齐蔽,里面有一個zip包dr-elephant.zip,解壓縮這個zip包床估,生成一個文件夾dr-elephant含滴。記住,這個文件夾需要被分發(fā)到需要部署Dr.Elephant的機器上丐巫,下面會用到它谈况。
源碼中的app-conf文件夾也會在后面分發(fā)到需要部署Dr.Elephant的機器上
編譯生成可執(zhí)行文件,在本地即可完成递胧。是不需要在本地安裝Hadoop平臺的碑韵。
集群環(huán)境要求
確保Yarn資源管理器的正常運行以及歷史任務(wù)服務(wù)的正常運行,對于使用Yarn管理Hadoop平臺的集群環(huán)境來說缎脾,一般這個條件都能滿足
-
部署啟動一個MySQL服務(wù)祝闻,MySQL的版本必須是5.5+。對MySQL沒有特殊配置遗菠,分配好對這個DB有讀寫權(quán)限的賬號即可联喘。在MySQL中創(chuàng)建一個db名稱drelephant(這個名稱可以是任意的,后面可以看到辙纬,和elephant.conf配置文件中db名稱一致即可)
# 若操作系統(tǒng)是redhat7,沒有mysql源,可以用mariadb代替 yum install mariadb* # 安裝mariadb的全套 systemctl start mariadb # 啟動mariadb # 安裝成功后mariadb其他命令與mysql一樣 # 創(chuàng)建drelephant數(shù)據(jù)庫 mysql> create database drelephant;
-
將準(zhǔn)備工作中提到的需要用到的app-conf文件夾也拷貝到需要部署的機器上某個目錄豁遭,假設(shè)這個目錄是/a/app-conf/。修改app-conf文件夾中的文件elephant.conf文件贺拣,添加jvm_props,注意與文件里本來有的一行jvm_args不一樣.
jvm_props=" -Devolutionplugin=enabled -DapplyEvolutions.default=true
并修改這個文件中的db_url蓖谢、db_user、db_name和db_password配置參數(shù)譬涡,改為我們要使用的MySQL的連接參數(shù)闪幽。
在這個機器上配置環(huán)境變量ELEPHANT_CONF_DIR,讓這個環(huán)境變量指向從源碼中拷貝過來的app-conf文件夾涡匀。其實這步不是必須的沟使,后面可以看到,如果不設(shè)置這個變量ELEPHANT_CONF_DIR渊跋,在啟動Dr.Elephant時腊嗡,在命令行參數(shù)中第一個參數(shù)添加這個本地目錄也是可以的着倾。
部署啟動
在Hadoop集群中選擇一臺機器作為Dr.Elephant的部署機器,在這個機器上選擇一個有權(quán)限訪問HDFS的賬號燕少,作為Dr.Elephant的啟動賬號
將前面步驟中提到的編譯后生成的dist/dr-elephant*文件拷貝到這個機器上,如/opt/dr-elephant/
修改app-conf/elephant.conf中第一行,端口號默認(rèn)是8080,但是會與ambari沖突,所以改成port=8081
進(jìn)入bin目錄卡者,執(zhí)行./start.sh [/a/app-conf]啟動。如果沒有執(zhí)行“集群環(huán)境要求”中的第4步客们,這里需要手動輸入/a/app-conf這個目錄作為命令行參數(shù)
啟動后崇决,驗證是否執(zhí)行成功。如果命令行輸出提示“Dr.Elephant started”并不能證明它已經(jīng)成功啟動底挫『闵担可以按照以下步驟逐步驗證:(1)ps aux | grep elephant,查看是否有這個進(jìn)程建邓,如果有盈厘,那么說明啟動成功;(2)查看默認(rèn)的log官边,dr.log沸手,在安裝包的首層目錄下,如果日志中沒有明顯的異常拋出注簿,說明啟動正常契吉;(3)登錄用到的MySQL,進(jìn)入使用的db诡渴,查看是否有表play_evolutions捐晶、yarn_app_heuristic_result、yarn_app_heuristic_result_details以及yarn_app_result妄辩,如果有這些表也說明啟動正常惑灵;(4)瀏覽器請求 http://host:8081 ,(這個host是部署Dr.Elephant的機器的host),看看是否能看到Dr.Elephant UI的首頁恩袱,如果可以泣棋,說明啟動成功
Dr elephant運行的詳細(xì)日志在安裝包的上層目錄,如/opt/logs/elephant/dr_elephant.log,比較難找.
使用中常見問題
作業(yè)信息獲取
-
mapreduce作業(yè)有兩種可選的fetcher,在FetcherConf.xml中配置.
MapReduceFetcherHadoop2是從yarn history server獲取作業(yè)信息,如
http://localhost:19888/ws/v1/history/mapreduce/jobs/job_1477464172237_0069MapReduceFSFetcherHadoop2是通過讀日志文件來獲取作業(yè)信息,每個作業(yè)對應(yīng).jhist和.xml兩個文件
# *.xml文件里面記錄的是相應(yīng)作業(yè)運行時候的完整參數(shù)配置 hdfs dfs -cat /mr-history/done/2016/11/01/000000/job_1477464172237_0052_conf.xml # *.jhist文件里存放的是具體Hadoop作業(yè)運行的詳細(xì)信息 hdfs dfs -cat /mr-history/done/2016/11/01/000000/job_1477464172237_0052-1477984365827-ocdp-QuasiMonteCarlo-1477984395977-4-1-SUCCEEDED-default-1477984370174.jhist
spark作業(yè)只有一種fetcher,即SparkFSFetcher,通過讀日志文件來獲取信息
監(jiān)控和優(yōu)化spark作業(yè)
-
首先要保證spark history server在正常運行,如果它正常運行的話,每運行一個spark作業(yè),可以在hdfs:///spark-history/下看到對應(yīng)的日志文件,如application_1478153889331_0019,dr-elephant就是從這個日志獲取數(shù)據(jù)的.
cd /usr/hdp/2.4.0.0-169/spark/sbin/ ./start-history-server.sh
如果還有問題,先把spark history server的進(jìn)程kill掉,再重新起.
要注意dr-elephant是否有/spark-history/目錄的讀寫權(quán)限
-
提交spark作業(yè)時,要使用yarn-client模式(--master yarn-client),產(chǎn)生的日志文件名為application_1478153889331_0021,如果用yarn-cluster模式,產(chǎn)生的日志文件名為application_1478153889331_0012_appattempt_1478153889331_0012_000001,而dr-elephant能識別的文件名為前者.
./bin/spark-submit \ --class org.apache.spark.examples.SparkPi \ --master yarn-client \ --num-executors 3 \ --driver-memory 512m \ --executor-memory 2g \ --executor-cores 1 \ /usr/hdp/2.4.0.0-169/spark/lib/spark-examples-1.6.0.2.4.0.0-169-hadoop2.7.1.2.4.0.0-169.jar \ 10
-
FetcherConf.xml里spark的params默認(rèn)是注釋掉的,注意需要去掉注釋. event_log_dir定義了spark作業(yè)歷史日志的路徑,要與spark history server的配置一致,我的是/spark-history,注意這里指是hdfs上的文件.spark_log_ext定義了spark作業(yè)日志文件的后綴,如果把spark.eventLog.compress設(shè)為true,則后綴為.snappy,表示壓縮文件.相反如果把spark.eventLog.compress設(shè)為false,則沒有后綴,spark_log_ext應(yīng)為空.
<fetcher> <applicationtype>spark</applicationtype> <classname>org.apache.spark.deploy.history.SparkFSFetcher</classname> <params> <event_log_size_limit_in_mb>100</event_log_size_limit_in_mb> <event_log_dir>/spark-history</event_log_dir> <spark_log_ext>.snappy</spark_log_ext> #the values specified in namenode_addresses will be used for obtaining spark logs. The cluster configuration will be ignored. <!-- <namenode_addresses>address1,address2</namenode_addresses> --> </params> </fetcher>
spark配置
spark.eventLog.compress 默認(rèn)值:false 是否壓縮記錄Spark事件胶哲,前提spark.eventLog.enabled為true畔塔,默認(rèn)使用的是snappy
以spark.history開頭的需要配置在spark-env.sh中的SPARK_HISTORY_OPTS,以spark.eventLog開頭的配置在spark-defaults.conf.
如果ambari中搜不到這項配置,可以在自定義spark-defaults中手工增加屬性.
Job history和 Flow history功能
搜索框要輸入的job id/url可以是azkaban里定義的job name(如pi),dr.elephant會從mysql的drelephant庫里的yarn_app_result表中搜索字段job_def_id='pi'對應(yīng)的作業(yè)application id,然后根據(jù)數(shù)據(jù)庫里的具體信息畫出圖表.
MariaDB [drelephant]> show tables;
+-----------------------------------+
| Tables_in_drelephant |
+-----------------------------------+
| play_evolutions |
| yarn_app_heuristic_result |
| yarn_app_heuristic_result_details |
| yarn_app_result |
+-----------------------------------+
4 rows in set (0.00 sec)
MariaDB [drelephant]> select id,name,username,job_type,scheduler,job_name,job_exec_id,job_def_id,flow_def_id,flow_exec_id from yarn_app_result where job_def_id !="";
+--------------------------------+-----------------+----------+------------+-----------+----------+-------------+------------+-------------+--------------+
| id | name | username | job_type | scheduler | job_name | job_exec_id | job_def_id | flow_def_id | flow_exec_id |
+--------------------------------+-----------------+----------+------------+-----------+----------+-------------+------------+-------------+--------------+
| application_1477464172237_0067 | QuasiMonteCarlo | test | HadoopJava | azkaban | pi | 4 | pi | example | 8 |
| application_1477464172237_0071 | QuasiMonteCarlo | test | HadoopJava | azkaban | pi | 3 | pi | example | 9 |
| application_1478153889331_0007 | QuasiMonteCarlo | test | HadoopJava | azkaban | pi | 1 | pi | example | 10 |
| application_1478153889331_0008 | QuasiMonteCarlo | test | HadoopJava | azkaban | pi | 2 | pi | example | 11 |
+--------------------------------+-----------------+----------+------------+-----------+----------+-------------+------------+-------------+--------------+
4 rows in set (0.00 sec)