Dr. Elephant是linkedin開源的mapreduce和spark作業(yè)的性能監(jiān)控及調優(yōu)工具, 它開發(fā)了可插拔式的啟發(fā)式規(guī)則來診斷mapreduce和spark作業(yè)運行中存在的問題, 并給出調優(yōu)的解決方案. 它也可以通過與其他調度器 (如Azakaban) 結合來分析作業(yè)流的歷史性能表現.
用戶在上線新的hadoop和spark作業(yè)之前, 使用Dr. Elephant進行診斷及調優(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以上。(從官網下載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修改成對應的版本。(如果不修改,是否會遇到問題,我沒有嘗試)。
運行源碼中編譯命令./compile.sh [./app-conf/compile.conf],請將中括號中路徑修改為相應文件的路徑。編譯過程會下載很多需要用到的jar包和文件,請耐心等待。我前兩次編譯都因為部分文件下載失敗而導致編譯失敗。如果有問題,繼續(xù)嘗試編譯,已經下載過的文件會自動跳過,就不用再次下載了。
編譯完成后,會有SUCCESS的提示。這時可以看到在源碼文件夾中,多了一個目錄dist,進入這個目錄可以看到,里面有一個zip包dr-elephant.zip,解壓縮這個zip包,生成一個文件夾dr-elephant。記住,這個文件夾需要被分發(fā)到需要部署Dr.Elephant的機器上,下面會用到它。
源碼中的app-conf文件夾也會在后面分發(fā)到需要部署Dr.Elephant的機器上
編譯生成可執(zhí)行文件,在本地即可完成。是不需要在本地安裝Hadoop平臺的。
集群環(huán)境要求
確保Yarn資源管理器的正常運行以及歷史任務服務的正常運行,對于使用Yarn管理Hadoop平臺的集群環(huán)境來說,一般這個條件都能滿足
-
部署啟動一個MySQL服務,MySQL的版本必須是5.5+。對MySQL沒有特殊配置,分配好對這個DB有讀寫權限的賬號即可。在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數據庫 mysql> create database drelephant; -
將準備工作中提到的需要用到的app-conf文件夾也拷貝到需要部署的機器上某個目錄,假設這個目錄是/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配置參數,改為我們要使用的MySQL的連接參數。
在這個機器上配置環(huán)境變量ELEPHANT_CONF_DIR,讓這個環(huán)境變量指向從源碼中拷貝過來的app-conf文件夾。其實這步不是必須的,后面可以看到,如果不設置這個變量ELEPHANT_CONF_DIR,在啟動Dr.Elephant時,在命令行參數中第一個參數添加這個本地目錄也是可以的。
部署啟動
在Hadoop集群中選擇一臺機器作為Dr.Elephant的部署機器,在這個機器上選擇一個有權限訪問HDFS的賬號,作為Dr.Elephant的啟動賬號
將前面步驟中提到的編譯后生成的dist/dr-elephant*文件拷貝到這個機器上,如/opt/dr-elephant/
修改app-conf/elephant.conf中第一行,端口號默認是8080,但是會與ambari沖突,所以改成port=8081
進入bin目錄,執(zhí)行./start.sh [/a/app-conf]啟動。如果沒有執(zhí)行“集群環(huán)境要求”中的第4步,這里需要手動輸入/a/app-conf這個目錄作為命令行參數
啟動后,驗證是否執(zhí)行成功。如果命令行輸出提示“Dr.Elephant started”并不能證明它已經成功啟動??梢园凑找韵虏襟E逐步驗證:(1)ps aux | grep elephant,查看是否有這個進程,如果有,那么說明啟動成功;(2)查看默認的log,dr.log,在安裝包的首層目錄下,如果日志中沒有明顯的異常拋出,說明啟動正常;(3)登錄用到的MySQL,進入使用的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運行的詳細日志在安裝包的上層目錄,如/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è)對應.jhist和.xml兩個文件
# *.xml文件里面記錄的是相應作業(yè)運行時候的完整參數配置 hdfs dfs -cat /mr-history/done/2016/11/01/000000/job_1477464172237_0052_conf.xml # *.jhist文件里存放的是具體Hadoop作業(yè)運行的詳細信息 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/下看到對應的日志文件,如application_1478153889331_0019,dr-elephant就是從這個日志獲取數據的.
cd /usr/hdp/2.4.0.0-169/spark/sbin/ ./start-history-server.sh 如果還有問題,先把spark history server的進程kill掉,再重新起.
要注意dr-elephant是否有/spark-history/目錄的讀寫權限
-
提交spark作業(yè)時,要使用yarn-client模式(--master yarn-client),產生的日志文件名為application_1478153889331_0021,如果用yarn-cluster模式,產生的日志文件名為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默認是注釋掉的,注意需要去掉注釋. event_log_dir定義了spark作業(yè)歷史日志的路徑,要與spark history server的配置一致,我的是/spark-history,注意這里指是hdfs上的文件.spark_log_ext定義了spark作業(yè)日志文件的后綴,如果把spark.eventLog.compress設為true,則后綴為.snappy,表示壓縮文件.相反如果把spark.eventLog.compress設為false,則沒有后綴,spark_log_ext應為空.
<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 默認值:false 是否壓縮記錄Spark事件,前提spark.eventLog.enabled為true,默認使用的是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è)application id,然后根據數據庫里的具體信息畫出圖表.
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)