Flink on YARN 常見問題與排查思路
- 2019 年 12 月 5 日
- 筆記
楊弢(搏遠),阿里巴巴計算平台事業部技術專家,Apache Hadoop Committer,目前專註於 YARN、Flink、YuniKorn 等開源項目的資源調度方向。
Flink 支援 Standalone 獨立部署和 YARN、Kubernetes、Mesos 等集群部署模式,其中 YARN 集群部署模式在中國的應用越來越廣泛。Flink 社區將推出 Flink on YARN 應用解讀系列文章,分為上、下兩篇。上篇分享了基於 FLIP-6 重構後的資源調度模型介紹 Flink on YARN 應用啟動全流程,本文將根據社區大群回饋,解答客戶端和 Flink Cluster 的常見問題,分享相關問題的排查思路。
客戶端常見問題與排查思路
▼ 應用提交控制台異常資訊:Could not build the program from JAR file.
這個問題的迷惑性較大,很多時候並非指定運行的 JAR 文件問題,而是提交過程中發生了異常,需要根據日誌資訊進一步排查。最常見原因是未將依賴的 Hadoop JAR 文件加到 CLASSPATH,找不到依賴類(例如:ClassNotFoundException: org.apache.hadoop.yarn.exceptions.YarnException)導致載入客戶端入口類(FlinkYarnSessionCli)失敗。
▼ Flink on YARN 應用提交時如何關聯到指定 YARN 集群?
Flink on YARN 客戶端通常需配置 HADOOP_CONF_DIR 和 HADOOP_CLASSPATH 兩個環境變數來讓客戶端能載入到 Hadoop 配置和依賴 JAR 文件。示例(已有環境變數 HADOOP_HOME 指定 Hadoop 部署目錄):
export HADOOP_CONF_DIR=${HADOOP_HOME}/etc/hadoop export HADOOP_CLASSPATH=`${HADOOP_HOME}/bin/hadoop classpath`
▼ 客戶端日誌在哪裡,如何配置?
客戶端日誌通常在 Flink 部署目錄的 log 文件夾下:${FLINK_HOME}/log/flink-${USER}-client-<HOSTNAME>.log,使用 log4j 配置:${FLINK_HOME}/conf/log4j-cli.properties。
有的客戶端環境比較複雜,難以定位日誌位置和配置時,可以通過以下環境變數配置打開 log4j 的 DEBUG 日誌,跟蹤 log4j 的初始化和詳細載入流程:export JVM_ARGS="-Dlog4j.debug=true"
▼ 客戶端疑難問題排查思路
當客戶端日誌無法正常定位時,可以修改 log4j 配置文件將日誌級別由 INFO 改為 DEBUG 後重新運行,看是否有 DEBUG 日誌可以幫助排查問題。對於一些沒有日誌或日誌資訊不完整的問題,可能需要開展程式碼級調試,修改源碼重新打包替換的方式太過繁瑣,推薦使用 Java 位元組碼注入工具 Byteman(詳細語法說明請參考:Byteman Document),使用示例:
(1) 編寫調試腳本,例如列印 Flink 實際使用的 Client 類,以下腳本表示在 CliFrontend#getActiveCustomCommandLine 函數退出時列印其返回值;
(2) 設置環境變數,使用 byteman javaagent:
export BYTEMAN_HOME=/path/to/byte-home export TRACE_SCRIPT=/path/to/script export JVM_ARGS="-javaagent:${BYTEMAN_HOME}/lib/byteman.jar=script:${TRACE_SCRIPT}"
(3) 運行測試命令 bin/flink run -m yarn-cluster -p 1 ./examples/streaming/WordCount.jar ,控制台將輸出內容:
——->CliFrontend#getActiveCustomCommandLine return: org.apache.flink.yarn.cli.FlinkYarnSessionCli@25ce9dc4
Flink Cluster 常見問題與排查思路
▼ 用戶應用和框架 JAR 包版本衝突問題
該問題通常會拋出 NoSuchMethodError/ClassNotFoundException/IncompatibleClassChangeError 等異常,要解決此類問題:
1.首先需要根據異常類定位依賴庫,然後可以在項目中執行 mvn dependency:tree 以樹形結構展示全部依賴鏈,再從中定位衝突的依賴庫,也可以增加參數 -Dincludes 指定要顯示的包,格式為 [groupId]:[artifactId]:[type]:[version],支援*匹配,多個用逗號分隔,例如:mvn dependency:tree -Dincludes=*power*,*javaassist*;
2.定位衝突包後就要考慮如何排包,簡單的方案是用 exclusion 來排除掉其從他依賴項目中傳遞過來的依賴,不過有的應用場景需要多版本共存,不同組件依賴不同版本,就要考慮用 Maven Shade 插件來解決,詳情請參考 Maven Shade Plugin。
▼ 依賴庫有多版本 JAR 包共存時如何確定某類的具體來源?
很多應用運行 CLASSPATH 中存在相同依賴庫的多個版本 JAR 包,導致實際使用的版本跟載入順序有關,排查問題時經常需要確定某個類的來源 JAR,Flink 支援給 JM/TM 進程配置 JVM 參數,因此可以通過下面三個配置項來列印載入類及其來源(輸出在 .out 日誌),根據具體需要選擇其中之一即可:
▼ Flink 應用的完整日誌如何查看?
Flink 應用運行中的 JM/TM 日誌可以在 WebUI 上查看,但是查問題時通常需要結合完整日誌來分析排查,因此就需要了解 YARN 的日誌保存機制,YARN 上 Container 日誌保存位置跟應用狀態有關:
1.如果應用還沒有結束,Container 日誌會一直保留在其運行所在的節點上,即使 Container 已經運行完成仍然可以在所在節點的配置目錄下找到: ${yarn.nodemanager.log-dirs}/<APPLICATION_ID>/<CONTAINER_ID>,也可以直接從 WebUI訪問:http://<NM_ADDRESS>/node/containerlogs/<CONTAINER_ID>/<USER>
2.如果應用已結束並且集群啟用了日誌收集(yarn.log-aggregation-enable=true),則通常應用結束後(也有配置可以增量上傳)NM會將其全部日誌上傳至分散式存儲(通常是 HDFS)並刪除本地文件,我們可以通過 yarn 命令 yarn logs -applicationId <APPLICATION_ID> -appOwner <USER> 查看應用的全部日誌,還可以增加參數項 -containerId <CONTAINER_ID> -nodeAddress <NODE_ADDRESS> 來查看某 container 的日誌,也可以直接訪問分散式存儲目錄:${yarn.nodemanager.remote-app-log-dir}/${user}/${yarn.nodemanager.remote-app-log-dir-suffix}/<APPLICATION_ID>
▼ Flink 應用資源分配問題排查思路
如果 Flink 應用不能正常啟動達到 RUNNING 狀態,可以按以下步驟進行排查:
1.需要先檢查應用當前狀態,根據上述對啟動流程的說明,我們知道:
- 處於 NEW_SAVING 狀態時正在進行應用資訊持久化,如果持續處於這個狀態我們需要檢查 RM 狀態存儲服務(通常是 ZooKeeper 集群)是否正常;
- 如果處於 SUBMITTED 狀態,可能是 RM 內部發生一些 hold 讀寫鎖的耗時操作導致事件堆積,需要根據 YARN 集群日誌進一步定位;
- 如果處於 ACCEPTED 狀態,需要先檢查 AM 是否正常,跳轉到步驟2;
- 如果已經是 RUNNING 狀態,但是資源沒有全部拿到導致 JOB 無法正常運行,跳轉到步驟 3;
2.檢查 AM 是否正常,可以從 YARN 應用展示介面(http://<rmAddress>/cluster/app/<APPLICATION_ID>)或 YARN 應用 REST API(http://<rmAddress>/ws/v1/cluster/apps/<APPLICATION_ID>)查看 diagnostics 資訊,根據關鍵字資訊明確問題原因與解決方案:
- Queue's AM resource limit exceeded. 原因是達到了隊列 AM 可用資源上限,即隊列的 AM 已使用資源和 AM 新申請資源之和超出了隊列的 AM 資源上限,可以適當調整隊列 AM 可用資源百分比的配置項:yarn.scheduler.capacity.<QUEUE_PATH>.maximum-am-resource-percent。
- User's AM resource limit exceeded. 原因是達到了應用所屬用戶在該隊列的 AM 可用資源上限,即應用所屬用戶在該隊列的 AM 已使用資源和 AM 新申請資源之和超出了應用所屬用戶在該隊列的 AM 資源上限,可以適當提高用戶可用 AM 資源比例來解決該問題,相關配置項:yarn.scheduler.capacity.<QUEUE_PATH>.user-limit-factor 與 yarn.scheduler.capacity.<QUEUE_PATH>.minimum-user-limit-percent。
- AM container is launched, waiting for AM container to Register with RM. 大致原因是 AM 已啟動,但內部初始化未完成,可能有 ZK 連接超時等問題,具體原因需排查 AM 日誌,根據具體問題來解決。
- Application is Activated, waiting for resources to be assigned for AM. 該資訊表示應用 AM 檢查已經通過,正在等待調度器分配,此時需要進行調度器層面的資源檢查,跳轉到步驟 4。
3.確認應用確實有 YARN 未能滿足的資源請求:從應用列表頁點擊問題應用 ID 進入應用頁面,再點擊下方列表的應用實例 ID 進入應用實例頁面,看 Total Outstanding Resource Requests 列表中是否有 Pending 資源,如果沒有,說明 YARN 已分配完畢,退出該檢查流程,轉去檢查 AM;如果有,說明調度器未能完成分配,跳轉到步驟4;
4.調度器分配問題排查,YARN-9050 支援在 WebUI 上或通過 REST API 自動診斷應用問題,將在 Hadoop3.3.0 發布,之前的版本仍需進行人工排查:
- 檢查集群或 queue 資源,scheduler 頁面樹狀圖葉子隊列展開查看資源資訊:Effective Max Resource、Used Resources:(1)檢查集群資源或所在隊列資源或其父隊列資源是否已用完;(2)檢查葉子隊列某維度資源是否接近或達到上限;
- 檢查是否存在資源碎片:(1)檢查集群 Used 資源和 Reserved 資源之和佔總資源的比例,當集群資源接近用滿時(例如 90% 以上),可能存在資源碎片的情況,應用的分配速度就會受影響變慢,因為大部分機器都沒有資源了,機器可用資源不足會被 reserve,reserved 資源達到一定規模後可能導致大部分機器資源被鎖定,後續分配可能就會變慢;(2)檢查 NM 可用資源分布情況,即使集群資源使用率不高,也有可能是因為各維度資源分布不同造成,例如 1/2 節點上的記憶體資源接近用滿 CPU 資源剩餘較多,1/2 節點上的 CPU 資源接近用滿記憶體資源剩餘較多,申請資源中某一維度資源值配置過大也可能造成無法申請到資源;
- 檢查是否有高優先順序的問題應用頻繁申請並立即釋放資源的問題,這種情況會造成調度器忙於滿足這一個應用的資源請求而無暇顧及其他應用;
- 檢查是否存在 Container 啟動失敗或剛啟動就自動退出的情況,可以查看 Container 日誌(包括 localize 日誌、launch 日誌等)、YARN NM 日誌或 YARN RM 日誌進行排查。
▼ TaskManager 啟動異常: org.apache.hadoop.yarn.exceptions.YarnException: Unauthorized request to start container. This token is expired. current time is … found …
該異常在 Flink AM 向 YARN NM 申請啟動 token 已超時的 Container 時拋出,通常原因是 Flink AM 從 YARN RM 收到這個 Container 很久之後(超過了 Container有效時間,默認 10 分鐘,該 Container 已經被釋放)才去啟動它,進一步原因是 Flink 內部在收到 YARN RM 返回的 Container 資源後串列啟動。
當待啟動的 Container 數量較多且分散式文件存儲如 HDFS 性能較慢(啟動前需上傳 TaskManager 配置)時 Container 啟動請求容易堆積在內部,FLINK-13184 對這個問題進行了優化,一是在啟動前增加了有效性檢查,避免了無意義的配置上傳流程,二是進行了非同步多執行緒優化,加快啟動速度。
▼ Failover 異常 1: java.util.concurrent.TimeoutException: Slot allocation request timed out for …
異常原因是申請的 TaskManager 資源無法正常分配,可以按 Flink 應用資源分配問題排查思路的步驟4排查問題。
▼ Failover 異常 2: java.util.concurrent.TimeoutException: Heartbeat of TaskManager with id <CONTAINER_ID> timed out.
異常直接原因是 TaskManager 心跳超時,進一步原因可能有:
- 進程已退出,可能自身發生錯誤,或者受到 YARN RM 或 NM 上搶佔機制影響,需要進一步追查 TaskManager 日誌或 YARN RM/NM 日誌;
- 進程仍在運行,集群網路問題造成失聯,連接超時會自行退出,JobManager 在該異常後會 Failover 自行恢復(重新申請資源並啟動新的 TaskManager);
- 進程 GC 時間過長,可能是記憶體泄露或記憶體資源配置不合理造成,需根據日誌或分析記憶體進一步定位具體原因。
▼ Failover 異常 3: java.lang.Exception: Container released on a lost node
異常原因是 Container 運行所在節點在 YARN 集群中被標記為 LOST,該節點上的所有 Container 都將被 YARN RM 主動釋放並通知 AM,JobManager 收到此異常後會 Failover 自行恢復(重新申請資源並啟動新的 TaskManager),遺留的 TaskManager 進程可在超時後自行退出。
▼ Flink Cluster 疑難問題排查思路
首先根據 JobManager/TaskManager 日誌分析定位問題,完整日誌請參考「Flink 應用的完整日誌如何查看」,如果想獲取 DEBUG 資訊,需修改 JobManager/TaskManager 的 log4j 配置(${FLINK_HOME}/conf/log4j.properties)後重新提交運行,對於仍在運行的進程,推薦使用 Java 位元組碼注入工具 Byteman 來一窺進程內部的相關狀態,詳細說明請參考:How Do I Install The Agent Into A Running Program?
參考資料
文中綠色字體部分均有跳轉,詳細參考資料請見下方鏈接:
- Byteman Documents
https://byteman.jboss.org/docs.html
- Maven Shade Plugin
http://maven.apache.org/plugins/maven-shade-plugin/
- YARN-9050
https://issues.apache.org/jira/browse/YARN-9050
- FLINK-13184
https://issues.apache.org/jira/browse/FLINK-13184
- How Do I Install The Agent Into A Running Program?
https://developer.jboss.org/wiki/ABytemanTutorial#how_do_i_run_a_program_using_byteman
Flink on YARN 上、下兩篇文章對 Flink on YARN 應用啟動全流程進行梳理,並對客戶端和 Flink Cluster 的常見問題提供了排查思路,供大家參考,希望在應用實踐中能夠對大家有所幫助。