李 云,張海明
1(中國科學院 計算機網絡信息中心,北京 100190)
2(中國科學院大學,北京 100049)
隨著大數據時代的到來,分布式文件系統因其良好的拓展性、支持大規模存儲而備受關注.很多優秀的分布式文件系統也隨之出現,例如谷歌的GFS[1]、Facebook 優化過的HDFS[2]、阿里的TFS[3]以及開源社區的明星項目CephFS[4]、GlusterFS[5].這些分布式文件系統在實際使用過程中在拓展性、存儲規模方面都表現得十分出色.但是,在面向用戶提供數據服務時相比于普通的文件系統缺少了靈活性,普通的文件系統可以通過直接搭建FTP 服務來為用戶提供數據服務,方便用戶上傳下載數據,而分布式文件系統由于其自身的局限性,無法直接提供類似的服務.因此,就分布式文件系統如何面向用戶提供高效的數據服務,本文提出基于FTP 協議的解決方案——SPDScheme.
分布式文件系統向外提供數據服務接口,但是這些接口對于用戶并不友好.需要由研發人員將這些接口進行封裝,使之成為方便用戶使用的方式.在工業領域,目前常用的方案是將分布式文件系統掛載到普通文件系統上,通過在普通文件系統搭建FTP 服務端來向外提供服務,這種方案的優勢在于快速搭建,但是劣勢也十分明顯,無法對分布式文件系統的特點以及用戶服務做出有針對性的調整.SPDScheme 主要設計了一個基于FTP 協議的獨立服務SPDServer,作用于用戶和分布式文件系統之間,根據分布式文件系統的高IO、高吞吐量等特點進行優化,同時根據一些用戶需求進行針對性的調整.另外通過使用一些開源技術保證服務的高可用、高并發以及可拓展性.因此,本文提出的SPDScheme 具有如下幾方面的技術優勢.
1)利用生成器、協程、多線程、緩沖區等技術,針對分布式文件系統的特性設計優化數據傳輸的模型和算法,極大的提高了數據服務的傳輸效率.
2)SPDServer 獨立于分布式文件系統,與分布式文件系統耦合程度很低,服務掛掉不會對分布式文件系統產生任何的影響.由于利用Keepalived[6]和LVS[7]實現高可用,一臺機器的服務出現問題,也不會對用戶服務產生任何影響.
3)利用LVS 對請求做負載均衡,實現用戶請求的高并發,同時也使服務具備了非常好的拓展性,可以隨著用戶請求的增加,相應的增加服務節點,提高服務的響應速度以及傳輸速度.
4)FTP 協議的認證方式是在服務啟動時將明文密碼配置到服務中,使用過程非常不靈活,而本文提出的SPDServer 通過連接MySQL 數據庫,將用戶登錄信息和權限信息保存到數據庫中,實現動態認證.同時利用編碼探測技術,分析請求中內容的編碼格式,做到多種編碼格式的兼容,以及針對用戶體驗做出的其它一些調整,對用戶十分友好.
SPDScheme 是一個面向用戶,針對分布式文件系統的數據服務解決方案,整體為C/S 架構,其中核心服務SPDServer 作用于用戶和分布式文件系統之間,是一個相對獨立的服務,旨在為用戶提供簡單、方便、快捷、安全的數據服務,主要由用戶認證、文件操作、模式選擇、編碼兼容和日志收集等模塊構成;另外通過Keepalived+LVS 實現服務的高可用和高并發.方案架構如圖1所示.

圖1 方案總體架構
FTP 協議建立在客戶端-服務器端模型體系結構之上[8],在客戶端和服務器端之間使用單獨的控制和數據連接.使用FTP 協議進行數據傳輸,需要有FTP 客戶端軟件和FTP 服務端的軟件配合使用.優秀的客戶端軟件有很多,例如Flashfxp[9]、Filezilla[10]、Xftp[11]等,用戶可以選擇其中任意一款作為客戶端使用.FTP 服務端工具同樣層出不窮,例如Vsftpd[12]、Pyftpdlib[13]、Proftpd[14]、Twisted[15]等,這些服務端軟件都有著非常好的性能表現,但是不能直接使用在分布式文件系統上,原因在于這些服務端軟件都只能對接操作系統下的文件系統.若要使得FTP 服務端能夠對接到分布式文件系統,可以在現有的服務端軟件之上進行傳輸算法、傳輸模型以及部分功能的重構,會減少大量沒有必要的重復研發,因此SPDServer 底層框架的選擇非常關鍵.通過對幾款常用服務端軟件測試對比如圖2.

圖2 多種FTP 軟件性能比較
從測試數據中可以清楚地了解到,Pyftpdlib 在上傳、下載速度以及多客戶端的連接和斷開所用時間上都表現十分優異,因此選取Pyftpdlib 軟件作為SPDServer 的底層框架.
SPDScheme 使用Keepalived 實現服務的高可用,使用LVS 進行負載均衡,實現服務的高并發,并保證服務可以橫向拓展,在用戶請求增加時,可以通過增加服務節點的數量來增大并發量.Keepalived 的優勢在于通過簡單的配置就可以實現高可用,使用靈活.LVS 的優勢在于極強的負載均衡性能,只分發請求,不會有流量經過的特點,保證了均衡器的IO 性能不會受到大規模流量的影響.同時由于其工作在網絡的傳輸層,上層應用協議支持廣泛,FTP 協議可以很好的在LVS 上層工作.
在Pyftpdlib 底層框架的基礎上,SPDServer 利用緩沖區[16]、生成器[17]、協程[18]、多線程[19]等技術,針對分布式文件系統的特點進行了數據傳輸算法和傳輸模型的優化.在用戶認證、文件操作、模式選擇、編碼兼容和日志收集方面設計了全新的管理策略.
對于評價數據服務的性能,上傳文件和下載文件速度是一項重要指標.上傳文件時數據流的傳輸過程是客戶端將文件分片發送到SPDServer,SPDserver 收到分片的數據再發送到分布式文件系統,下載文件的過程與之相反.但是這個過程中,存在著容易被忽視的問題,客戶端的讀寫能力和吞吐量相比于分布式文件系統要小的多,如果SPDServer 只是簡單的接收數據片再發送到分布式文件系統,就會導致部分資源閑置以及沒有必要的網絡開銷.而SPDServer 能夠進行高速的數據傳輸,原因在于使用基于生成器的協議技術、緩沖區技術以及多線程技術用來解決上述存在的問題.同時,整個數據流的傳輸過程,可以抽象成為生產者-消費者模型,可以把SPDServer 抽象成為中間存放商品的倉庫,使用生產者-消費者模型的思想對其進行優化.
利用生成器特性加快傳輸速度.利用生成器,本質是一種協程的思想.若不使用生成器,由于文件數據是分片讀取或者寫入,每次讀取或者寫入都要讀取該文件對應的元數據信息,但多次查詢元數據信息,極大的耗費了傳輸時間.利用生成器,就可以保存查詢到的元數據在生成器上下文當中,在上傳文件時,通過文件操作可以返回一個生成器句柄,每次向生成器寫入數據即可;在下載文件時,同樣返回一個生成器句柄,每次從生成器讀出數據即可.
SPDServer 使用生成器避免了大量的元數據查詢,在處理每個上傳下載任務后可以快速恢復到服務主程序,極大地提高了傳輸速度.具體算法步驟如算法1.

算法1.基于協程思想的上傳算法1.Def Generator:2.Metadata ← getMetadata()3.While DATA_PIECE:4.DATA_PIECE ← yield 5.Write(Metadata,DATAPIECE)6.Def Upload:7.Generator ← getGenerator()8.While GET_DATA_PIECE():// 接收數據片9.Generator.send(DATA_PIECE)10.Generator.close()
在協程思想的基礎上利用緩沖區加快傳輸速度.文件是分片進行傳輸的,每一片的大小會有一個具體的值.在上傳文件時,如果數據片的大小被設置的很小,數據就會被分為更多的片,在向存儲后端發送數據時,每次寫入都會有時間開銷,次數越多,耗費的時間也會越多.如果數據片的大小被設置的很大,單次寫入的數據越大,一個數據片耗費的時間也會越多,次數雖然變小了,但是總的時間開銷依然很大.于是數據片過大和過小都會造成時間上不必要的耗費,因此這里需要一個經驗值讓傳輸速度達到最佳狀態,SPDServer 采用這樣的設計:在內存中開辟一片緩沖區,按數據片的順序暫存在緩沖區,當緩沖區中數據的大小等于這個經驗值時,就可以將緩沖區中的內容一起通過生成器發送到分布式文件系統中.
以字符串拼接的方案作為對比,可以更好地理解緩沖區的作用.對分片的數據進行拼接,需要多次的賦值操作,本質是對內存的反復申請釋放,產生大量的時間開銷.而對于緩沖區來說,只需要每次按順序將數據片放入緩沖區,這樣可以極大地節省反復申請內存的時間.具體算法步驟如算法2.

算法2.基于緩沖區的上傳算法1.Def createBuffer:2.Buffer ← SYSTEM_CALL()3.return Buffer 4.Def Upload:5.Generator ← getGenerator()6.Buffer ← createBuffer()7.While GET_DATA_PIECE():// 接收數據片8.if sizeof(Buffer)<BUFFER_SIZE:9.Write(Buffer,DATA_PIECE)10.else:11.Generator.send(Buffer)12.Empty(Buffer)

13.Generator.send(Buffer)14.Generator.close()15.Buffer.close()?
在協程和緩沖區技術的基礎上,再使用多線程技術加速傳輸效率.多線程和多進程是指對任務進行異步處理,可以加快任務的處理效率.任務從使用資源情況看可以分為兩種,一種是I/O 密集型任務,即占用大量的I/O 資源,另一種是計算密集型任務,即占用大量的CPU 資源.多進程的優點在于每個進程相互獨立,但是占用內存多,創建、銷毀、切換進程效率低,比較適合大量計算的計算密集型任務,不用多次切換或創建銷毀.而多線程占用內存少,切換簡單.適合需要快速切換、創建銷毀的I/O 密集型任務,對于基于FTP協議的數據服務來說,并沒有復雜的計算過程,有的只是密集的請求和讀寫過程,是I/O 密集型任務.于是SPDServer 采用多線程的方式處理各種客戶端請求.
多線程的使用,相比于單個線程的處理能力,性能提升明顯;相比于多進程,在提高對客戶端請求的處理能力的同時,沒有增加更多的時間開銷和內存開銷,進一步提高了數據服務服務的響應速度.具體算法步驟如算法3.

算法3.基于多線程的上傳算法1.Def Work(Generator,Buffer):2.Generator.send(Buffer)3.return ok 4.Def Upload:5.Ex ← ThreadingPool(size)6.Generator ← getGenerator()7.Buffer ← createBuffer()8.While GET_DATA_PIECE():// 接收數據片9.if sizeof(Buffer)<BUFFER_SIZE:10.Write(Buffer,DATA_PIECE)11.else:12.Ex.submit(Work,Generator,Buffer)13.Empty(Buffer)14.Ex.submit(Work,Generator,Buffer)15.WAIT_COMPLETED(Ex)16.Generator.close()17.Buffer.close()18.Ex.close()
Pyftpdlib 原本的認證模塊是在啟動服務時,傳入用戶名、口令以及對應的操作權限,在用戶登錄時進行對比認證,但是服務一旦啟動,這些信息無法被修改,若要修改認證信息,必須重啟服務[20].由于面向用戶服務時,用戶端登錄信息以及權限信息是動態變化的,無法將所有用戶的數據在FTP 服務啟動時讀入.線上的數據服務,也不可能經常性的重新啟動.因此,登錄過程需要重新設計為動態認證,即拿到用戶的登錄數據后需要和一個可以動態更新的用戶數據表進行比對認證.
SPDServer 使用MySQL 數據庫存儲用戶信息,同時基于該數據庫向用戶提供Web 服務,用戶通過Web端可以在任意時間修改數據庫中的信息,SPDServer 每次處理認證請求時都會檢查該數據庫中的認證和權限信息,實現動態認證的效果.另外,數據庫中指定了用戶的訪問路徑,做到用戶與用戶之間隔離,底層存儲互不影響.為了區分用戶的讀寫權限,SPDServer 采用一個用戶名對應兩個口令的方式,兩個口令分別對應只讀權限和讀寫權限.在認證通過之后返回權限信息,用于檢查用戶的每個請求是否有足夠的權限,并予以正確響應.
Pyftpdlib 原本的文件操作模塊包括各種文件系統操作函數,這些函數需要全部對接到分布式文件系統,才能夠進行文件傳輸,SPDServer 對這些文件操作進行了功能的重構,最核心的部分如表1.

表1 功能重構的文件操作函數
FTP 協議中的服務模式分為主動模式和被動模式,主動和被動都是針對服務端而言,FTP 協議在進行數據傳輸時,客戶端和服務端會建立兩個連接,一個是控制連接,另一個是數據連接[21].無論是主動模式還是被動模式,服務端建立控制連接所用的都是21 端口,但是在建立數據連接時,服務端會根據請求模式的不同,采取不同的連接方式.主動模式下,服務端使用20 端口主動連接客戶端的高端端口,但是客戶端多為內網用戶,在防火墻之后,防火墻會屏蔽掉服務器發過來的主動連接請求.被動模式下,服務端會隨機打開一個高端端口,被動等待客戶端發過來的連接請求,但是FTP服務需要開放到公網,服務器的端口為了避免受到攻擊不能任意開放.兩種連接方式都有著不能忽略的弊端,SPDServer 采用了折中的辦法,即指定被動模式下用于建立連接的高端端口區間.固定的區間,降低了受到攻擊的風險,也避免了一部分客戶端在防火墻之后不能建立連接,保證了數據服務的穩定.
Windows 系統默認編碼為GBK,而Pyftpdlib 底層框架默認編碼為UTF8,Windows 用戶在訪問服務時,客戶端發送請求為GBK 編碼格式,而服務端處理請求時,會使用默認的UTF8 編碼格式進行解碼,兩者屬于完全不同的編碼類型,于是產生了亂碼問題.如果只是將SPDServer 的默認編碼修改為GBK 編碼,那么當Linux 系統上的客戶端訪問時,同樣會出現亂碼問題,因為Linux 默認編碼是UTF8.因此,選取一種編碼格式作為默認編碼,并不能夠解決多平臺兼容問題.SPDServer提出通過智能檢測技術來處理編碼問題的方法.
Chardet[22]是一個非常優秀的字符編碼識別方法庫,SPDServer 使用Chardet 工具對接收到的請求編碼進行智能判斷,準確地獲取接收到請求的編碼類型,有針對性的對接收到的請求進行解碼.同時,在響應該請求時也使用相同的編碼對客戶端進行反饋.因此,SPDServer 可以處理任意編碼的請求,有著十分強大的編碼兼容能力,能夠避免使用不同操作系統導致的編碼問題.
日志是服務運行時不可缺少的部分,好的日志策略可以保證系統的平穩運行,在出現問題時,迅速準確地定位到系統問題所在[23].SPDServer 擁有單獨的日志管理模塊,該管理模塊支持兩種輸出,一種是標準輸出到屏幕,另外一種是輸出到文本;線下測試使用輸出到屏幕,方便研發調試,線上運行環境輸出到文本,方便大量存儲、記錄用戶的行為并追蹤定位問題.另外,線上環境的日志輸出到文本,以文本的大小為單位,當文本的大小達到設定值時,文本自動分割打包,新產生的日志繼續寫入到空的文本中.當文本的大小又達到設定值時,繼續自動分割打包,依次類推.這樣可以留存長時間的日志記錄,避免了日志寫入單一文件,導致文件過大不好處理,又可以保證日志的時限.
一個方案的實際運行效果,必須在實際項目中使用,這樣才能夠全面、準確的了解.中國科技云iHarbor存儲系統是一個帶有文件目錄樹的分布式對象存儲系統,本質上可以作為一個分布式文件系統使用.iHarbor使用了本文提出的方案SPDScheme.本文對iHarbor存儲系統的數據服務進行了兼容性測試、性能測試、穩定性測試以及并發拓展測試.測試結果表明,單個數據傳輸連接可以達到200 MB/s 的傳輸速度,在兼容性、穩定性、可拓展性等方面,均表現優秀.具體測試數據過程詳見下文.
測試所用的客戶端與iHarbor 數據服務在同一網段內,均為萬兆光纖網絡,可以避免網絡帶寬不足造成的瓶頸,并測試出數據服務實際性能的上限.存儲設備方面,客戶端和iHarbor 底層存儲均使用普通機械硬盤.另外,在性能測試環節,SPDServer 部署在單個節點上,測試數據基于單個SPDServer.測試使用的SPDServer配置均為8 核CPU,8 GB 內存.在LVS 支持的范圍內,每增加一個新的SPDServer 節點,就會增加和測試SPDServer 節點同樣的處理能力,損耗可忽略不計.
表2是FTP 客戶端兼容性測試結果,測試方法是在不同的操作系統平臺上,使用多種不同的客戶端工具,訪問中國科技云iHarbor 存儲系統數據服務,查看服務是否可以正常響應.測試使用的客戶端幾乎包含了各大平臺當前常用的客戶端工具.測試結果表明數據服務在客戶端的兼容性方面考慮地比較全面,可以支持主流的FTP 客戶端工具.

表2 FTP 客戶端兼容性測試
性能與穩定性的測試用例主要考慮到客戶端個數、文件個數、單個文件大小等因素.
測試在不同并發客戶端數下,一小時可以上傳或者下載的小文件數量,用于測試的小文件的大小都在幾個字節左右.客戶端的數量從1 個到50 個.測得的結果如圖3,橫坐標表示并發客戶端數,縱坐標表示用時1 分鐘可以上傳或者下載的小文件數目.

圖3 測試小文件上傳下載情況
數據統計了多個客戶端傳輸過程中的文件累計傳輸數量.可以看到,隨著客戶端并發數的增大,并沒有過多的影響到數據服務的性能.同時,沒有出現明顯的波動情況,驗證了數據服務的穩定性.在單客戶端下,可以在1 分鐘內上傳600 個以上的小文件;在50 個客戶端同時上傳的情況下,也能達到將近6000 個小文件,效率很高.
測試在不同并發客戶端數下,上傳或者下載單個10 GB大文件用時.測試結果如圖4,橫坐標表示并發客戶端數,縱坐標表示上傳或者下載單個10 GB 大文件的用時.
數據統計了在多個客戶端傳輸大文件過程中的最長用時,最短用時,平均用時.可以看到,隨著客戶端的增多,數據服務的效率稍有下降,但是總的來看服務依舊是高效、穩定的.
對iHarbor 數據服務的高可用和并發測試情況如下.在服務運行時,人為停掉一個LVS 節點和一個SPDServer 服務,數據服務不受任何影響.
用并發測試軟件JMeter 對啟動單個SPDServer 的數據服務進行并發測試.在1 s 內并發下載100 KB 的文件,可以保證420 個連接的高效服務,吞吐率保持在36 req/s.受硬件資源限制,本次實驗測試的最大規模為10 個節點.并且在LVS 支持的范圍內,每增加一個新的SPDServer 節點,就會增加和測試SPDServer 節點相同的處理能力,損耗可忽略不計,可以通過增加節點的方法,增大并發量.

圖4 測試大文件上傳下載情況
隨著存儲技術的不斷發展,越來越多的應用需要建立在方便、快捷的數據服務之上.同時,越來越多的需求也在被用戶提出來,這些需求對存儲環境的拓展性、易用性和可靠性提出了更高要求.本文提出的解決方案經過運行在真實系統上,有效性、可靠性、高效性得到驗證,能夠為用戶提供優質的數據服務.
接下來將繼續研究數據傳輸模型以及算法中的瓶頸,以及SPDServer 中各個模塊的解耦,如何根據用戶需求在拓展功能時更加的方便靈活.同時希望本文提出的解決方案SPDScheme 可以應用到更多的存儲系統架構中.