1. 程式人生 > >基於Lustre檔案系統的MPI-IO程式設計介面改進

基於Lustre檔案系統的MPI-IO程式設計介面改進

摘  要: 針對傳統MPI叢集並行I/O效率不高的問題,通過分析Lustre並行檔案系統的特點和MPI-IO集中式I/O操作的演算法,提出了一種基於MPI-IO程式設計介面的改進方案,用以改善叢集I/O瓶頸,提高I/O並行效率,並通過實驗驗證了該方案的可行性。

關鍵詞:並行檔案系統; 程式設計介面; 集中式I/O; Lustre; MPI-IO
    為解決這一問題,通常的方法是在Lustre的上層加入一個並行I/O庫,通過該庫將多個不連續小資料塊的I/O操作轉化為對並行檔案系統中的少量連續大資料塊的實際I/O操作,最大程度地利用並行檔案系統所提供的頻寬,減少I/O瓶頸對程式效能的影響,在庫的級別上優化並行I/O的訪問效率。本文提出了一種基於MPI-IO庫(並行I/O庫)程式設計介面的改進方案,以保證在小資料整合為大資料的過程中進一步減少程序間的通訊量和時間消耗,從而提升叢集並行效率,為傳統MPI叢集的升級改造提供新的思路或新的方法。

1 Lustre檔案系統性能介紹

    Lustre是面向叢集的儲存架構,是基於Linux平臺的開源叢集(並行)檔案系統。由於其提供了與POSIX相容的檔案系統介面,從而使其擴充套件了應用領域。Lustre擁有高效能和高擴充套件性兩個最大特徵。高效能是指它能夠支援數萬客戶端系統、PB級儲存容量和數百GB的聚合I/O吞吐量;高擴充套件性是指由於Lustre是Scale-Out儲存架構,由此可以藉助強大的橫向擴充套件能力,只要以增加伺服器的方式便可擴充套件系統總儲存容量和系統總效能。
     Lustre檔案系統主要由元資料伺服器MDS(Metadata Server)、物件儲存伺服器OSS(Object Storage Server)、客戶端(Lustre Client)三部分組成。MDS用於儲存資料描述資訊,管理名稱空間和目標儲存地址;OSS進行實際的資料儲存,提供檔案I/O服務;Lustre Client則執行Lustre檔案系統,並作為叢集計算端與MDS和OSS進行資訊互動[2]。如圖1所示。

    因此Lustre叢集及其並行架構非常適合眾多客戶端併發進行大資料讀寫的場合,但對於不連續小資料的應用是不適合的,尤其是海量小檔案應用LOSF(LotsOf Small Files)。

2 MPI-IO對並行I/O的實現

    MPI-IO是一個並行I/O庫,作為 MPI-2 規範的一部分,提供了執行可移植的、使用者級的I/O 操作介面。MPI可以通過該介面在檔案和程序間傳送資料,如圖2所示。ROMIO是MPI-IO的一個具體實現,而ADIO是位於並行檔案系統和上層I/O庫ROMIO之間的軟體層,它的作用是使得上層並行I/O庫的實現具有更好的移植性和更好的I/O訪問效率。由於ADIO可以在不同的並行檔案系統上實現,提供了一組最基本的並行I/O訪問的函式,所以I/O庫只需要在ADIO上實現一次,就可以通過ADIO實現對所有底層檔案系統的訪問。一些特定的並行檔案系統的優化通常也在ADIO層上實現,所以ADIO的實現使得上層庫可以透明訪問底層並行檔案系統,而不必考慮底層並行檔案系統方面的細節。正基於此,本文所提出的改進策略也是在ADIO上實現的[3]。

    非集中式I/O操作,是MPI-IO的普通I/O操作方式。在此操作下,若每個程序訪問檔案中存放位置不連續的小片資料時,往往是對每一個小片連續的資料使用單個獨立函式來讀寫資料,就像在Unix或Linux中一樣,所以這種方法I/O延遲較大,系統開銷也較大。但對於連續大資料的讀寫,此種方式可以利用作業系統快取和Lustre資料分片等技術,充分發揮並行I/O的優勢。
    而對於集中式I/O操作,由於集中式I/O具有並行程式的對稱性,當I/O發生時叢集中所有節點均執行到各自子程序的相同位置,所以各子程序會在一個很短的時間間隔內各自發出I/O 請求,集中式I/O便合併這些小的讀寫請求,使之整合成為大的讀寫請求,從而減少磁碟磁頭移動和I/O次數,提高I/O讀寫速度。本文的改進型程式設計介面也正是基於此類I/O方式將多個不連續的小資料I/O整合為少量的大資料I/O,進而再利用底層的Lustre並行檔案系統對大資料I/O的優勢,使得叢集的整體並行效率得到提升。集中式I/O有很多實現方案,ROMIO是採用基於Client-level的兩階段法來實現集中式I/O的。
    兩階段法通過分析集中式I/O請求對資料的總體需求,將一次I/O操作分成兩個階段來完成。第一個階段是所有計算程序交換彼此I/O資訊,確定每個程序的檔案域,從磁碟上讀取相應I/O資料;第二個階段是按照應用需求將緩衝區的資料交換分配到各程序的使用者緩衝區,寫操作與讀操作類似。在這兩個階段中,程序之間需要進行相互通訊,同步同一通訊域中的相關程序的資料資訊,從而得到程式總體的I/O行為資訊,以便整合各個程序獨立的I/O請求。如圖3所示。
       (1) 確定參加讀操作的通訊域中所有程序,並進行同步;
       (2) 確定每個程序各自需要讀取的一個包含所請求資料的連續的檔案區域;
       (3) 每個程序根據自己的檔案區域進行I/O訪問,並將這些資料存放在一個臨時緩衝中,同步所有程序到每個程序的I/O操作結束。
      第二階段:
      (1) 進行I/O資料的置換,將快取中資料傳送給目標程序;
      (2) 同步所有程序到資料置換結束。
    寫操作類似於讀操作。兩階段I/O整合了多個程序所請求的資料範圍,訪問到稠密的資料區域的可能性比較大,因此對於非連續資料分佈比較分散情況,該演算法有明顯的效能優勢。但是,兩階段I/O的效能很大程度上依賴於MPI所提供的高效的資料傳遞機制,即訊息傳遞機制。如果MPI無法提供比底層檔案的聚合頻寬更快的速度,那麼在兩階段I/O中資料傳遞所帶來的額外開銷將會大大降低該I/O方式的效能[4]。

3 改進的並行I/O程式設計介面

    從上述分析可知,MPI-IO在整個集群系統中起到了承上啟下的作用,向上連線MPI計算系統,向下連線Lustre並行檔案系統,所以其效率的高低一直影響到叢集的整體並行I/O效率。為此,本文所提方案需要對以下三個方面進行改進。
    (1) 如何界定資料塊的大小
    在Linux 32 bit的作業系統中,一個頁面大小為4 KB,同時也是Lustre網路傳輸的基本單位。由參考文獻[4]可知,當資料大小不到一頁或不同程序同時讀寫一個頁面中資料的時候,Lustre的I/O效能最差,甚至不如傳統的本地檔案系統;若資料塊的大小不足一個條塊(資料分片),則客戶端每次讀寫只與一個OST互動資訊,沒有從真正意義上實現Lustre併發I/O的功能。
    所以如何界定資料塊的大小,是提高系統並行效率的關鍵。本文依據參考文獻[4]所提供的實驗資料,設定Lustre條塊大小為64 KB,若資料塊小於該值,則視為小資料,按本文改進的集中式MPI-IO程式設計介面操作;若資料塊大於該值,則視為大資料,按非集中式MPI-IO介面操作。
    (2) 採用直接I/O模式以減少核心消耗
    Lustre檔案系統底層採用Portals協議進行資料傳輸,上層則連線Linux作業系統的VFS(虛擬檔案系統)。應用程式所有的I/O操作都必須通過Linux的VFS才能進入Lustre。在Linux作業系統中,讀寫模式分為檔案快取(Cache)模式和直接(Direct)模式。
    對於Lustre檔案系統而言,由於該檔案系統是以頁面為I/O的基本單位,所以當n個程序去讀取僅需一個頁面的資料流量時,若採用快取機制,則實際系統需要n個頁面的I/O流量才可完成,而隨著I/O請求的增加,這種額外的開銷將會越來越大;而對於寫操作,快取機制在小資料I/O的問題則更加突出。在寫操作時,由於每個程序必須獲得該頁面上的檔案鎖才能進行,以保證對這個檔案寫操作的獨佔性。但是當一個程序獲得鎖後,其他程序只有等待該程序結束操作,所以對於同一個頁面的寫操作是序列的,系統不能發揮程式的並行作用而造成效能下降。並且,當資料塊小於4 KB時(不足一個頁面),檔案快取的作用已經不明顯,反而使得I/O呼叫的開銷越來越突出。因此, Lustre在非連續小資料I/O時,採用可以繞過系統快取的直接I/O方式,直接將檔案資料傳遞到程序的記憶體空間則是一個可行的辦法。
    (3) 減少集中式I/O第一階段的通訊量
    由前述可知,MPI-IO中的集中式I/O操作是採用兩階段法來進行的。該演算法第一階段,通訊域中所有程序同步操作方式採用廣播的形式,即每個程序的資料資訊通過廣播的方式傳送給通訊域裡的所有程序。也就是說,若有n個程序參與此次集中I/O操作,則整個過程中程序間需要n×(n-1)次點對點通訊才能完成。這樣,隨著叢集節點數的增加, 程序間的通訊次數勢必會給I/O效能造成較大影響。所以,本文的優化方案就是以減少程序間的通訊量為目的,儘量減少程序間的通訊次數,以提高整體的I/O效能。這裡,選取通訊域中的一個程序作為主程序,通過它從其他程序收集各自的I/O資訊進行相關的計算,並彙總整合本通訊域中的所有I/O資訊,再將其進行廣播,以達到程序間I/O資訊同步的目的。若還是n個程序參與此次集中式I/O操作,則程序間的點到點通訊次數將會降到2×(n-1)次。顯然,改進後的策略可以明顯降低程序之間的通訊次數,進而提高了整個集中操作的I/O效能。

4 實驗與分析

    為驗證改進方案的可行性,在傳統的MPI叢集上做了相應的測試。測試環境為7個節點的集群系統(3臺OST,3臺客戶端,1臺MDS),每個節點包含一顆PIV處理器和2 GB記憶體,40 GB的硬碟,作業系統採用Redhat Linux Enterprise 5(核心為2.6.18),並行叢集軟體為MPICH2.1,並行檔案系統為Lustre 1.0.2。在測試程式中,在3個客戶端上同時執行3個程序讀寫一個檔案的不同部分,測試檔案為2 GB,其他的什麼都不做,來測試改進前後的I/O 讀寫頻寬(改進前的讀寫方式為Lustre系統的普通讀寫方式)。
    如圖4所示,先分析改進前Lustre系統的讀寫情況:資料塊為64 KB時,由於大部分RPC資料包中都包含了數十個頁,從而減少了I/O呼叫的次數,效率達到最高;而當資料塊小於64 KB(一個分片的大小)時,此時客戶端每次讀寫只能與一個OST互動資訊,從而無法使用Lustre分片技術的併發功能,造成這一階段讀寫效能不佳;而當資料塊大小為4 KB或者小於4 KB時,效能則快速下降,特別是寫操作,效能下降得更為嚴重,這主要是因為資料塊的大小不足1個頁面(4 KB),此時大部分的RPC資料包僅僅包含1個頁面而導致I/O效率不高,特別是在不同程序同時讀寫一個頁面中的資料的時候,則效能更糟。

    近年來,Lustre作為一個開源的高效能分散式叢集檔案系統,以其PB級的共享儲存容量和上百吉位元組每秒的聚合 I/O頻寬被廣泛應用於HPC領域。有資料[1]表明Lustre在HPC領域佔有最大的市場份額,已成為構建HPC叢集的事實上的標準。將Lustre引入到傳統的MPI叢集解決I/O瓶頸,可提升平行計算速度。但是簡單地將Lustre移植到MPI叢集中並不能獲得預期的效果。其主要原因是,執行MPI的並行程式需要進行大量的I/O訪問,而在這些I/O訪問中基於小資料(細粒度)的I/O訪問往往佔據著相當大的比率,雖然Lustre能在連續大資料(粗粒度)傳輸上達到很高的I/O頻寬,但在不連續小資料傳輸上並沒有獲得顯著的效能提升。當大量小資料I/O頻繁訪問時,就會使該檔案系統的整體效能迅速下降,以至實際I/O頻寬遠低於所提供的最大頻寬。

     由於Lustre設計的初衷是要提高資料訪問的並行性和擴充套件聚合I/O頻寬,所以在設計過程中廣泛採用了元資料與資料分離、資料分片策略、資料快取和LNET網路等技術。而在這些設計中,資料分片設計和後端改進的EXT3檔案系統非常適合大資料連續I/O訪問,所以Lustre在大資料應用中其效能表現得非常好。但對於不連續小資料I/O而言,由於Lustre在讀寫檔案前需要與MDS進行互動,以獲得相關的屬性和物件位置資訊,從而增加了一次額外的網路傳輸和元資料訪問的開銷(與傳統本地檔案系統相比)。若有大量頻繁的小資料讀寫時,Lustre客戶端上Cache的作用將失效,其命中率也會大大降低。如果資料小於物理頁大小,則還會產生額外的網路通訊量,小資料訪問越頻繁,則網路開銷也就越大,進而影響Lustrer的總體I/O效能。OST(物件儲存目標伺服器)後端雖然採用了改進的EXT3檔案系統,但它對小資料的讀寫效能存在先天的缺陷,其元資料訪問效率也不高,且磁碟定址延遲和磁碟碎片問題嚴重。所以,Lustre的設計決定了它對小資料I/O的表現,其實際I/O頻寬遠低於所提供的最大頻寬。

    MPI-IO可分為非集中式(noncollectiveI/O)和集中式(collective I/O)兩種I/O操作。

       第一階段: