
作者 |
車漾 阿裡雲進階技術專家
範斌 Alluxio 創始成員,開源社群副總裁
來源 |
阿裡巴巴雲原生公衆号為什麼要加速雲端深度學習
人工智能是近幾年非常火熱的技術領域,而推動這個領域快速演進的原動力包括以英偉達 GPU 為代表的異構算力,以 TensorFlow,Pytorch 為代表的的機器學習架構,以及海量的資料集。除此之外我們也發現了一個趨勢,就是以 Kubernetes 和 Docker 為代表的容器化基礎架構也成為了資料科學家的首選,這主要有兩個因素:分别是标準化和規模化。比如 TensorFlow,Pytorch 的軟體釋出過程中一定包含容器版本,這主要是仰仗容器的标準化特點。另一方面以 Kubernetes 為基礎的叢集排程技術使大規模的分布式訓練成為了可能。
背景
首先我們觀察下圖,這是模拟資料下的深度學習模型訓練速度,所謂模拟資料的意思就是這個測試中沒有 IO 的影響。從這個圖中我們可以得到兩個發現:
- GPU 硬體更新的加速效果顯著。從單卡的算力看,pascal 架構為代表的 P100 一秒鐘隻能處理 300 張圖檔,而 volta 架構的 v100一秒鐘可以處理 1200 張圖檔,提升了 4 倍。
- 分布式訓練的也是有效加速的方式。從單卡 P100 到分布式 32 卡 v100,可以看到訓練速度提升了 300 倍。
1. 模拟資料訓練速度
而從訓練時間來看,同樣的資料,同樣的訓練目标,單卡 P100 需要 108 個小時,4 天半的時間。而 V100 的 32 卡分布式訓練隻需要 1 小時。而從成本上來看,單卡 P100 的成本是接近 1400 元,而 8 卡 V 100 是 600 元,不到一半。
可以發現,更新的 GPU 硬體不但會更高效,實際上也會更省錢。這也許就是黃教主說的買的越多,省的越多。從雲資源的角度來說還是有道理的。
2. 模拟資料訓練時間
但是之前的測試結果實際上是做了一些前提假設,就是沒有資料延時的影響。而真實的情況下,模型訓練是離不開海量資料的通路。而實際上:
- 強大的算力需要與之比對的資料通路能力,不論是延時還是吞吐,都提出了更高的需求。下面的圖可以看到,在雲盤的資料讀取的情況下,GPU 的訓練速度直接降為了原來的三分之一。GPU 的使用率也很高。
- 在雲環境下,計算和存儲分離後,一旦沒有了資料本地化,又明顯惡化了 I/O 影響。
- 此時如果能夠把資料直接加載到計算的節點上,比如ossutil把資料拷貝到 GPU 機器是不是可以滿足計算的需求呢。實際上也還是不夠的,因為一方面資料集無法全集控制,另一方面AI場景下是全量資料集,一旦引入驅逐機制,實際上性能影響也非常顯著。是以我們意識到在 K8s 下使用分布式緩存的意義。
Alluxio 是什麼
Alluxio 是一個面向 AI 以及大資料應用,開源的分布式記憶體級資料編排系統。在很多場景底下, Alluxio 非常适合作為一個分布式緩存來加速這些應用。這個項目是李浩源博士在加州大學 Berkeley 分校的 AMPLab 攻讀博士的時候創立的,最早的名字 Tachyon。AMPLab 也是孵化出了 Spark 和 Mesos 等優秀開源項目的功勳實驗室。2015 年,由頂級的風險投資 Andreessen Horowitz 投資,Alluxio 項目的主要貢獻者在舊金山灣區成立了 Alluxio 這家公司。
1. Alluxio - 分布式緩存的上司者
2. Alluxio 的簡介
簡單看一下在大資料和 AI 生态圈裡, Alluxio 處于什麼位置。在大資料軟體棧裡,Alluxio 是新的一層,我們稱之為資料編排層。它向上對接計算應用,比如Spark, Presto,Hive,Tensorflow,向下對接不同的存儲,比如阿裡巴巴的 OSS,HDFS。我們希望通過這一層新加入的資料編排層,可以讓計算和存儲之間的強關聯解耦。進而讓計算和存儲都可以獨立而更靈活的部署和演進。資料應用可以不必關心和維護資料存儲的具體類型,協定,版本,地理位置等。而資料的存儲也可以通過資料編排這一層更靈活更高效的被各種不同應用消費。
3. Alluxio 的核心功能
1)分布式資料緩存
下面介紹一下 Alluxio 的核心功能。Alluxio 最核心的服務就是提供一個分布式的資料緩存用來加速資料應用。對于 Spark,Presto,Tensorflow 等資料密集型的應用,當讀取非本地的資料源時,Alluxio 可以通過加載原始資料檔案,将其分片以及打散,并存儲在靠近應用的 Alluxio 伺服器上, 增強這些應用的資料本地性。
比如在這個例子裡, 檔案 1 和檔案 2 分别被分片後存儲在不同的 Alluxio 伺服器上,應用端可以就近從存儲了對應的資料分片的伺服器讀取。當應用需要的讀入有明顯的熱資料時, 添加緩存層可以顯著的節省資源以及提升效率。
2)靈活多樣的資料通路 API
Alluxio 的第二個核心應用,是對應用提供不同類型的資料接口,包括在大資料領域最常見的 HDFS 接口,以及在 ai 和模型訓練場景下常用的 POSIX 标準檔案系統接口。
這樣同樣的資料一旦準備完畢, 可以以不同的形式呈現給應用,而不用做多次處理或者 ETL。
3)統一檔案系統抽象
Alluxio 的第三個核心功能,是把多個不同的存儲系統,以對使用者透明的方式,統一接入一個檔案系統抽象中。這樣使得複雜的資料平台變得簡單而易于維護。資料消費者,隻需要知道資料對應的邏輯位址,而不用去關心底層對接的時候什麼存儲系統。
舉個例子, 如果一家公司同時有多個不同的 HDFS 部署,并且線上上接入了 Alibaba 的 OSS 服務, 那麼我們完全可以使用 Alluxio 的挂載功能,把這些系統接入一個統一的邏輯上的 Alluxio 檔案系統抽象中。每一個 HDFS 會對應到不同的 Alluxio 目錄。
Alluxio 在雲端 AI 訓練場景的性能好處
介紹完了 Alluxio 的核心功能,讓我們聚焦在雲端 AI 訓練場景下,再來回顧一下 Alluxio 可能帶來的好處。在模型訓練場景下記憶體加速才能滿足 GPU 需要的高吞吐。如果通過普通的網絡從 Object store 傳輸資料, 大約能支撐 300MB/s, 這遠遠不能達到充分使用訓練資源特别是 GPU 高吞吐的特性。但是一旦利用 Alluxio 建構了一層分布式的資料緩存,負責訓練的容器程序和 alluxio worker 容器程序就可以以很高的速率交換資料。比如當兩者在同一實體主機上的時候, 可以達到 1-6GB 每秒。從其他 alluxioworker 處讀取也可以通常達到 1-2GB/s 。
此外,通過 Alluxio 可以實作非常簡單便捷的分布式緩存管理,比如設定緩存替換政策,設定資料的過期時間,預讀取或者驅逐特定目錄下的資料等等操作。這些都可以給模型訓練帶來效率的提升和管理的便捷。
Alluxio 在 Kubernetes 上的架構
要在 Kubernetes 中原生的使用 Alluxio,首先就要把它部署到 K8s 中,是以我們的第一步工作和 Alluxio 團隊一起提供一個 Helmchart,可以統一的配置使用者身份,參數以及分層緩存配置。
從左圖中看,這裡 Alluxio 的 master 以 statefulset 的模式部署,這是因為 Alluxiomaster 首先需要穩定,唯一的網絡 id,可以應對容災等複雜場景。而 worker 和 Fuse 以 daemonset 的模式部署,并且二者通過 podaffinity 綁定,這樣可以使用到資料親和性。
KubeNode - Remedy Operator
通過将應用完成 helm 化之後,部署它就變成了非常簡單的事情,隻需要編寫 cong.yaml,執行 helminstall 就可以一鍵式在 Kubernetes 中部署 Alluxio。大家感興趣的話可以檢視 alluxio 文檔,或者借鑒阿裡雲容器服務的文檔。
Alluxio 支援 AI 模型訓練場景的挑戰
在性能評估中,我們發現當 GPU 硬體從 NVidia P100 更新到 NVidia V100 之後,單卡的計算訓練速度得到了不止 3 倍的提升。計算性能的極大提升給資料存儲通路的性能帶來了壓力。這也給 Alluxio 的 I/O 提出了新的挑戰。
下圖是在分别在合成資料 (Synthetic Data) 和使用 Alluxio 緩存的性能對比,橫軸表示 GPU 的數量,縱軸表示每秒鐘處理的圖檔數。合成資料指訓練程式讀取的資料有程式自身産生,沒有 I/O 開銷,代表模型訓練性能的理論上限; 使用 Alluxio 緩存指訓練程式讀取的資料來自于 Alluxio 系統。在 GPU 數量為 1 和 2 時,使用 Alluxio 和合成資料對比,性能差距在可以接受的範圍。但是當 GPU 的數量增大到 4 時,二者差距就比較明顯了,Alluxio 的處理速度已經從 4981 images/second 降到了 3762 images/second。而當 GPU 的數量達到 8 的時候,Alluxio 上進行模型訓練的性能不足合成資料的 30%。而此時通過系統監控,我們觀察到整個系統的計算、記憶體和網絡都遠遠沒有達到瓶頸。這間接說明了簡單使用 Alluxio 難以高效支援 V100 單機 8 卡的訓練場景。
調優政策
1. 緩存中繼資料減少 gRPC 互動
Alluxio 不隻是一個單純的緩存服務。它首先是一個分布式虛拟檔案系統,包含完整的中繼資料管理、塊資料管理、UFS 管理(UFS 是底層檔案系統的簡稱)以及健康檢查機制,尤其是它的中繼資料管理實作比很多底層檔案系統更加強大。這些功能是 Alluxio 的優點和特色,但也意味着使用分布式系統帶來的開銷。例如,在預設設定下使用 Alluxio 用戶端來讀一個檔案,即便資料已經緩存在本地的 Alluxio Worker 中,用戶端也會和 Master 節點有多次 RPC 互動來擷取檔案元資訊以保證資料的一緻性。完成整個讀操作的鍊路額外開銷在傳統大資料場景下并不明顯,但是深度面對學習場景下高吞吐和低延時的需求就顯得捉襟見肘了。是以我們要提供用戶端的中繼資料緩存能力。
2. Alluxio 緩存行為控制
由于深度學習訓練場景下,每次訓練疊代都是全量資料集的疊代,緩存幾個 TB 的資料集對于任何一個節點的存儲空間來說都是捉襟見肘。而 Alluxio 的預設緩存政策是為大資料處理場景(例如查詢)下的冷熱資料分明的需求設計的,資料緩存會儲存在 Alluxio 用戶端所在的本地節點,用來保證下次讀取的性能最優。具體來說:
- alluxio.user.ufs.block.read.location.policy 預設值為 alluxio.client.block.policy.LocalFirstPolicy,這表示 Alluxio 會不斷将資料儲存到 Alluxio 用戶端所在的本地節點,就會引發其緩存資料接近飽和時,該節點的緩存一直處于抖動狀态,引發吞吐和延時極大的下降,同時對于 Master 節點的壓力也非常大。是以需要 location.policy 設定為 alluxio.client.block.policy.LocalFirstAvoidEvictionPolicy 的同時,指定 alluxio.user.block.avoid.eviction.policy.reserved.size.bytes 參數,這個參數決定了當本地節點的緩存資料量到一定的程度後,預留一些資料量來保證本地緩存不會被驅逐。通常這個參數應該要大于節點緩存上限 X(100%-節點驅逐上限的百分比)。
- alluxio.user.file.passive.cache.enabled 設定是否在 Alluxi 的本地節點中緩存額外的資料副本。這個屬性是預設開啟的。是以,在 Alluxio 用戶端請求資料時,它所在的節點會緩存已經在其他 Worker 節點上存在的資料。可以将該屬性設為 false,避免不必要的本地緩存。
- alluxio.user.file.readtype.default 預設值為 CACHE_PROMOTE。這個配置會有兩個潛在問題,首先是可能引發資料在同一個節點不同緩存層次之間的不斷移動,其次是對資料塊的大多數操作都需要加鎖,而 Alluxio 源代碼中加鎖操作的實作不少地方還比較重量級,大量的加鎖和解鎖操作在并發較高時會帶來不小的開銷,即便資料沒有遷移還是會引入額外開銷。是以可以将其設定為 CACHE 以避免 moveBlock 操作帶來的加鎖開銷,替換預設的 CACHE_PROMOTE。
3. Fuse 性能調優
1)延長 FUSE 中繼資料有效時間
Linux 中每個打開檔案在核心中擁有兩種中繼資料資訊:
struct dentry
和
struct inode
,它們是檔案在核心的基礎。所有對檔案的操作,都需要先擷取檔案這兩個結構。是以,每次擷取檔案/目錄的 inode 以及 dentry 時,FUSE 核心子產品都會從 libfuse 以及 Alluxio 檔案系統進行完整操作,這樣會帶來資料通路的高延時和高并發下對于 Alluxio Master 的巨大壓力。可以通過配置
–o entry_timeout=T –o attr_timeout=T
進行優化。
2)配置 max_idle_threads
避免頻繁線程建立銷毀引入 CPU 開銷
max_idle_threads
這是由于 FUSE 在多線程模式下,以一個線程開始運作。當有兩個以上的可用請求,則 FUSE 會自動生成其他線程。每個線程一次處理一個請求。處理完請求後,每個線程檢查目前是否有超過
max_idle_threads
(預設 10)個線程;如果有,則該線程回收。而這個配置實際上要和使用者程序生成的 I/O 活躍數相關,可以配置成使用者讀線程的數量。而不幸的是
max_idle_threads
本身隻在 libfuse3 才支援,而 AlluxioFUSE 隻支援 libfuse2,是以我們修改了 libfuse2 的代碼支援了
max_idle_threads
的配置。
總結
在優化 Alluxio 之後,ResNet50 的訓練性能單機八卡性能提升了 236.1%,并且擴充性問題得到了解決,訓練速度在不但可以擴充到了四機八卡,而且在此場景下和合成資料相比性能損失為 3.29%(31068.8images/s vs 30044.8 images/s)。相比于把資料儲存到 SSD 雲盤,在四機八卡的場景下,Alluxio 的性能提升了 70.1% (雲 SSD 17667.2 images/s vs 30044.8 images/s)。
端到端的優化方案
如果您對通過 Alluxio 在 Kubernetes 中加速深度學習感興趣,歡迎釘釘掃碼加入中國社群大群。我們一起來讨論您的場景和問題。
作者簡介
範斌,是 Alluxio 的創始成員,曾經就職于 Google,早期負責 Alluxio 的架構設計,現在關注于 Alluxio 開源社群的營運。
車漾,就職于阿裡雲容器服務團隊,關注于雲原生技術與 AI、大資料場景的結合。