天天看點

AI+雲原生,把衛星遙感虐的死去活來

摘要:遙感影像,作為地球自拍照,能夠從更廣闊的視角,為人們提供更多元度的輔助資訊,來幫助人類感覺自然資源、農林水利、交通災害等多領域資訊。

本文分享自華為雲社群《AI+雲原生,把衛星遙感虐的死去活來》,作者:tsjsdbd。

遙感影像,作為地球自拍照,能夠從更廣闊的視角,為人們提供更多元度的輔助資訊,來幫助人類感覺自然資源、農林水利、交通災害等多領域資訊。

AI技術,可以在很多領域超過人類,關鍵是它是自動的,省時又省力。可顯著提升遙感影像解譯的工作效率,對各類地物元素進行自動化的檢測,例如建築物,河道,道路,農作物等。能為智慧城市發展&治理提供決策依據。

AI+雲原生,把衛星遙感虐的死去活來

雲原生技術,近年來可謂是一片火熱。易建構,可重複,無依賴等優勢,無論從哪個角度看都與AI算法天生一對。是以大家也可以看到,各領域的AI場景,大都是将AI推理算法運作在Docker容器裡面的。

AI+雲原生這麼6,那麼強強聯手後,地物分類、目标提取、變化檢測等高性能AI解譯不就手到擒來?我們也是這麼認為的,是以基于AI+Kubernetes雲原生,建構了支援遙感影像AI處理的空天地平台。

不過理想是好的,過程卻跟西天取經一般,九九八十一難,最終修成正果。

遇到問題的業務場景叫影像融合(Pansharpen),也就是對地球自拍照進行“多鏡頭合作美顔”功能。(可以了解成:手機的多個攝像頭,同時拍照,合并成一張高清彩色大圖)。

AI+雲原生,把衛星遙感虐的死去活來

是以業務簡單總結就是:讀取2張圖檔,生成1張新的圖檔。該功能我們放在一個容器裡面執行,每張融合後的結果圖檔大約5GB。

問題的關鍵是,一個批次業務量需要處理的是3000多張衛星影像,是以每批任務隻需要同時運作完成3000多個容器就OK啦。雲原生YYDS!

為了幫助了解,這裡分解使用雲原生架構實作該業務場景的邏輯圖如下:

AI+雲原生,把衛星遙感虐的死去活來

在雲上,原始資料,以及結果資料,一定是要存放在對象存儲桶裡面的。因為這個資料量,隻有對象存儲的價格是合适的。(對象存儲,1毛錢/GB。檔案存儲則需要3毛錢/GB)

因為容器之間是互相獨立無影響的,每個容器隻需要處理自己的那幅影像就行。例如1号容器處理 1.tif影像;2号容器處理2.tif影像;一次類推。

是以管理程式,隻需要投遞對應數量的容器(3000+),并監控每個容器是否成功執行完畢就行(此處為簡化說明,實際業務場景是一個pipeline處理流程)。那麼,需求已經按照雲原生理想的狀态分解,咱們開始起(tang)飛(keng)吧~

注:以下描述的問題,是經過梳理後呈現的,實際問題出現時是互相穿插錯綜複雜的。

當作業投遞後,不多久系統就顯示作業紛紛失敗。檢視日志報調用K8s接口失敗,再一看,K8s的Master都已經挂了。。。

K8s-Master處理過程,總結版:

發現Master挂是因為CPU爆了

是以擴容Master節點(此次重複N次);

性能優化:擴容叢集節點數量;

性能優化:容器分批投放;

性能優化:查詢容器執行進度,少用ListPod接口;

詳細版:

看監控Master節點的CPU已經爆掉了,是以最簡單粗暴的想法就是給Master擴容呀,嘎嘎的擴。于是從4U8G * 3 一路擴容一路測試一路失敗,擴到了32U64G * 3。可以發現CPU還是爆滿。看來簡單的擴容是行不通了。

AI+雲原生,把衛星遙感虐的死去活來

3000多個容器,投給K8s後,大量的容器都處于Pending狀态(叢集整體資源不夠,是以容器都在排隊呢)。而正在Pending的Pod,K8s的Scheduler會不停的輪訓,去判斷能否有資源可以給它安排上。是以這也會給Scheduler巨大的CPU壓力。擴容叢集節點數量,可以減少排隊的Pod數量。

AI+雲原生,把衛星遙感虐的死去活來

另外,既然排隊的太多,不如就把容器分批投遞給K8s吧。于是開始分批次投遞任務,想着别一次把K8s壓垮了。每次投遞數量,減少到1千,然後到500,再到100。

同時,查詢Pod進度的時候,避免使用ListPod接口,改為直接查詢具體的Pod資訊。因為List接口,在K8s内部的處理會列出所有Pod資訊,處理壓力也很大。

這一套組合拳下來,Master節點終于不挂了。不過,一頭問題按下去了,另一頭問題就冒出來了。

雖然Master不挂了,但是當投遞1~2批次作業後,容器又紛紛失敗。

容器挂掉的處理過程,總結版:

發現容器挂掉是被eviction驅逐了;

Eviction驅逐,發現原因是節點報Disk Pressure(存儲容量滿了);

于是擴容節點存儲容量;

延長驅逐容器(主動kill容器)前的容忍時間;

(注:以下問題是定位梳理後,按順序呈現給大家。但其實出問題的時候,順序沒有這麼友好)

容器執行失敗,首先想到的是先看看容器裡面腳本執行的日志呗:結果報日志找不到~

AI+雲原生,把衛星遙感虐的死去活來

于是查詢Pod資訊,從event事件中發現有些容器是被Eviction驅逐幹掉了。同時也可以看到,驅逐的原因是 DiskPressure(即節點的存儲滿了)。

AI+雲原生,把衛星遙感虐的死去活來

當Disk Pressure發生後,節點被打上了驅逐标簽,随後啟動主動驅逐容器的邏輯:

AI+雲原生,把衛星遙感虐的死去活來

由于節點進入Eviction驅逐狀态,節點上面的容器,如果在5分鐘後,還沒有運作完,就被Kubelet主動殺死了。(因為K8s想通過幹掉容器來騰出更多資源,進而盡快退出Eviction狀态)。

AI+雲原生,把衛星遙感虐的死去活來

這裡我們假設每個容器的正常運作時間為1~2個小時,那麼不應該一發生驅動就馬上殺死容器(因為已經執行到一半的容器,殺掉重新執行是有成本浪費的)。我們期望應該盡量等待所有容器都運作結束才動手。是以這個 pod-eviction-timeout 容忍時間,應該設定為24小時(大于每個容器的平均執行時間)。

Disk Pressure的直接原因就是本地盤容量不夠了。是以得進行節點存儲擴容,有2個選擇:1)使用雲存儲EVS(給節點挂載雲存儲)。 2)擴容本地盤(節點自帶本地存儲的VM)。

由于雲存儲(EVS)的帶寬實在太低了,350MB/s。一個節點咱們能同時跑30多個容器,帶寬完全滿足不了。最終選擇使用 i3類型的VM。這種VM自帶本地存儲。并且将8塊NVMe盤,組成Raid0,帶寬還能x8。

容器執行繼續紛紛失敗。

容器往對象存儲寫入失敗處理過程,總結版:

不直接寫入,而是先寫到本地,然後cp過去。

将普通對象桶,改為支援檔案語義的并行檔案桶。

檢視日志發現,腳本在生成新的影像時,往存儲中寫入時出錯:

AI+雲原生,把衛星遙感虐的死去活來

我們整叢集是500核的規模,同時運作的容器數量大概在250個(每個2u2g)。這麼多的容器同時往1個對象存儲桶裡面并發追加寫入。這個應該是導緻該IO問題的原因。

對象存儲協定s3fs,本身并不适合大檔案的追加寫入。因為它對檔案的操作都是整體的,即使你往一個檔案追加寫入1位元組,也會導緻整個檔案重新寫一遍。

最終這裡改為:先往本地生成目标影像檔案,然後腳本的最後,再拷貝到對象存儲上。相當于增加一個臨時存儲中轉一下。

AI+雲原生,把衛星遙感虐的死去活來

在臨時中轉存儲選擇中,2種本地存儲都試過: 1)塊存儲帶寬太低,350MB/s影響整體作業速度。2)可以選擇帶本地存儲的VM,多塊本地存儲組成Raid陣列,帶寬速度都杠杠滴。

同時,華為雲在對象存儲協定上也有一個擴充,使其支援追加寫入這種的POSIX語義,稱為并行檔案桶。後續将普通的對象桶,都改為了檔案語義桶。以此來支撐大規模的并發追加寫入檔案的操作。

So,繼續跑任務。但是這容器作業,執行又紛紛失敗鳥~

計算節點挂掉,定位梳理後,總結版:

計算節點挂掉,是因為好久沒上報K8s心跳了。

沒上報心跳,是因為kubelet(K8s節點的agent)過得不太好(死掉了)。

是因為Kubelet的資源被容器搶光了(由于不想容器經常oom kill,并未設定limit限制)

為了保護kubelet,所有容器全都設定好limit。

詳細版,直接從各類奇葩亂象等問題入手:

容器啟動失敗,報逾時錯誤。

AI+雲原生,把衛星遙感虐的死去活來

然後,什麼PVC共享存儲挂載失敗:

AI+雲原生,把衛星遙感虐的死去活來

或者,又有些容器無法正常結束(删不掉)。

AI+雲原生,把衛星遙感虐的死去活來

查詢節點Kubelet日志,可以看到充滿了各種逾時錯誤:

AI+雲原生,把衛星遙感虐的死去活來

啊,這麼多的底層容器逾時,一開始感覺的Docker的Daemon程序挂了,通過重新開機Docker服務來試圖修複問題。

後面繼續定位發現,K8s叢集顯示,好多計算節點Unavailable了(節點都死掉啦)。

AI+雲原生,把衛星遙感虐的死去活來

繼續分析節點不可用(Unavailable),可以發現是Kubelet好久沒有給Master上報心跳了,是以Master認為節點挂了。說明不僅僅是Docker的Daemon受影響,節點的Kubelet也有受影響。

那什麼情況會導緻Kubelet,Docker這些主機程序都不正常呢?這個就要提到Kubernetes在排程容器時,所設計的Request和Limit這2個概念了。

Request是K8s用來排程容器到空閑計算節點上的。而Limit則會傳遞給Docker用于限制容器資源上限(觸發上限容易被oom killer 殺掉)。前期我們為了防止作業被殺死,僅為容器設定了Request,沒有設定Limit。也就是每個容器實際可以超出請求的資源量,去搶占額外的主機資源。大量容器并發時,主機資源會受影響。

考慮到雖然不殺死作業,對使用者挺友好,但是平台自己受不了也不是個事。于是給所有的容器都加上了Limit限制,防止容器超限使用資源,強制使用者程序運作在容器Limit資源之内,超過就Kill它。以此來確定主機程序(如Docker,Kubelet等),一定是有足夠的運作資源的。

于是,繼續跑任務。不少作業執行又雙叒失敗鳥~

節點又挂了,總結版:

分析日志,這次挂是因為PLEG(Pod Lifecycle Event Generator)失敗。

PLEG異常是因為節點上面存留的曆史容器太多(>500個),查詢用時太久逾時了。

及時清理已經運作結束的容器(即使跑完的容器,還是會占用節點存儲資源)。

容器接口各種逾時(cpu+memory是有limit保護,但是io還是會被搶占)。

提升系統磁盤的io性能,防止Docker容器接口(如list等)逾時。

現象還是節點Unavailable了,檢視Kubelet日志搜尋心跳情況,發現有PLEG is not healthy 的錯誤:

AI+雲原生,把衛星遙感虐的死去活來

于是搜尋PLEG相關的Kubelet日志,發現該錯誤還挺多:

AI+雲原生,把衛星遙感虐的死去活來

這個錯誤,是因為kubelet去list目前節點所有容器(包括已經運作結束的容器)時,逾時了。看了代碼:https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/pleg/generic.go#L203

kubelet判斷逾時的時間,3分鐘的長度是寫死的。是以當pod數量越多,這個逾時機率越大。很多場景案例表明,節點上的累計容器數量到達500以上,容易出現PLEG問題。(此處也說明K8s可以更加Flexible一點,逾時時長應該動态調整)。

緩解措施就是及時的清理已經運作完畢的容器。但是運作結束的容器一旦清理,容器記錄以及容器日志也會被清理,是以需要有相應的功能來彌補這些問題(比如日志采集系統等)。

List所有容器接口,除了容器數量多,IO慢的話,也會導緻逾時。

這時,從背景可以看到,在投遞作業期間,大量并發容器同時運作時,雲硬碟的寫入帶寬被大量占用:

AI+雲原生,把衛星遙感虐的死去活來

對存儲池的沖擊也很大:

AI+雲原生,把衛星遙感虐的死去活來

這也導緻了IO性能變很差,也會一定程度影響list容器接口逾時,進而導緻PLEG錯誤。

該問題的解決措施:盡量使用的帶本地高速盤的VM,并且将多塊資料盤組成Raid陣列,提高讀寫帶寬。

AI+雲原生,把衛星遙感虐的死去活來

這樣,該VM作為K8s的節點,節點上的容器都直接讀寫本地盤,io性能較好。(跟大資料叢集的節點用法一樣了,強依賴本地shuffle~)。

在這多條措施實施後,後續多批次的作業都可以平穩的運作完。

雲原生是趨勢,已經成為大家的共識,各領域也都開始以雲原生為底座的業務嘗試。AI是未來,這也是目前不可阻擋的力量。但是當AI踏上這條雲原生的道路卻不那麼一帆風順。至少可以看到,華為雲的雲原生底座(當然,也包括存儲、網絡等周邊基礎設施)還可以有更多的進步空間。

但是,大家也不用擔心太多,因為目前華為雲的空天地平台,在經曆了多年的AI+雲原生的積累,目前可以很穩定的處理PB級每日的遙感影像資料,支撐各類空基、天基、地基等場景,并且在該領域保持絕對領先的戰鬥值。雖然大家看到此間過程有點曲折,但是所有的困難都是涅槃的火種,克服過的困難都是今後可以對客戶做的承諾。在這裡可以很明确的告訴各位:AI+雲原生=真香。

寫這篇文章的目的,不是在闡述困難,而是為了總結分享。與同領域的人分享并促進遙感領域的快速發展,共同推動AI+雲原生的落地。

點選關注,第一時間了解華為雲新鮮技術~

繼續閱讀