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 函數退出時列印其傳回值;
RULE test CLASS org.apache.flink.client.cli.CliFrontend METHOD getActiveCustomCommandLine AT EXIT IF TRUE DO traceln("------->CliFrontend#getActiveCustomCommandLine return: "+$!); ENDRULE
(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: [email protected]
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 日志),根據具體需要選擇其中之一即可:
env.java.opts=-verbose:class //配置JobManager&TaskManager env.java.opts.jobmanager=-verbose:class //配置JobManager env.java.opts.taskmanager=-verbose:class //配置TaskManager
▼ 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?