issue:yarn-11396

語言: CN / TW / HK

在容量排程方式中,佇列的capacity引數是作用於單個使用者可以使用的資源上限,這個在文章《YARN——正確理解容量排程的capacity引數》一文中詳細講解過。

然而,最近一次發測自驗過程中,發現單個使用者提交的任務,其資源使用超過了佇列的capacity配置引數,甚至是幾乎用滿了叢集的全部資源

本文就該問題進行分析總結。


前兩天,在版本發測自驗時,同事運行了一個flink任務,然後去吃飯了,回來正準備看執行結果時,任務還未結束,但發現該任務用光了叢集的所有資源。

於是問了我一句,一個佇列在capacity配置為30%,maximum-capacity配置為100%的時候,單個任務能用到多少資源?

我信心滿滿地告訴他:單個使用者最多能用叢集30%的資源,也就是capacity配置的值,多個使用者累加在一起可以用滿叢集的全部資源。

同事:我這單個使用者提交的單個任務,已經用完了叢集的全部資源,你要不幫我看下?

我:額,有沒有可能是最後一個container資源申請的時候,資源非常大導致出現了該問題呢。

同事:沒有,總共申請了400多個container,每個container都是3核2G的資源。

我:哦,這樣的話,應該是不可能申請到這麼多資源的才對,頂多也就30%多一點,那有沒有可能是先運行了任務,然後調整了佇列的資源大小呢?

同事:我看過日誌了,佇列的資源大小一直沒有調整過,就是這麼多。

我:那你把環境發我,我看下吧。

登入到環境匯中,看了下RM的日誌,發現佇列裡面只有一個任務(也就是有問題的這個flink任務),但是該flink任務重試了多次,也就是jobmanager退出後,yarn重新拉起了一個新的jobmanger,而jobmanager每次都申請100多個container(taskManager),累計400多個container,最終將資源全部用完。

看到這裡,開始疑惑起來,jobmanager退出重試是符合邏輯的, 但是重試後為什麼申請container還能分配到資源呢,不應該是達到使用者資源使用上限,不會排程分配資源才對啊

日誌無法分析出結果,那就還得原始碼來說話!

經過一番分析後,還是從原始碼中找到了問題,關鍵步驟及程式碼如下所示:

  • AM(異常)結束後,最終會觸發RM內部產生移除attempt事件,排程器在處理移除該事件時,根據任務的配置決定是否將該attempt申請的container全部kill,然後由任務所屬的佇列進行處理。

在佇列的處理中,主要是重新計算已使用的資源,包括佇列中該使用者已使用的資源

上面這兩段程式碼中,有兩個關鍵資訊:

1、第一步中,根據任務的配置決定是否將該attempt申請的container全部kill,具體來說,這個配置項為:"keepContainersAcrossApplicationAttempts"。其作用也就是當AM異常時,不主動殺掉AM所申請出來的正在執行的container,當建立新的AM時,主動告知之前已執行的container資訊。避免誤殺從而提高任務的處理速度。

但是,在MR/Spark/Flink三種主流任務型別中,只有flink對該配置項的值設定為true,即僅有flink支援該配置項。

2、在第二步中,在使用者管理裡刪除使用者的條件是:該使用者當前沒有活躍的attempt(包括正在執行的和等待執行的attempt)。

注:在每個佇列中都維護了一個使用者管理資訊,裡面記錄了當前佇列中所有使用者提交的任務數、以及累計使用的資源,方便進行排程時進行判斷,是否還可以繼續分配資源。

對應的結構體如下所示:

再接著來看任務重試,即重新建立新的attempt時的邏輯:排程器在處理新增attemtp事件時,先在記憶體記錄相關資訊後,然後交由任務提交的佇列處理,而在佇列的處理邏輯中,主要就是在使用者管理中,查詢對應的使用者資訊,如果沒有該使用者,則建立一個新的使用者資訊,然後記錄使用者的相關資訊。


此後進行排程時,判斷該使用者的資源是否超過使用上限,如果沒有則可以分配資源,否則會提示該使用者在當前佇列中已經超過限制,無法繼續分配資源。


如此一來,整個問題可以全部得到解釋:

即佇列中的首個flink任務,正常執行一段時間後,AM(jobmanager)異常退出;

接著,在rm排程器內部清除attempt後,發現該使用者沒有活躍的attempt,因此在佇列中連同使用者資訊一併刪除(但此時已經分配排程的container,也就是taskmanager仍舊在執行)

此後,任務進入重試邏輯,重新新增一個新的attempt,在佇列中找不到該使用者資訊,因此重新初始化並新增該使用者資訊,但此時新新增使用者時並沒有將之前未刪除的container的資源計算在內,而是簡單的將已使用的資源初始化為0;

再然後,隨著NM的心跳上報,開始分配資源進行排程,由於記憶體中記錄的該使用者當前已使用資源未達到限制,因此允許資源分配。

這樣,當AM多次退出重試後,每次都能分配到資源,也就將叢集的資源全部用完。

知曉完整流程後,自然也就能輕鬆地復現問題。

注:這是在AM進行一次重試後的截圖:上面是佇列中的使用者統計資訊,AM每次申請5個container,一個是任務的統計資訊,兩者明顯是不一致的。

對於該問題,其實比較好解決,我們當前也已經向社群提單,並準備了patch(還未推送),有興趣的朋友,可以去檢視issue並關注下後面的patch(https://issues.apache.org/jira/browse/YARN-11396

好了,這就是本文的全部內容,如果覺得本文對您有幫助,請點贊+轉發,也歡迎加我微信交流~

本文分享自微信公眾號 - 陳猿解碼(gh_383bc7486c1a)。
如有侵權,請聯絡 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。