傳統(tǒng)的機器學習模型凳寺,數(shù)據(jù)集比較小,模型的算法也比較簡單套啤,使用單機存儲宽气,或者本地硬盤就足夠了,像 JuiceFS 這樣的分布式存儲并不是必需品潜沦。
隨著近幾年深度學習的蓬勃發(fā)展萄涯,越來越多的團隊開始遇到了單機存儲的瓶頸,分布式存儲在 AI 領(lǐng)域的重要性不斷凸顯唆鸡。AI 團隊通常會面臨以下幾種問題:
數(shù)據(jù)集太大
隨著數(shù)據(jù)量和模型規(guī)模的增加涝影,單機存儲往往無法滿足需求。為解決這些問題争占,就需要使用分布式存儲燃逻。
歷史數(shù)據(jù)集需要進行全量歸檔
在某些應(yīng)用場景每天都會產(chǎn)生大量新的數(shù)據(jù)集序目,這些數(shù)據(jù)集在一段時間后將變?yōu)闅v史數(shù)據(jù),需要進行歸檔伯襟。由于這些數(shù)據(jù)的生成成本較高猿涨,因此不能輕易刪除,尤其是在自動駕駛領(lǐng)域姆怪,如路測車采集的雷達和攝像頭數(shù)據(jù)叛赚,這些數(shù)據(jù)對公司來說是極為寶貴的資產(chǎn)。若要整理這些數(shù)據(jù)稽揭,傳統(tǒng)的單機存儲顯然不足以滿足需求俺附,因此需要考慮使用分布式存儲。
小文件和非結(jié)構(gòu)化數(shù)據(jù)太多
針對傳統(tǒng)的分布式文件系統(tǒng)淀衣,管理大量小文件會帶來元數(shù)據(jù)存儲的負擔昙读,對于視覺類模型,影響更加明顯膨桥。解決這一問題的方法是使用對小文件存儲友好的分布式存儲系統(tǒng)蛮浑,這樣可以保證上層訓練任務(wù)的高效率,同時也能夠方便地管理大量的小文件只嚣。
訓練框架需要 POSIX 接口
最初算法科學家在做模型調(diào)研時沮稚,都是基于本地的資源來做研發(fā)和數(shù)據(jù)的訪問,但當需要在分布式存儲上進行更大規(guī)模的訓練時册舞,原本的代碼一般不會做太多的調(diào)整蕴掏。所以這就要求分布式存儲需要支持 POSIX 接口,最大程度上兼容本地開發(fā)階段的代碼调鲸。
公共數(shù)據(jù)集需要不同團隊共享盛杰,也可能需要數(shù)據(jù)隔離
在某些領(lǐng)域,如計算機視覺藐石,有一些權(quán)威的公共數(shù)據(jù)集即供,這些數(shù)據(jù)集需要在公司內(nèi)部不同的團隊間共享。為了方便團隊之間的使用于微,通常會將這些數(shù)據(jù)整合并打包存儲到一個共享存儲中逗嫡,避免不必要的數(shù)據(jù)復制和冗余。
云上訓練的數(shù)據(jù) I/O 效率不高
在云上進行模型訓練通常是使用對象存儲作為底層存儲的存算分離架構(gòu)株依,由于對象存儲的讀寫性能較差驱证,在訓練上會有很大的瓶頸。
本文將會介紹在模型訓練中如何使用 JuiceFS恋腕,以及優(yōu)化訓練效率的實踐抹锄。
1.JuiceFS 在模型訓練場景中的架構(gòu)
上圖是架構(gòu)圖,分為三個部分:
第一部分:元數(shù)據(jù)引擎,根據(jù)個人選擇伙单,可以使用任何數(shù)據(jù)庫呆万,例如 Redis、MySQL 等等车份,作為元數(shù)據(jù)引擎。
第二部分:底層數(shù)據(jù)存儲牡彻,在云上或私有云中扫沼,使用對象存儲服務(wù)來對接 JuiceFS。
第三部分:JuiceFS 客戶端庄吼,用戶在使用時需要在每個 GPU 和計算節(jié)點上掛載 JuiceFS缎除,這樣就可以像訪問本地硬盤一樣訪問 JuiceFS 的文件系統(tǒng)。
底層存儲依賴于對象存儲中的原始數(shù)據(jù)总寻,同時每個計算節(jié)點上還有一些本地緩存器罐,包括元數(shù)據(jù)和數(shù)據(jù)緩存。JuiceFS 的設(shè)計中渐行,每個計算節(jié)點的本地可以有多級緩存轰坊。第一級是基于內(nèi)存的緩存,第二級是基于本地磁盤的緩存祟印,只有在本地緩存沒有命中時肴沫,才會訪問對象存儲。
如果進行單機模型訓練蕴忆,在首輪訓練時颤芬,訓練集或數(shù)據(jù)集通常不會命中緩存。但是從第二輪開始套鹅,在緩存資源充足的情況下站蝠,幾乎不需要訪問對象存儲,達到加速數(shù)據(jù) I/O 的效果卓鹿。
JuiceFS 讀寫緩存流程
我們之前進行了一項評測菱魔,比較了在訪問對象存儲時,使用緩存和不使用緩存這兩種方式對于訓練效率的影響减牺。評測結(jié)果表明豌习,這兩種方式的性能差別非常大。(點擊 此處拔疚,了解評測結(jié)果)
上圖展示了 JuiceFS 緩存讀寫的流程肥隆。最上面是應(yīng)用程序,它相當于是最初發(fā)起讀請求的起點應(yīng)用或訓練任務(wù)稚失。
當應(yīng)用程序發(fā)起讀請求后栋艳,請求會先進入左側(cè)的內(nèi)核空間,內(nèi)核會查看內(nèi)核頁緩存中是否有請求的數(shù)據(jù)句各。如果內(nèi)核頁緩存中沒有數(shù)據(jù)吸占,請求會回到用戶空間的 JuiceFS 進程晴叨。在用戶空間,JuiceFS 進程會處理所有的讀寫請求矾屯。
JuiceFS 默認會在內(nèi)存中維護一個讀緩沖區(qū)兼蕊,當請求未能從緩沖區(qū)中獲取數(shù)據(jù)時,JuiceFS 會進入塊緩存索引件蚕,即基于本地磁盤的緩存目錄孙技。JuiceFS 默認將文件切割成 4MB 的塊并存儲,因此緩存的粒度也是 4MB排作。
舉個例子牵啦,當訪問一個文件的一部分數(shù)據(jù)時,JuiceFS 只會緩存該部分數(shù)據(jù)對應(yīng)的 4MB 塊到本地緩存目錄中妄痪,而不會緩存整個文件哈雏。這是 JuiceFS 與其他文件系統(tǒng)或緩存系統(tǒng)的顯著差異之一。
Block cache index 用于快速定位本地緩存目錄中的文件塊衫生。如果找到了裳瘪,JuiceFS 進程會自動讀取本地盤,然后進入內(nèi)核態(tài)障簿,讀取完成后返回給 JuiceFS 進程盹愚,最后返回給應(yīng)用程序。
當本地盤數(shù)據(jù)讀取完成后站故,數(shù)據(jù)還會進入內(nèi)核頁緩存皆怕。這是因為如果沒有使用 direct I/O,Linux 系統(tǒng)默認會將數(shù)據(jù)存儲在內(nèi)核頁緩存中西篓。這些內(nèi)核頁緩存都用于加速緩存訪問愈腾,如果第一個請求直接命中并返回,那么效率是最高的岂津,并且請求不會通過 FUSE 層進入用戶態(tài)進程虱黄。如果沒有命中,則會通過 index 查找吮成,如果在節(jié)點目錄中沒有找到 block橱乱,則會通過網(wǎng)絡(luò)請求到達對象存儲,然后將數(shù)據(jù)讀回來并原路返回給應(yīng)用程序粱甫。
從對象存儲上下載數(shù)據(jù)時泳叠,JuiceFS 會有一個后臺異步線程,把讀回來的 block 同時寫到本地緩存盤里茶宵,確保下一次訪問同樣的 block 時危纫,能直接從本地緩存命中,而不需要再次從對象存儲上獲取。以上就是 JuiceFS 建立讀緩存的流程种蝶。
上圖有一部分的模塊叫 Chunk Cache契耿,chunk 是 JuiceFS 中的一個邏輯概念,每個文件會按照 64MB 大小分為多個 chunk螃征,來提升大文件的讀取性能搪桂。這部分信息會被緩存到 JuiceFS 進程的內(nèi)存里,來加速元數(shù)據(jù)訪問的效率盯滚。
與數(shù)據(jù)緩存不同锅棕,元數(shù)據(jù)緩存時間較短,并且為確保強一致性淌山,open 操作默認不緩存」苏埃考慮到元數(shù)據(jù)流量很小泼疑,所以對整體的 I/O 性能影響比較小,但是在大量小文件的場景荷荤,如果需要頻繁訪問小文件退渗,元數(shù)據(jù)的開銷也會占到一定的比重。
2.為什么訓練太慢以及如何排查蕴纳?
當使用 JuiceFS 進行訓練時会油,性能是最重要的考慮因素,它直接影響到模型訓練的速度古毛。以下是可能影響 JuiceFS 效率的幾個方面:
元數(shù)據(jù)引擎
在處理小文件時翻翩,選擇不同的元數(shù)據(jù)引擎(如 Redis、TiKV稻薇、MySQL)的性能差別很大。JuiceFS 官網(wǎng)提供了一份對比它們作為元數(shù)據(jù)引擎的性能文檔塞椎,平均來說 Redis 會比其他數(shù)據(jù)庫快 3~5 倍桨仿。如果發(fā)現(xiàn)元數(shù)據(jù)請求特別慢,建議嘗試使用一些性能更好的數(shù)據(jù)庫作為 JuiceFS 的元數(shù)據(jù)引擎案狠。
對象存儲
主要影響數(shù)據(jù)存儲訪問的性能和吞吐量服傍。如果在云上使用,通常使用公有云提供的對象存儲服務(wù)骂铁,其性能相對固定吹零。如果使用自建的對象存儲,例如使用開源的 Ceph 或 MinIO 組件从铲,可以對組件進行調(diào)優(yōu)以達到更好的性能和吞吐量瘪校。
本地磁盤
緩存目錄存儲的位置對整個讀取性能影響很大。在緩存命中率高的情況下,緩存磁盤的 I/O 效率會直接影響整體 I/O 效率阱扬。因此需要注意存儲類型泣懊、存儲介質(zhì)以及磁盤容量等因素,數(shù)據(jù)集的大小也會對訓練效率產(chǎn)生影響麻惶。
網(wǎng)絡(luò)帶寬
在第一輪訓練完成后馍刮,如果數(shù)據(jù)集不足以在本地完全緩存,網(wǎng)絡(luò)帶寬或網(wǎng)絡(luò)資源的消耗會影響整體數(shù)據(jù)訪問效率窃蹋。在云上卡啰,不同機型的網(wǎng)卡帶寬也有所不同,這也會對數(shù)據(jù)的訪問速度和效率產(chǎn)生影響警没。
內(nèi)存
內(nèi)存的大小會直接影響內(nèi)核頁緩存的大小匈辱。當內(nèi)存足夠大時,剩余的空閑內(nèi)存可以用作 JuiceFS 數(shù)據(jù)的緩存杀迹,進一步加快數(shù)據(jù)的訪問速度亡脸。但是,當剩余的空閑內(nèi)存較少時树酪,數(shù)據(jù)訪問需要通過本地磁盤獲取浅碾,這會導致訪問開銷變大。另外续语,內(nèi)核態(tài)和用戶態(tài)之間的切換會對性能造成影響垂谢,比如系統(tǒng)調(diào)用的上下文切換開銷等。
如何排查
JuiceFS 提供了許多工具和命令來幫助用戶更好地進行性能調(diào)優(yōu)和診斷疮茄。在去年的 Office Hours 中滥朱,已經(jīng)對如何在 JuiceFS 中進行性能調(diào)優(yōu)和診斷進行了全面介紹。如果感興趣力试,可以在 B 站上觀看視頻回放焚虱。以下是其中幾個方法的簡要介紹:
工具1 :juicefs profile 命令
它可以通過分析訪問日志來幫助用戶更好地優(yōu)化性能。每個文件系統(tǒng)掛載之后都會有訪問日志懂版,但訪問日志并不會實時保存鹃栽,只有在查看訪問日志時才會顯示出來。相比直接查看原始的訪問日志躯畴,juicefs profile 命令會進行信息的聚合和類似滑動窗口的數(shù)據(jù)統(tǒng)計民鼓,并按照響應(yīng)時間從高到低排序,幫助用戶優(yōu)先關(guān)注響應(yīng)時間較慢的請求蓬抄,進一步分析請求與元數(shù)據(jù)引擎或?qū)ο蟠鎯Φ年P(guān)系丰嘉。
工具2:juicefs stats 命令
它從更宏觀的角度收集監(jiān)控數(shù)據(jù),并實時展示出來嚷缭。它可以監(jiān)控當前掛載點的 CPU 占用饮亏、內(nèi)存占用耍贾、內(nèi)存中的緩沖區(qū)占用、FUSE 讀寫請求路幸、元數(shù)據(jù)請求以及對象存儲的延遲情況等荐开。這些細致的監(jiān)控指標可以方便用戶查看和分析當前模型訓練的瓶頸或性能問題出現(xiàn)的可能環(huán)節(jié)。
JuiceFS 還提供了更底層的信息分析工具简肴,包括 CPU profile 和 heap profile晃听。CPU profile 可以分析 JuiceFS 進程執(zhí)行速度的瓶頸所在,適用于熟悉源代碼的用戶砰识。而 heap profile 則主要用于分析內(nèi)存占用情況能扒,尤其是當 JuiceFS 進程占用大量內(nèi)存時,需要使用 heap profile 來確定具體哪些函數(shù)或數(shù)據(jù)結(jié)構(gòu)占用了較多內(nèi)存辫狼。
3.一些常見的優(yōu)化策略
元數(shù)據(jù)緩存優(yōu)化
元數(shù)據(jù)緩存的優(yōu)化方案主要分為兩類:
1)調(diào)整內(nèi)核元數(shù)據(jù)緩存的超時時間
可以使用 --attr-cache
初斑、--entry-cache
和 --dir-entry-cache
參數(shù),這三個參數(shù)分別對應(yīng)不同類型的元數(shù)據(jù):attr 表示文件屬性(如大小膨处、修改時間越平、訪問時間等),entry 是 Linux 中的概念灵迫,表示文件和相關(guān)屬性,dir-entry 表示目錄和其中包含的文件晦溪。
這些參數(shù)分別控制著元數(shù)據(jù)緩存的超時時間瀑粥。為了保證數(shù)據(jù)訪問的一致性,這些參數(shù)的默認值只有一秒鐘三圆,但在模型訓練的場景中狞换,原始數(shù)據(jù)通常不會被修改,因此可以將這些參數(shù)的超時時間設(shè)置得更長一些舟肉,比如幾天到一周等修噪。但需要注意的是,元數(shù)據(jù)緩存是無法主動失效的路媚,只能等待超時時間到期黄琼。
2)優(yōu)化 JuiceFS 客戶端的用戶態(tài)元數(shù)據(jù)緩存
默認情況下,在打開文件時會強制請求元數(shù)據(jù)引擎獲取最新的文件屬性整慎,以保證強一致性脏款。但由于模型訓練的數(shù)據(jù)通常不會被修改,因此可以打開 --open-cache
參數(shù)裤园,并設(shè)置一個超時時間撤师,以避免每次打開同一個文件都重復訪問元數(shù)據(jù)引擎。另外可以通過 --open-cache-limit
參數(shù)控制緩存的最大文件數(shù)拧揽,默認值是 10000剃盾,即最多緩存最近打開的 10000 個文件的元數(shù)據(jù)在內(nèi)存中腺占,可以根據(jù)數(shù)據(jù)集的文件個數(shù)進行適當調(diào)整。
數(shù)據(jù)緩存
JuiceFS 的數(shù)據(jù)緩存分為內(nèi)核頁緩存和本地數(shù)據(jù)緩存兩種痒谴,其中內(nèi)核頁緩存無法進行參數(shù)調(diào)優(yōu)衰伯。因此,在計算節(jié)點上應(yīng)該盡量保留足夠的空閑內(nèi)存闰歪,以便 JuiceFS 能夠充分利用嚎研。如果計算節(jié)點上的資源緊張, JuiceFS 就不會將數(shù)據(jù)緩存到內(nèi)核中库倘。
而本地數(shù)據(jù)緩存相對來說用戶更加可控临扮,可以根據(jù)具體場景調(diào)優(yōu)緩存參數(shù)。首先教翩,可以調(diào)整緩存的大懈擞隆( --cache-size
),默認值為 100G饱亿,對于大部分場景都足夠了蚜退。但是對于占用空間特別大的數(shù)據(jù)集,需要適當調(diào)整緩存大小彪笼,否則 100G 的緩存空間可能很快被寫滿钻注,導致 JuiceFS 無法緩存更多數(shù)據(jù)。配合 --cache-size 參數(shù)一起使用的另一個參數(shù)是 --free-space-ratio
配猫,這個參數(shù)用于控制緩存盤的空間空閑比例幅恋,默認值是 0.1,即最多使用 90% 的磁盤空間緩存數(shù)據(jù)泵肄。
JuiceFS還支持同時使用多個緩存盤捆交,推薦盡量使用所有可用的盤。數(shù)據(jù)會通過輪詢的方式均勻分布到多個盤中腐巢,從而實現(xiàn)負載均衡品追,同時最大化利用多塊盤的存儲優(yōu)勢。
緩存預熱
為了提高訓練效率冯丙,可以通過預熱緩存來加速訓練任務(wù)肉瓦。JuiceFS 支持預熱客戶端中的元數(shù)據(jù)緩存和本地數(shù)據(jù)緩存,通過使用 juicefs warmup 命令可以將緩存提前預熱到緩存盤胃惜,從而在訓練任務(wù)開始時直接命中緩存风宁,提高效率。
增大緩沖區(qū)大小
緩沖區(qū)的大小也會影響讀取性能蛹疯。默認情況下戒财,緩沖區(qū)大小為 300MB,但在高吞吐的訓練場景下捺弦,這可能不夠用饮寞⌒⒖福可以根據(jù)訓練節(jié)點的內(nèi)存資源情況來調(diào)整緩沖區(qū)大小,一般來說幽崩,緩沖區(qū)越大讀取性能越好苦始,但也不要設(shè)置過大的值(特別是在限制了最大內(nèi)存的容器環(huán)境中)。需要結(jié)合實際負載情況進行調(diào)優(yōu)慌申,找到一個相對合理的緩沖區(qū)大小陌选”廾可以參考前面介紹的 juicefs stats 命令實時觀測緩沖區(qū)的使用量期揪。
如有幫助的話歡迎關(guān)注我們項目 Juicedata/JuiceFS 喲寂呛! (0?0?)