董 聰,張 曉,程文迪,石 佳
(1.西北工業(yè)大學(xué)軟件學(xué)院,西安 710129;2.大數(shù)據(jù)存儲(chǔ)與管理工業(yè)和信息化部重點(diǎn)實(shí)驗(yàn)室(西北工業(yè)大學(xué)),西安 710129;3.西北工業(yè)大學(xué)計(jì)算機(jī)學(xué)院,西安 710129)
(?通信作者電子郵箱zhangxiao@nwpu.edu.cn)
伴隨著信息化時(shí)代的到來(lái),單機(jī)的存儲(chǔ)與處理已經(jīng)無(wú)法適應(yīng)實(shí)際應(yīng)用產(chǎn)生的巨大數(shù)據(jù)量,因此分布式文件系統(tǒng)的推行成為大數(shù)據(jù)發(fā)展的關(guān)注熱點(diǎn)。隨著Hadoop 生態(tài)圈的發(fā)展,Hadoop 分布式文件系統(tǒng)(Hadoop Distributed File System,HDFS)這個(gè)旨在解決大數(shù)據(jù)分布式存儲(chǔ)問(wèn)題的分布式文件存儲(chǔ)系統(tǒng)在各行各業(yè)的大數(shù)據(jù)系統(tǒng)中得到了較為廣泛的應(yīng)用[1]。作為海量數(shù)據(jù)的存儲(chǔ)底層平臺(tái),HDFS 存儲(chǔ)了海量的結(jié)構(gòu)化和非結(jié)構(gòu)化數(shù)據(jù),支撐著復(fù)雜查詢分析、交互式分析、詳單查詢、Key-Value讀寫(xiě)以及迭代計(jì)算等豐富的應(yīng)用場(chǎng)景[2]。
由于上層應(yīng)用需要向HDFS 寫(xiě)入或者讀取數(shù)據(jù),HDFS 的性能將會(huì)影響其上層所有大數(shù)據(jù)的應(yīng)用和系統(tǒng),因此HDFS性能的優(yōu)化至關(guān)重要。在HDFS 性能優(yōu)化時(shí),既要保持其通用的訪問(wèn)接口和穩(wěn)定的性能,也要保證高可用性和高可擴(kuò)展性等其他特性。針對(duì)在大數(shù)據(jù)背景分析下對(duì)HDFS 的存儲(chǔ)和優(yōu)化,文獻(xiàn)[3]提出了一種異構(gòu)感知的分層存儲(chǔ)——hatS,它將固態(tài)硬盤(pán)作為磁盤(pán)的上層存儲(chǔ),把數(shù)據(jù)副本存儲(chǔ)到不同的層級(jí)中。此時(shí)文件先在固態(tài)驅(qū)動(dòng)器(Solid State Disk,SSD)中存儲(chǔ),再?gòu)?fù)制到磁盤(pán)中,讀取時(shí)優(yōu)先從最上層讀取。這種放置策略雖然提高了數(shù)據(jù)寫(xiě)入的性能,但會(huì)造成數(shù)據(jù)訪問(wèn)的不均衡。文獻(xiàn)[4]提出了一種根據(jù)數(shù)據(jù)冷熱程度來(lái)訪問(wèn)HDFS 的優(yōu)化方案。該系統(tǒng)可以遵循一組預(yù)定規(guī)則,根據(jù)熱度使用不同的存儲(chǔ)策略來(lái)優(yōu)化數(shù)據(jù)的訪問(wèn),從而提高整個(gè)存儲(chǔ)系統(tǒng)的效率。但該技術(shù)目前只適用企業(yè)ERP/MES(Enterprise Resource Planning/Manufacturing Execution System)場(chǎng)景,使用具有局限性。
當(dāng)前新型存儲(chǔ)器件的研究主要集中于低延遲存儲(chǔ)與持久內(nèi)存,但隨著成本的降低,新型存儲(chǔ)器件也開(kāi)始應(yīng)用于大規(guī)模分布式文件系統(tǒng)以提高性能。受到廣泛關(guān)注的非易失內(nèi)存(Non-Volatile Memory,NVM)類似于動(dòng)態(tài)隨機(jī)存取存儲(chǔ)器(Dynamic Random Access Memory,DRAM),是按字節(jié)尋址,提供了對(duì)持久性存儲(chǔ)的快速、細(xì)粒度訪問(wèn),并保證不會(huì)在斷電后丟失數(shù)據(jù),因此被認(rèn)為是一種具有廣泛前景的新型存儲(chǔ)[5]。目前新型存儲(chǔ)器主要有3 種:相變存儲(chǔ)器PCM(Pulse Code Modulation),以英特爾與美光聯(lián)合研發(fā)的3D Xpoint 為代表;磁變存儲(chǔ)器MRAM(Magnetic Random Access Memory),以美國(guó)Everspin 公司推出的STT-MRAM 為代表;阻變存儲(chǔ)器ReRAM(Resistive Random-Access Memory),目前暫無(wú)商用產(chǎn)品,代表公司有美國(guó)Crossbar。
由于硬件與軟件接口限制了NVM 設(shè)備硬件優(yōu)勢(shì)的發(fā)揮,國(guó)內(nèi)外研究根據(jù)NVM 的存儲(chǔ)特性設(shè)計(jì)并改良傳統(tǒng)的操作系統(tǒng)和數(shù)據(jù)管理方式。文獻(xiàn)[6]提出了Tinca,一種事務(wù)NVM 磁盤(pán)緩存的新機(jī)制,它以COW 方式將數(shù)據(jù)保存到非易失性主內(nèi)存(Non-Volatile Main Memory,NVMM)緩存中,并可以在日志數(shù)據(jù)和文件數(shù)據(jù)間切換,避免雙重寫(xiě)入;但Tinca 的設(shè)計(jì)被緊密耦合在Ext4(fourth Extended filesystem)的體系結(jié)構(gòu)中,這種基于慢速存儲(chǔ)設(shè)備的存儲(chǔ)方式并不適用于NVM。文獻(xiàn)[7]提出了HiNFS,該文件系統(tǒng)操作以細(xì)粒度的方式將緩沖和直接訪問(wèn)結(jié)合起來(lái),旨在通過(guò)DRAM 緩存延遲的持久寫(xiě)入操作來(lái)隱藏NVMM 的高寫(xiě)入延遲,從而形成DRAM-NVMM 混合架構(gòu);但這種方式未考慮DRAM高速緩存的崩潰一致性問(wèn)題。
由于非易失性內(nèi)存產(chǎn)品比磁盤(pán)和固態(tài)硬盤(pán)的讀寫(xiě)性能更高,同時(shí)還能持久化地存儲(chǔ)數(shù)據(jù)[8],因此,最近幾年開(kāi)始出現(xiàn)將NVM集成到HDFS中的研究。文獻(xiàn)[9]提出了NVFS(NVMand RDMA-aware HDFS),在現(xiàn)有的HDFS 中加入了對(duì)NVM 和遠(yuǎn)程直接數(shù)據(jù)存?。≧emote Direct Memory Access,RDMA)的支持。NVFS中NVM 提供兩種訪問(wèn)模式:塊訪問(wèn)和內(nèi)存訪問(wèn)。塊訪問(wèn)模式下,NVM 可以作為塊設(shè)備被加載到DataNode 的本地文件系統(tǒng)中,文件系統(tǒng)的I/O 操作調(diào)用NVMe(Non-Volatile Memory express)存儲(chǔ)系統(tǒng)接口通過(guò)底層的NVMe 驅(qū)動(dòng)實(shí)現(xiàn)。內(nèi)存訪問(wèn)模式下,DataNode 的讀寫(xiě)線程可以通過(guò)NVM 的直接內(nèi)存訪問(wèn)接口按照內(nèi)存語(yǔ)義訪問(wèn)NVM。且針對(duì)上層應(yīng)用,NVFS 將預(yù)寫(xiě)日志(Write-Ahead Logging,WAL)存儲(chǔ)在NVM中,其他數(shù)據(jù)存儲(chǔ)在SSD 中。這在一定程度上提升了HDFS的性能,但該方案目前只針對(duì)于特定的上層應(yīng)用,不具有通用性,因此還需要繼續(xù)研究。本文針對(duì)通用的基于NVM 的HDFS重新設(shè)計(jì)其寫(xiě)入流程,以此來(lái)提高性能和獲得上層應(yīng)用的通用性??傊琀DFS 在實(shí)際生產(chǎn)系統(tǒng)中應(yīng)用廣泛,對(duì)其上層應(yīng)用的性能有很大影響。雖然NVM 這類新型存儲(chǔ)器件可用于HDFS 的性能提升,但是目前較多用于本地文件系統(tǒng),而關(guān)于分布式系統(tǒng)的研究則較少。因此本文提出了基于NVM的HDFS寫(xiě)性能優(yōu)化方案。
新一代的非易失性存儲(chǔ)介質(zhì)NVM 和DRAM 性能相近,但其容量更大、價(jià)格更低[10]。NVM 主要包括兩大類:基于外存塊尋址的NVM(如閃存)擁有性能高、能耗低等優(yōu)勢(shì),已經(jīng)被廣泛應(yīng)用于高性能存儲(chǔ)系統(tǒng)中;基于內(nèi)存的NVM 即持久性內(nèi)存,其具備快速持久化與可字節(jié)尋址的特征,以及具有與內(nèi)存相似的讀性能和掉電非易失的特性,它的出現(xiàn)為大規(guī)模存儲(chǔ)系統(tǒng)的改進(jìn)提供了新的思路和方向。
2017年10月,Intel發(fā)布了一款名為Optane SSD 900P的固態(tài)硬盤(pán)[11],該設(shè)備采用了非易失性存儲(chǔ)技術(shù)3D XPoint,將NVMe 與非易失性存儲(chǔ)技術(shù)結(jié)合,被稱為世界上最快、可用性最好的一款專業(yè)級(jí)SSD[12]。這里使用Linux中通用的性能測(cè)試基準(zhǔn)fio 對(duì)NVM_DISK(模擬NVM)、Optane 900P SSD(480 GB)、SAMSUNG SATA-SSD 860 EVO(250 GB)[13]的讀寫(xiě)吞吐量進(jìn)行測(cè)試與對(duì)比。fio是一個(gè)開(kāi)源I/O壓力測(cè)試工具,提供了豐富的存儲(chǔ)引擎支持和豐富的參數(shù)類型,被廣泛應(yīng)用于存儲(chǔ)系統(tǒng)的性能測(cè)試。fio 提供了基準(zhǔn)測(cè)試工具,可以測(cè)試不同設(shè)備在不同塊大小、不同讀寫(xiě)模式下的帶寬、每秒進(jìn)行讀寫(xiě)操作的次數(shù)(Input/Output operations Per Second,IOPS)和延遲,結(jié)果如表1 所示。通過(guò)表1 測(cè)試結(jié)果可以看出,Optane-SSD 與SAMSUNG SATA-SSD相比,4 KB隨機(jī)讀取的讀取IOPS及帶寬均提升為原來(lái)的8 倍,讀延遲減少為原來(lái)的1/8.7,但Optane-SSD與模擬NVM相比,4 KB隨機(jī)讀取的讀取IOPS及帶寬均下降為原來(lái)的1/2.8,讀延遲增加為原來(lái)的4.3 倍。Optane-SSD與SAMSUNG SATA-SSD相比,4 KB隨機(jī)寫(xiě)入的IOPS及帶寬均提升為原來(lái)的9.2 倍,寫(xiě)入延遲減少為原來(lái)的1/9.7。且Optane-SSD與模擬NVM相比,4 KB隨機(jī)寫(xiě)入的IOPS及帶寬均提升為原來(lái)的2.7倍,寫(xiě)入延遲減少為原來(lái)的1/1.8。
HDFS 是由多臺(tái)機(jī)器組成的一個(gè)邏輯上的應(yīng)用級(jí)文件系統(tǒng),通過(guò)庫(kù)調(diào)用的方式提供數(shù)據(jù)存儲(chǔ)服務(wù),將數(shù)據(jù)分散存儲(chǔ)在集群中的多臺(tái)機(jī)器上,其上運(yùn)行著相關(guān)的存儲(chǔ)軟件,文件系統(tǒng)對(duì)外提供了統(tǒng)一的文件存儲(chǔ)服務(wù),因此需要綜合考慮硬件故障、網(wǎng)絡(luò)故障、擴(kuò)展性以及可用性等多重因素。HDFS 通過(guò)將文件劃分為固定大小的塊進(jìn)行存儲(chǔ),客戶端首先會(huì)與NameNode通信得到塊存儲(chǔ)的節(jié)點(diǎn)地址列表,然后將數(shù)據(jù)塊以文件的形式存儲(chǔ)在DataNode 節(jié)點(diǎn)。HDFS 的DataNode 節(jié)點(diǎn)用于存儲(chǔ)文件的數(shù)據(jù)塊,每個(gè)數(shù)據(jù)塊以單獨(dú)文件的形式保存在DataNode 節(jié)點(diǎn)的本地文件系統(tǒng)上。因此,各個(gè)DataNode 節(jié)點(diǎn)中的存儲(chǔ)介質(zhì)可掛載為不同類型的本地文件系統(tǒng)[14]。
如圖1 所示,將HDFS 根據(jù)其組織方式由下至上分為5層,分別是存儲(chǔ)介質(zhì)層、文件系統(tǒng)層、軟件調(diào)用層、分布式結(jié)構(gòu)層以及應(yīng)用層。因?yàn)橐3諬DFS 本身接口的兼容性,所以文件系統(tǒng)的改進(jìn)應(yīng)盡可能與舊版本的接口與功能兼容。因此,在維護(hù)本地文件系統(tǒng)的POXIS(Portable Operating System Interface of UNIX)規(guī)范的同時(shí),替換底層存儲(chǔ)介質(zhì)是最友好的NVM 設(shè)備加入方式。這無(wú)需對(duì)代碼邏輯作出更改,且HDFS提供數(shù)據(jù)存儲(chǔ)目錄中存儲(chǔ)設(shè)備的配置方法。首先,在Linux 5.0 內(nèi)核版本下通過(guò)內(nèi)存模擬的方式模擬持久性內(nèi)存,并為其掛載不同類型的文件系統(tǒng)。然后對(duì)HDFS 的存儲(chǔ)介質(zhì)層進(jìn)行改動(dòng),將NVMe-SSD與模擬的持久性內(nèi)存加入到HDFS中替換傳統(tǒng)的硬盤(pán)驅(qū)動(dòng)器(Hard Disk Drive,HDD)設(shè)備,并為HDFS 集群的所有DataNode 節(jié)點(diǎn)替換并配置不同的存儲(chǔ)介質(zhì)與文件系統(tǒng),分別用NVMe-SSD-ext4、PM-ext4-dax、PM-NOVA、HDD 文件系統(tǒng)作為DataNode 端的存儲(chǔ)設(shè)備。最后,通過(guò)在HDFS DataNode 的寫(xiě)入路徑中添加時(shí)間戳的方式,得到了一個(gè)固定大小的塊(128 MB)的寫(xiě)入磁盤(pán)所用時(shí)間與其他處理操作所用時(shí)間,并對(duì)各種存儲(chǔ)介質(zhì)的表現(xiàn)進(jìn)行了對(duì)比。
圖1 HDFS分層存儲(chǔ)結(jié)構(gòu)Fig.1 HDFS hierarchical storage structure
測(cè)試結(jié)果如圖2所示,根據(jù)實(shí)驗(yàn)結(jié)果發(fā)現(xiàn)NVMe-SSD等快速持久化設(shè)備加入HDFS 集群并替換HDD 作為DataNode 的外部存儲(chǔ),性能有一定的提升。該方式并未改變數(shù)據(jù)的寫(xiě)入方式,其寫(xiě)入耗時(shí)的占比雖然有所減小,但整體性能提升效果并不明顯。而將持久性內(nèi)存以塊設(shè)備的形式掛載并配置到HDFS 的寫(xiě)入路徑中,HDFS 中寫(xiě)入耗時(shí)的占比由32%下降至28%,將其掛載為NOVA[15]文件系統(tǒng),其寫(xiě)入耗時(shí)的占比由31%下降至20%。由此可見(jiàn),NVM 設(shè)備的加入可以在一定程度上提升文件的寫(xiě)入性能,且使用適配于NVM 設(shè)備的ext4-dax 與NOVA 文件系統(tǒng),獲得的提升幅度更大。由1.1 節(jié)的測(cè)試結(jié)果可知,NVMe-SSD 與SATA-SSD 相比,二者的裸盤(pán)性能最多相差9 倍多。而對(duì)HDFS 的寫(xiě)入測(cè)試數(shù)據(jù)顯示,NVMe-SSD 的加入并未獲得顯著的性能提升,并且將持久性內(nèi)存加入HDFS 中,最多也只能將塊數(shù)據(jù)寫(xiě)入耗時(shí)從原來(lái)的32%減少到20%。因此,通過(guò)簡(jiǎn)單的更換數(shù)據(jù)節(jié)點(diǎn)的存儲(chǔ)介質(zhì),并未充分發(fā)揮NVMe-SSD 與NVM 設(shè)備優(yōu)異的硬件性能,對(duì)于集群的性能提升幅度不太理想。
圖2 HDFS不同存儲(chǔ)介質(zhì)處理和寫(xiě)入耗時(shí)占比Fig.2 Time consumption proportion of processing and writing of different HDFS storage medias
通過(guò)分析發(fā)現(xiàn)僅替換其底層存儲(chǔ)介質(zhì)的方式,雖然保留了HDFS 的原始讀寫(xiě)方式,且配置方法與設(shè)備的更換較易操作,但NVM 自身的硬件優(yōu)勢(shì)被分布式環(huán)境中數(shù)據(jù)的處理與傳輸過(guò)程覆蓋,并未獲得較大的性能提升。因此,要對(duì)HDFS 的寫(xiě)路徑進(jìn)行詳細(xì)的分析,在軟件調(diào)用層詳細(xì)探究HDFS 的軟件調(diào)用過(guò)程中存在的性能瓶頸。
為了更好地優(yōu)化HDFS,首先要了解HDFS 的集群架構(gòu)與副本放置策略。HDFS采用Mater/Slave的架構(gòu)來(lái)存儲(chǔ)數(shù)據(jù),主要由四個(gè)部分組成:Client、NameNode、DataNode 以及Secondary NameNode[16]。如圖3 所示,Client 節(jié)點(diǎn)代表用戶通過(guò)HDFS 提供的類POSIX 接口,通過(guò)與NameNode 和DataNode交互來(lái)訪問(wèn)文件系統(tǒng)中的數(shù)據(jù);NameNode管理著集群中的元數(shù)據(jù),處理客戶端的請(qǐng)求,其中元數(shù)據(jù)主要包括文件系統(tǒng)命名空間和數(shù)據(jù)塊的存儲(chǔ)位置等;DataNode 管理集群中客戶端發(fā)來(lái)的讀寫(xiě)請(qǐng)求,且負(fù)責(zé)管理節(jié)點(diǎn)本地文件系統(tǒng)中數(shù)據(jù)塊,并定時(shí)向NameNode 發(fā)送心跳,反饋本節(jié)點(diǎn)狀態(tài)。同時(shí)為了提供存儲(chǔ)的容錯(cuò)性,每個(gè)數(shù)據(jù)塊都存有一定數(shù)量的副本,用戶可以自行設(shè)置(默認(rèn)為3 副本)。所有的數(shù)據(jù)塊由NameNode 決定其存儲(chǔ)的位置;Secondary NameNode 主要作用是定期合并NameNode 中的元數(shù)據(jù)文件,在NameNode 發(fā)生故障時(shí)可以作為輔助節(jié)點(diǎn)恢復(fù)NameNode中的數(shù)據(jù)。
為了保證可靠性,HDFS 采用了多副本機(jī)制,如圖3所示,數(shù)字方塊代表數(shù)據(jù)塊,相同數(shù)字的方塊表示同一數(shù)據(jù)塊及其副本。在副本數(shù)為3的情況下,HDFS 的默認(rèn)副本放置策略將3 個(gè)副本中的2 個(gè)放在同一機(jī)架(Rack)中的2 個(gè)不同DataNode 上,另外1 個(gè)副本放置在不同機(jī)架的DataNode 上。如果HDFS 集群跨越多個(gè)數(shù)據(jù)中心,還可以配置更多的副本數(shù),并調(diào)整副本放置策略保證至少1 個(gè)副本存儲(chǔ)在不同的數(shù)據(jù)中心。這樣的副本放置策略在容錯(cuò)和寫(xiě)入性能方面進(jìn)行了有效的權(quán)衡:一方面保證了數(shù)據(jù)副本在多節(jié)點(diǎn)、多機(jī)架甚至多數(shù)據(jù)中心的冗余,提高了系統(tǒng)容錯(cuò)能力;另一方面,保證盡可能多的副本優(yōu)先寫(xiě)入到網(wǎng)絡(luò)距離較近的節(jié)點(diǎn)(如同一節(jié)點(diǎn)、機(jī)架或數(shù)據(jù)中心)中,由于網(wǎng)絡(luò)距離較近的節(jié)點(diǎn)間網(wǎng)絡(luò)帶寬較高、傳輸延遲較低,保證了HDFS Client向HDFS中寫(xiě)入數(shù)據(jù)塊的性能。
圖3 HDFS集群架構(gòu)和數(shù)據(jù)塊放置策略Fig.3 Cluster architecture and data block placement strategy of HDFS
HDFS 文件系統(tǒng)以塊(默認(rèn)128 MB)為基本單位進(jìn)行文件的寫(xiě)入,文件按照固定塊大小分割為若干個(gè)塊存儲(chǔ)在DataNode 上。集群通過(guò)在客戶端、NameNode、DataNode 各節(jié)點(diǎn)間建立pipeline進(jìn)行文件的傳輸,每個(gè)塊在傳輸過(guò)程被拆分為固定大小的packet(默認(rèn)64 KB)[17],packet 由chunk 組成且chunk 是客戶端向DataNode 或DataNode 間的pipeline 中數(shù)據(jù)傳輸與校驗(yàn)的基本單位。以packet 為單位,依次將數(shù)據(jù)從客戶端寫(xiě)入DataNode 節(jié)點(diǎn)。HDFS 設(shè)置多副本冗余存儲(chǔ)策略且采用流式接口實(shí)現(xiàn)對(duì)數(shù)據(jù)的訪問(wèn)。
如圖4 所示,首先客戶端將packet 傳入DataNode 中,DataNode會(huì)盡量一次接收一個(gè)完整的packet,并把這個(gè)packet全部存放到緩存塊中,然后一邊把接收到的packet 寫(xiě)入本地磁盤(pán),一邊把它發(fā)往下一個(gè)接收端,最后在pipeline 中的最后一個(gè)DataNode 節(jié)點(diǎn)上驗(yàn)證數(shù)據(jù),并返回確認(rèn)幀確認(rèn)這個(gè)packet已經(jīng)完成。
圖4 HDFS寫(xiě)入通信流程Fig.4 Flowchart of HDFS writing communication
HDFS 文件的寫(xiě)入包括客戶端、DataNode 與NameNode 三類節(jié)點(diǎn)。客戶端中主要包括DistributedFileSystem、DFSClient、DFSOutputStream、DataStreamer 等類;DataNode 端包括DataNode、DataXceiverServer、DataXceiver、BlockReceiver等類;NameNode 中包括NameNode、NameNodeRpcServer 等類。如圖5 所示,將HDFS 寫(xiě)入文件的過(guò)程分為建立連接、數(shù)據(jù)處理與存儲(chǔ),以及斷開(kāi)連接3個(gè)階段:
1)首先,客戶端調(diào)用DistributedFileSystem 對(duì)象的create()方法向NameNode 發(fā)送通信請(qǐng)求。隨后,客戶端創(chuàng)建FSDataOutputStream 對(duì)象進(jìn)行文件傳輸。若NameNode節(jié)點(diǎn)驗(yàn)證并通過(guò)客戶端的寫(xiě)入請(qǐng)求,則會(huì)在NameNode 節(jié)點(diǎn)中創(chuàng)建一個(gè)文件條目(Entry),然后獲取塊文件存儲(chǔ)節(jié)點(diǎn)信息,最后將寫(xiě)入的節(jié)點(diǎn)信息返回至客戶端。
2)首先,客戶端將從NameNode 返回的節(jié)點(diǎn)列表構(gòu)造一個(gè)pipeline(即管道)。然后,客戶端會(huì)和pipeline 中的第一個(gè)節(jié)點(diǎn)(即主DataNode)進(jìn)行通信并建立連接??蛻舳藢?zhǔn)備寫(xiě)入的數(shù)據(jù)分為多個(gè)packet,存儲(chǔ)到一個(gè)FSDataOutputStream 對(duì)象的內(nèi)存緩沖區(qū)中??蛻舳送ㄟ^(guò)FSDataOutputStream 對(duì)象,向pipeline 中的主DataNode 節(jié)點(diǎn)發(fā)送數(shù)據(jù)。packet 數(shù)據(jù)在pipeline 中的DataNode(默認(rèn)為3)依次向下游節(jié)點(diǎn)按序傳輸。在發(fā)送數(shù)據(jù)相反方向,pipeline中的各個(gè)DataNode節(jié)點(diǎn)不斷地向上游節(jié)點(diǎn)發(fā)送寫(xiě)入完成的ack響應(yīng)。pipeline中的節(jié)點(diǎn)重復(fù)執(zhí)行此過(guò)程直至處理完成當(dāng)前塊的最后一個(gè)packet。最終由pipeline 中的第一個(gè)DataNode 節(jié)點(diǎn)將最后一個(gè)packet 的寫(xiě)入完成響應(yīng)ack,發(fā)送給客戶端。
3)首先,客戶端通過(guò)調(diào)用FSDataOutputStream 對(duì)象的close()方法,關(guān)閉客戶端與DataNode 之間的輸出流。然后,客戶端調(diào)用DistributedFileSystem 對(duì)象的complete()方法,向元數(shù)據(jù)存儲(chǔ)節(jié)點(diǎn)通知文件的寫(xiě)入已完成。最后,客戶端向NameNode節(jié)點(diǎn)發(fā)送寫(xiě)入完成信息,關(guān)閉所有的連接。
圖5 HDFS數(shù)據(jù)塊寫(xiě)入路徑Fig.5 HDFS data block write path
假設(shè)文件被分為M個(gè)塊,設(shè)寫(xiě)入過(guò)程中階段1 建立連接用時(shí)為T(mén)1,階段2數(shù)據(jù)處理與存儲(chǔ)用時(shí)為T(mén)2,階段3斷開(kāi)連接用時(shí)為T(mén)3。階段1 所用時(shí)間(T1)為客戶端與NameNode 通信時(shí)間以及NameNode 獲取節(jié)點(diǎn)列表的時(shí)間,可表示為常數(shù)tcn。階段2 所用時(shí)間(T2)包含客戶端與DataNode 通信時(shí)間tcm(建立連接過(guò)程與創(chuàng)建pipeline 的過(guò)程)、主DataNode 接收客戶端傳輸數(shù)據(jù)的時(shí)間ttransi、主DataNode 將數(shù)據(jù)持久化到磁盤(pán)的時(shí)間、主DataNode 將數(shù)據(jù)發(fā)送至下游節(jié)點(diǎn)的時(shí)間、主DataNode等待packet到達(dá)響應(yīng)的時(shí)間。階段3為關(guān)閉連接的所用時(shí)間(T3),表示為常數(shù)tclose。則寫(xiě)入一個(gè)文件的用時(shí)T如式(1)所示:
通過(guò)上述寫(xiě)過(guò)程可以分析得出,HDFS的讀寫(xiě)性能主要受4個(gè)因素的影響:
1)數(shù)據(jù)塊的數(shù)量,即文件的大小。
2)節(jié)點(diǎn)之間的通信速度,包括Client 與NameNode、Client與DataNode、DataNode 與DataNode 之間的網(wǎng)絡(luò)傳輸速度,這取決于節(jié)點(diǎn)間的網(wǎng)絡(luò)狀況。
3)寫(xiě)入/讀取過(guò)程中,DataNode磁盤(pán)的讀取/寫(xiě)入速度。
4)從NameNode 獲取塊數(shù)據(jù)存儲(chǔ)節(jié)點(diǎn)列表時(shí),NameNode的元數(shù)據(jù)查詢速度。
將文件的寫(xiě)入分為3 個(gè)階段并通過(guò)log 統(tǒng)計(jì)分析,各階段時(shí)間占比如圖6 所示,可以得到對(duì)于文件中的某一數(shù)據(jù)(128 MB)的寫(xiě)入,DataNode 間pipeline 中數(shù)據(jù)的傳輸時(shí)間與處理過(guò)程占整個(gè)block寫(xiě)入過(guò)程的85%左右,因此消耗時(shí)間最多的步驟就是文件寫(xiě)入過(guò)程中的主要瓶頸。
因此,本文針對(duì)如何優(yōu)化DataNode 間pipeline 中數(shù)據(jù)的傳輸時(shí)間以及處理過(guò)程提出兩種優(yōu)化策略,將在第3 章繼續(xù)分析寫(xiě)入階段中各階段的時(shí)間占比。
圖6 HDFS數(shù)據(jù)塊各階段寫(xiě)入時(shí)間Fig.6 HDFS data block write times at different stages
HDFS 通常用來(lái)處理TB 甚至PB 級(jí)別的數(shù)據(jù)。但由于文件大小的增加,數(shù)據(jù)在客戶端與DataNode 節(jié)點(diǎn)之間傳輸與處理的耗時(shí)占整個(gè)寫(xiě)入過(guò)程的百分比就越大。通過(guò)第2 章的研究與分析可知,文件的寫(xiě)入過(guò)程主要瓶頸存在于DataNode 節(jié)點(diǎn)間,即pipeline 的寫(xiě)入過(guò)程。pipeline 中塊數(shù)據(jù)的寫(xiě)入按時(shí)序可分為如下4個(gè)階段:
1)客戶端輸入流傳入的數(shù)據(jù)保存在內(nèi)存buffer 中,包括packetHeader信息、校驗(yàn)數(shù)據(jù)、實(shí)際數(shù)據(jù)等。
2)當(dāng)前packet 數(shù)據(jù)發(fā)送到下游DataNode(非pipeline 中的最后一個(gè)節(jié)點(diǎn))。
3)若為pipeline中最后一個(gè)節(jié)點(diǎn),則對(duì)數(shù)據(jù)進(jìn)行校驗(yàn)。持久化校驗(yàn)和數(shù)據(jù)及packet數(shù)據(jù)到文件輸出流中。
4)對(duì)packet 數(shù)據(jù)的處理與計(jì)算過(guò)程。將packet 信息加入PacketResponder 線程隊(duì)列中,等待下游節(jié)點(diǎn)的響應(yīng),并更新packet寫(xiě)入信息。
將上述4 個(gè)過(guò)程的耗時(shí)分別稱為receive time、mirror time、write time 及process time。如圖7 所示,通過(guò)測(cè)量得到了packet 數(shù)據(jù)的寫(xiě)入過(guò)程中4 個(gè)階段的平均耗時(shí)以及4 個(gè)階段的耗時(shí)占比。由測(cè)量結(jié)果可知,receive time 即接收數(shù)據(jù)的耗時(shí)占40~50%,是寫(xiě)入過(guò)程中最耗時(shí)的操作。
將上述4個(gè)階段的用時(shí)receive time、mirror time、write time及process time 分別稱為T(mén)0、T1、T2、T3,其耗時(shí)占比為43∶21∶31∶5。pipeline中各DataNode節(jié)點(diǎn)的數(shù)據(jù)處理流程如下:
1)接收處理packet0到內(nèi)存中并將其寫(xiě)入到DataNode1。
2)由DataNode1負(fù)責(zé)將packet0傳輸?shù)紻ataNode2,同時(shí)客戶端可以開(kāi)始接收處理packet1 并將其寫(xiě)入到輸出流,DataNode1處理完packet0后便開(kāi)始接收packet1。
3)同時(shí)DataNode2負(fù)責(zé)將packet0寫(xiě)入DataNode3。
4)重復(fù)上述3 個(gè)步驟將多個(gè)packet 依次傳輸至主DataNode 中,直至所有的packet 數(shù)據(jù)傳輸并持久化完成后寫(xiě)入結(jié)束。
圖7 packet寫(xiě)入過(guò)程各階段耗時(shí)占比Fig.7 Time consumption proportion of packet at different stages of writing process
按照原始的寫(xiě)入流程,客戶端向DataNode 寫(xiě)入一個(gè)文件的總時(shí)間取決于packet 的數(shù)量與單個(gè)packet 的處理時(shí)間。即總體寫(xiě)入時(shí)間與packet 數(shù)量和單個(gè)packet 的處理時(shí)間均成正比,因此,想要降低總體的處理時(shí)間,有兩種可行的方案:
1)增大packet大小。
如圖8 所示,HDFS 中一個(gè)固定大小的塊(如128 MB)由多個(gè)固定大小的packet 組成,packet 數(shù)據(jù)是由多個(gè)chunk 組成,單個(gè)packet 中包含header(packet 的概要屬性)、循環(huán)冗余校驗(yàn)(Cyclic Redundancy Check,CRC)和數(shù)據(jù)以及其對(duì)應(yīng)的數(shù)據(jù)。綜上,通過(guò)增大packet 的大小可以直觀地減少packet 的數(shù)量。
圖8 packet數(shù)據(jù)結(jié)構(gòu)Fig.8 packet data structure
如圖9 所示,在第4.1 節(jié)所述的測(cè)試環(huán)境下,通過(guò)TestDFSIO 測(cè)試了將packet大小更改為128 KB 與256 KB 后的集群寫(xiě)入性能,發(fā)現(xiàn)增大packet性能最大可提升11.1%,這是由于數(shù)據(jù)傳輸過(guò)程減小的時(shí)間多于單個(gè)pacekt處理增加的時(shí)間,因此總體時(shí)間變短。但由于單個(gè)packet 的處理時(shí)間也與packet 的大小相關(guān),當(dāng)packet 設(shè)置過(guò)大,單個(gè)packet 的處理時(shí)間也會(huì)隨之增加,并且相同的網(wǎng)絡(luò)條件下,傳輸大的數(shù)據(jù)相較傳輸小的數(shù)據(jù)更加容易出錯(cuò),給網(wǎng)絡(luò)傳輸帶來(lái)較大的壓力,因此這種方式并不是最為理想的優(yōu)化方案。
2)減少單個(gè)packet的處理時(shí)間。
假設(shè)單個(gè)packet 的處理時(shí)間為t,一個(gè)塊中共有N個(gè)packet,若將t減少到50%,則總時(shí)間T也會(huì)由N×t減小至50%×N×t。因此該方式可以有效地減少寫(xiě)入的總處理時(shí)間,從而性能得到較大的提升。如圖10 所示,基于分析,在HDFS 原有設(shè)計(jì)的基礎(chǔ)上,對(duì)客戶端到DataNode 的pipeline 數(shù)據(jù)傳輸?shù)倪^(guò)程進(jìn)行改進(jìn)。通過(guò)改進(jìn)了寫(xiě)入流程的關(guān)鍵路徑,分離了pipeline 寫(xiě)入數(shù)據(jù)的4 個(gè)階段。單獨(dú)處理從輸入流接收數(shù)據(jù)到buffer 這一過(guò)程。為單個(gè)DataNode 中的每一個(gè)塊的寫(xiě)入過(guò)程分配了(64 KB×100=6.25 MB)的內(nèi)存空間,作為存儲(chǔ)packet數(shù)據(jù)的臨時(shí)緩沖區(qū)。
在原始的HDFS 設(shè)計(jì)中,相鄰packet 之間的寫(xiě)入耗時(shí)較長(zhǎng),下一個(gè)packet 的處理需要等待上一個(gè)packet 接收完成、發(fā)送到下游節(jié)點(diǎn)并持久化完成后,才可以開(kāi)始從輸入流接收下一個(gè)packet。該設(shè)計(jì)會(huì)使得數(shù)據(jù)塊的寫(xiě)入時(shí)間受到網(wǎng)絡(luò)傳輸速度與磁盤(pán)I/O 的影響,因此本文為packet 創(chuàng)建了臨時(shí)緩沖區(qū),用于保存從輸入流中接收的packet 數(shù)據(jù)。這時(shí)packet 數(shù)據(jù)的處理流程(包括向下游節(jié)點(diǎn)發(fā)送數(shù)據(jù)、校驗(yàn)并持久化、計(jì)算及其他操作)可以與packet數(shù)據(jù)的接收異步進(jìn)行,而下一個(gè)packet可以更快地被接收與處理。
圖9 更改packet大小后HDFS寫(xiě)入吞吐量對(duì)比Fig.9 HDFS write throughput comparison after changing packet size
圖10 修改前后packet數(shù)據(jù)處理流程對(duì)比Fig.10 Comparison of packet data processing flow before and after modification
如圖10所示,這時(shí)DataNode 端寫(xiě)入數(shù)據(jù)的整體處理時(shí)間T由式(2)變?yōu)槭剑?)。另外,當(dāng)數(shù)據(jù)塊數(shù)量較大時(shí),數(shù)據(jù)傳輸時(shí)間t位于(N×T0,(N+1)×T0)。
要減少單個(gè)packet 的處理時(shí)間,需要在Hadoop 2.9.0 版本中的DataNode 端加入相應(yīng)的寫(xiě)緩沖處理機(jī)制。下面將整個(gè)優(yōu)化流程分為兩個(gè)處理實(shí)現(xiàn)模塊,并設(shè)計(jì)具體的實(shí)現(xiàn)細(xì)節(jié)。
3.2.1 寫(xiě)緩沖優(yōu)化機(jī)制的實(shí)現(xiàn)
DataNode端的塊數(shù)據(jù)接收和處理流程可以看作是一個(gè)典型的生產(chǎn)者-消費(fèi)者的問(wèn)題。DataNode 端的packetReceiver 類中的receivePacket(in)方法作為生產(chǎn)者,從客戶端/上游DataNode 發(fā)送的輸入流in 中不斷接收packet 數(shù)據(jù),而PacketResponder 線程作為消費(fèi)者,負(fù)責(zé)接收下游節(jié)點(diǎn)的ack響應(yīng),并向上游節(jié)點(diǎn)發(fā)送已處理完成的ack 響應(yīng)。ack 信息則為生產(chǎn)與消費(fèi)的對(duì)象。因此,當(dāng)pipeline 中的主DataNode 接收到塊中最后一個(gè)packet 的ack 響應(yīng)后,就代表所有的packet數(shù)據(jù)均已成功寫(xiě)入所有的副本中。通過(guò)生產(chǎn)者-消費(fèi)者作為切入點(diǎn),具體實(shí)現(xiàn)DataNode端寫(xiě)流程的優(yōu)化。
1)異步阻塞隊(duì)列的加入。
Java 為開(kāi)發(fā)者提供了幾種常用的阻塞隊(duì)列,如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlocking-Queue 等。阻塞隊(duì)列中維護(hù)了一個(gè)連續(xù)的存儲(chǔ)空間,生產(chǎn)者線程不斷地向隊(duì)列中放入數(shù)據(jù)對(duì)象直至隊(duì)列滿。消費(fèi)者線程不斷地從隊(duì)列中取出數(shù)據(jù)對(duì)象直至隊(duì)列為空。當(dāng)隊(duì)列滿時(shí),生產(chǎn)者線程會(huì)以阻塞的形式等待消費(fèi)者線程的消費(fèi)數(shù)據(jù)。當(dāng)隊(duì)列為空時(shí),消費(fèi)者線程會(huì)以阻塞的形式等待生產(chǎn)者線程生產(chǎn)數(shù)據(jù)[18]。LinkedBlockingQueue 是Java自帶的一種基于鏈表的有界阻塞隊(duì)列,在大量數(shù)據(jù)并發(fā)操作時(shí),可以通過(guò)其內(nèi)部的兩個(gè)讀寫(xiě)鎖進(jìn)行異步的讀寫(xiě)操作而不相互影響。
為了實(shí)現(xiàn)寫(xiě)緩沖優(yōu)化,在DataNode 端接收到packet 數(shù)據(jù)后,需要將數(shù)據(jù)先暫存在分配的緩沖區(qū)中,然后再進(jìn)行異步的持久化與處理操作。隊(duì)列結(jié)構(gòu)是一種先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu),使用隊(duì)列來(lái)存儲(chǔ)數(shù)據(jù)不僅可以保證packet 數(shù)據(jù)的按序輸出,同時(shí)可以實(shí)現(xiàn)對(duì)packet 的暫存。因此,為了使得生產(chǎn)者與消費(fèi)者之間相互獨(dú)立地進(jìn)行讀寫(xiě)操作,既可以實(shí)現(xiàn)在客戶端向隊(duì)列中寫(xiě)入packet數(shù)據(jù)(生產(chǎn)者),同時(shí)packetProcesser線程可以進(jìn)行packet 數(shù)據(jù)的處理(消費(fèi)者),通過(guò)使用LinkedBlockingQueue 這一基于鏈表實(shí)現(xiàn)的異步阻塞隊(duì)列完成了對(duì)packet數(shù)據(jù)的生產(chǎn)、消費(fèi)流程。
如圖11所示,對(duì)于DataNode2來(lái)說(shuō),從上游節(jié)點(diǎn)的輸出流in 中接收發(fā)送的packet 數(shù)據(jù),同時(shí)也通過(guò)mirrorout 向下游節(jié)點(diǎn)DataNode3 發(fā)送packet 數(shù)據(jù),從上游節(jié)點(diǎn)傳輸?shù)玫降膒acket數(shù)據(jù)被依次保存在異步處理隊(duì)列processQueue 中。packetReceiver 則負(fù)責(zé)將數(shù)據(jù)不斷地置入隊(duì)列(即生產(chǎn)過(guò)程),而packetProcesser線程則負(fù)責(zé)packet數(shù)據(jù)的處理,包括發(fā)送至下游節(jié)點(diǎn)、校驗(yàn)與持久化、計(jì)算與其他處理(即消費(fèi)的過(guò)程)。在整個(gè)塊數(shù)據(jù)寫(xiě)入的過(guò)程中,維持了一個(gè)穩(wěn)定的生產(chǎn)-消費(fèi)packet 數(shù)據(jù)的過(guò)程。通過(guò)實(shí)驗(yàn)驗(yàn)證,為每一個(gè)數(shù)據(jù)塊分配大小為100 的packet 緩沖區(qū),可以滿足數(shù)據(jù)傳輸速度與數(shù)據(jù)處理速度之間的平衡。
圖11 HDFS pipeline輸入輸出流Fig.11 HDFS pipeline input and output stream
2)異步處理線程。
如圖12 所示,為了在DataNode 端加入寫(xiě)入緩沖機(jī)制,需要在DataNode 端構(gòu)造新的線程去處理保存在阻塞隊(duì)列中的packet 數(shù)據(jù),將保存在緩沖buffer 中的packet 數(shù)據(jù)按序進(jìn)行分發(fā)、校驗(yàn)以及持久化等操作。
圖12 HDFS寫(xiě)緩沖異步處理機(jī)制的實(shí)現(xiàn)Fig.12 Implementation of HDFS write buffer asynchronous processing mechanism
對(duì)于DataNode 來(lái)說(shuō),當(dāng)緩沖buffer 中接收到packet 數(shù)據(jù)后,即可進(jìn)行下一個(gè)packet 的接收。這種異步處理流程無(wú)需進(jìn)行后續(xù)的計(jì)算、校驗(yàn)以及持久化到磁盤(pán)等過(guò)程,經(jīng)過(guò)實(shí)驗(yàn)分析,這種方式減少了DataNode 節(jié)點(diǎn)寫(xiě)入數(shù)據(jù)塊的總時(shí)間,并將單個(gè)packet的接收與處理時(shí)間重疊。詳細(xì)步驟如下:
首先,由于線程對(duì)象的創(chuàng)建與銷毀對(duì)資源的消耗較大,為了節(jié)省計(jì)算資源、提升存儲(chǔ)空間利用率以及提高線程的可管理性,在DataNode 端創(chuàng)建了newCachedThreadPool 可緩存線程池來(lái)管理新創(chuàng)建的線程,主要有兩個(gè)數(shù)據(jù)處理線程(packetPersister 與packetProcesser)與一個(gè)響應(yīng)處理線程(packetResponder)。
1)packetPersister 線程。在開(kāi)始傳輸塊數(shù)據(jù)前創(chuàng)建并啟動(dòng)線程,對(duì)于保存在內(nèi)存buffer 中的packet 數(shù)據(jù),在經(jīng)過(guò)前面的計(jì)算、校驗(yàn)等處理流程后,將其以先進(jìn)先出的順序暫存于阻塞隊(duì)列中,然后依次進(jìn)行持久化操作。packetPersister 線程需要等待最后一個(gè)packet處理完成才可關(guān)閉。
2)packetProcesser線程。在開(kāi)始傳輸塊數(shù)據(jù)前,創(chuàng)建并啟動(dòng)線程,將buffer中接收到的packet數(shù)據(jù)存儲(chǔ)依次向下游節(jié)點(diǎn)發(fā)送。packetProcesser 線程在最后一個(gè)packet 處理完成后才可關(guān)閉。
3)packetResponder 線程。要減少單個(gè)packet 的處理延時(shí),則需要修改packetResponder 的處理流程。通常認(rèn)為當(dāng)packet 被持久化至緩沖buffer 后,就表示packet 數(shù)據(jù)已經(jīng)完成持久性。因此可以向packetResponder 線程發(fā)送寫(xiě)入成功響應(yīng)。此時(shí)單個(gè)packet的接收、處理延時(shí)減少。對(duì)于pipeline 中的非末尾DataNode 節(jié)點(diǎn)都只需進(jìn)行packet 的接收,即可得到返回的響應(yīng)。而對(duì)于pipeline中的最后一個(gè)節(jié)點(diǎn),需要對(duì)數(shù)據(jù)進(jìn)行校驗(yàn)并持久化后才能向上游節(jié)點(diǎn)返回成功的響應(yīng)。
在HDFS中加入異步阻塞隊(duì)列處理核心代碼如下所述:
3.2.2 數(shù)據(jù)異常處理方案
3.2.1 節(jié)提出的HDFS 寫(xiě)緩沖優(yōu)化方案通過(guò)更改塊數(shù)據(jù)的寫(xiě)入流程,使性能得到一定程度上的提升,但同時(shí)也引發(fā)了一些可靠性問(wèn)題,下面討論了寫(xiě)流程的更改是否仍然能夠保證節(jié)點(diǎn)間數(shù)據(jù)的一致性及集群中數(shù)據(jù)的可靠性。
首先,針對(duì)在塊數(shù)據(jù)的pipeline 寫(xiě)入流程中DataNode 端可能出現(xiàn)的幾種異常情況進(jìn)行了如下分析:
1)DataNode 節(jié)點(diǎn)接收到的packet數(shù)據(jù)的頭部信息出現(xiàn)亂序或長(zhǎng)度為負(fù)值。這一般是由于網(wǎng)絡(luò)異常等原因,導(dǎo)致前面?zhèn)鬏敃r(shí)packet 信息丟失或packet 的頭部信息讀取錯(cuò)誤,接收到的數(shù)據(jù)不可用。此時(shí)已無(wú)法保證先前packet信息的一致性與正確性,應(yīng)中斷packet 數(shù)據(jù)的寫(xiě)入,建立pipeline 重新進(jìn)行傳輸。
2)packet 數(shù)據(jù)在傳輸?shù)较掠喂?jié)點(diǎn)的過(guò)程中出錯(cuò),下游節(jié)點(diǎn)無(wú)法接收到已發(fā)送的數(shù)據(jù)。這是由于I/O 流出現(xiàn)錯(cuò)誤或者節(jié)點(diǎn)間網(wǎng)絡(luò)出現(xiàn)了異常情況,導(dǎo)致數(shù)據(jù)的分發(fā)時(shí)間過(guò)長(zhǎng),無(wú)法保證數(shù)據(jù)成功發(fā)送至下游節(jié)點(diǎn),則代表pipeline 已經(jīng)出現(xiàn)問(wèn)題,無(wú)法為數(shù)據(jù)提供正常的傳輸服務(wù)。這時(shí)出現(xiàn)錯(cuò)誤的DataNode 節(jié)點(diǎn)應(yīng)捕獲分發(fā)數(shù)據(jù)時(shí)發(fā)生的異常信息,判斷是否為異常中斷情況。若為I/O異常等所帶來(lái)的中斷情況,則拋出I/O 異常;若非中斷情況,則等待線程的run()方法繼續(xù)執(zhí)行,標(biāo)記mirrorError位為true,然后DataNode會(huì)向客戶端節(jié)點(diǎn)告知異常并等待客戶端的處理,而客戶端會(huì)根據(jù)情況關(guān)閉pipeline。
3)packet 數(shù)據(jù)在校驗(yàn)時(shí)出現(xiàn)錯(cuò)誤。若通過(guò)CRC 確認(rèn)packet 數(shù)據(jù)與校驗(yàn)和數(shù)據(jù)無(wú)法對(duì)應(yīng),校驗(yàn)過(guò)程失敗,即說(shuō)明發(fā)生了數(shù)據(jù)異常。此時(shí)委托packetResponder 線程返回ERROR_CHECKSUM 的響應(yīng)ack,然后拋出校驗(yàn)和異常,中斷寫(xiě)入過(guò)程。
4)packet 數(shù)據(jù)在持久化到磁盤(pán)時(shí)出錯(cuò)。通常,從上游節(jié)點(diǎn)傳入的packet的開(kāi)始偏移信息與磁盤(pán)上的現(xiàn)存數(shù)據(jù)是對(duì)齊的。若packet 的開(kāi)始偏移量與校驗(yàn)和無(wú)法對(duì)齊,則可能會(huì)出現(xiàn)數(shù)據(jù)丟失/錯(cuò)誤失效的情況。當(dāng)涉及到故障恢復(fù)時(shí),客戶端的狀態(tài)與DataNode 節(jié)點(diǎn)的數(shù)據(jù)會(huì)出現(xiàn)不一致的情況,即客戶端發(fā)送的數(shù)據(jù)并未真正地寫(xiě)入到DataNode 節(jié)點(diǎn)中。這時(shí),客戶端可能會(huì)重新發(fā)送部分已經(jīng)在磁盤(pán)上的數(shù)據(jù)。在數(shù)據(jù)寫(xiě)入校驗(yàn)和緩沖區(qū)到磁盤(pán)時(shí),應(yīng)跳過(guò)已正確寫(xiě)入的數(shù)據(jù)。
本節(jié)對(duì)寫(xiě)入過(guò)程中DataNode 端的異常處理情況進(jìn)行了介紹,但大多數(shù)情況下,是由客戶端節(jié)點(diǎn)對(duì)塊寫(xiě)入過(guò)程中的異常進(jìn)行進(jìn)一步處理的:Client 通常會(huì)根據(jù)DataNode 端發(fā)送的異常響應(yīng)進(jìn)行相應(yīng)的處理(如失敗重傳、宕機(jī)后重啟節(jié)點(diǎn)等)。如圖13 所示,Client 節(jié)點(diǎn)中的DataStreamer 線程負(fù)責(zé)數(shù)據(jù)的傳輸。DataStreamer 從dataQueue(待發(fā)送packet 數(shù)據(jù)列表)中獲取packet 數(shù)據(jù),然后將其發(fā)送至主DataNode,并將packet 數(shù)據(jù)依次放入ackQueue(packet 數(shù)據(jù)響應(yīng)列表)中。對(duì)于每一個(gè)packet數(shù)據(jù),只有當(dāng)pipeline 中的所有DataNode 都寫(xiě)入成功并成功返回響應(yīng),才表示這個(gè)packet數(shù)據(jù)已寫(xiě)入成功。
若在寫(xiě)入過(guò)程中Client 節(jié)點(diǎn)得到了錯(cuò)誤的響應(yīng),則客戶端會(huì)將所有未成功寫(xiě)入的packet 數(shù)據(jù)從ackQueue 中依次移除。再通過(guò)重新建立新的pipeline 連接,將異常的DataNode節(jié)點(diǎn)從pipeline 中移除。然后,開(kāi)始從dataQueue 中重新發(fā)送數(shù)據(jù)。
此外,DataNode 需要每隔一段時(shí)間(默認(rèn)為3 s,通過(guò)dfs.heartbeat.interval設(shè)置)向NameNode 發(fā)送心跳信息,并且NameNode也會(huì)通過(guò)心跳向DataNode下發(fā)命令。若NameNode很久(默認(rèn)為5 min,通過(guò)heartbeat.recheck.interval設(shè)置)無(wú)法接收到DataNode 的心跳信息,則NameNode 會(huì)將該DataNode認(rèn)定為失效(HDFS中設(shè)置的默認(rèn)超時(shí)時(shí)間是10 min+30 s)。
圖13 Client端數(shù)據(jù)處理流程Fig.13 Flowchart of Client-side data processing
同時(shí),NameNode將缺失的副本根據(jù)副本因子數(shù)再?gòu)?fù)制一份。其中,DataNode 節(jié)點(diǎn)被認(rèn)定失效的時(shí)間timeout的計(jì)算公式如式(4)所示:
首先,選用通用的文件系統(tǒng)性能測(cè)試基準(zhǔn)如TestDFSIO對(duì)本文優(yōu)化方案進(jìn)行測(cè)試與分析。然后,結(jié)合實(shí)現(xiàn)方案、集群特征與硬件特征,通過(guò)設(shè)計(jì)一系列實(shí)驗(yàn)對(duì)本文所述優(yōu)化方案的效果進(jìn)行了評(píng)估、驗(yàn)證與對(duì)比,并在多個(gè)維度對(duì)實(shí)驗(yàn)結(jié)果進(jìn)行了詳細(xì)分析。
本次實(shí)驗(yàn)對(duì)Hadoop 2.9.0 版本進(jìn)行比對(duì)實(shí)驗(yàn),集群共配置5個(gè)節(jié)點(diǎn),包括1個(gè)NameNode節(jié)點(diǎn),3個(gè)DataNode節(jié)點(diǎn),1個(gè)Client 節(jié)點(diǎn)。有關(guān)Hadoop 集群各節(jié)點(diǎn)的配置信息如下所示:CPU 為Intel Xeon Gold 5115 CPU 2.40 GHz;網(wǎng)絡(luò)為Intel 10 Gigabit PCI Express Network Driver(Speed 為10 000 Mb/s);內(nèi)核版本為GNU/Linux 4.15.0-43-generic x86_64;內(nèi)存為32 GB;硬盤(pán)大小為1.8 TB-HDD、240 GB-SATA-SSD、480 GBNVMe-SSD;總核數(shù)為40;操作系統(tǒng)為Ubuntu 18.04.3 LTS;JDK版本為1.8.0_11-b12。
實(shí)驗(yàn)使用通用測(cè)試基準(zhǔn)TestDFSIO 工具對(duì)大數(shù)據(jù)存儲(chǔ)系統(tǒng)Hadoop 進(jìn)行測(cè)試與分析,得到分布式文件系統(tǒng)HDFS 的讀寫(xiě)性能指標(biāo)。
TestDFSIO 是Hadoop 集群自帶的一個(gè)benchmark 測(cè)試程序,該基準(zhǔn)通過(guò)調(diào)用集群自帶的MapReduce 任務(wù)來(lái)并發(fā)執(zhí)行讀寫(xiě)操作。其中,Map任務(wù)用于讀寫(xiě)文件中的數(shù)據(jù),Reduce任務(wù)則用于記錄累計(jì)的統(tǒng)計(jì)信息[19]。TestDFSIO 的測(cè)試結(jié)果取決于HDFS 的讀寫(xiě)性能。測(cè)試會(huì)產(chǎn)生兩個(gè)最重要的性能衡量指標(biāo):每個(gè)Map 任務(wù)的平均吞吐量(單位為MB/s);單個(gè)文件寫(xiě)入I/O 的平均速度(單位也為MB/s)。此外,使用TestDFSIO進(jìn)行測(cè)試讀寫(xiě)性能需要清空l(shuí)inux 文件系統(tǒng)緩存,并在測(cè)試結(jié)束后使用自帶的clean 命令清理文件。本文通過(guò)測(cè)試不同文件大小的吞吐量與I/O 平均速度等指標(biāo),對(duì)HDFS 集群的讀寫(xiě)性能進(jìn)行評(píng)估。
同時(shí)還設(shè)計(jì)了直觀的HDFS 文件讀寫(xiě)基準(zhǔn),用于測(cè)試集群的讀寫(xiě)性能,將其稱為T(mén)est_Execution_Time,其主要思想為:使用HDFS 的客戶端文件系統(tǒng)命令(put、get)向集群中寫(xiě)入或讀取N個(gè)固定大小的文件,通過(guò)統(tǒng)計(jì)整個(gè)過(guò)程的寫(xiě)入時(shí)間或讀取時(shí)間,可以得到集群寫(xiě)入/讀取單個(gè)大小為M的文件的執(zhí)行時(shí)間。然后,通過(guò)對(duì)比不同方案下文件的寫(xiě)入時(shí)間,測(cè)試出集群的I/O性能是否提升。
本節(jié)通過(guò)使用常用的兩種測(cè)試工具TestDFSIO 與Test_Execution_Time,分別測(cè)試了原始HDFS 集群與寫(xiě)緩沖優(yōu)化后HDFS的寫(xiě)入性能。將原始的HDFS稱為HDFS-org,將基于NVM 的寫(xiě)緩沖優(yōu)化后的HDFS 定義為HDFS-mod,其測(cè)試結(jié)果如圖14~16所示。
圖14 TestDFSIO測(cè)試HDFS寫(xiě)入吞吐量對(duì)比Fig.14 Comparison of HDFS write throughput tested by TestDFSIO
圖16 Test_Execution_Time測(cè)試的HDFS寫(xiě)入執(zhí)行時(shí)間對(duì)比Fig.16 Comparison of HDFS write execution time tested by Test_Execution_Time
首先,使用測(cè)試基準(zhǔn)TestDFSIO 對(duì)集群的寫(xiě)入性能進(jìn)行測(cè)試,分別測(cè)試了100 個(gè)50~500 MB 大小的文件,向集群中寫(xiě)入了約5~50 GB 的數(shù)據(jù)。從圖14~15 可以觀察到,集群的寫(xiě)入吞吐量與吞吐率均得到了15%~24%的性能提升。這表明在HDFS中加入寫(xiě)入緩沖區(qū),并且改進(jìn)HDFS寫(xiě)入路徑處理流程,集群的寫(xiě)入吞吐量與吞吐率均可以得到明顯的性能提升。
如圖16 所示,還使用了Test_Execution_Time 基準(zhǔn)測(cè)試了向集群中寫(xiě)入100 MB、200 MB、500 MB、1 GB、2 GB 文件的寫(xiě)入執(zhí)行時(shí)間??梢钥吹?,隨著寫(xiě)入文件大小的增加,所需時(shí)間也在不斷增加。而通過(guò)寫(xiě)緩沖優(yōu)化的HDFS 與原始的HDFS相比,執(zhí)行時(shí)間最高減少了36.1%,平均減少了28.1%,在很大程度上提升了集群的寫(xiě)入速度。
本文研究了基于非易失性存儲(chǔ)器件NVM 的大規(guī)模分布式存儲(chǔ)系統(tǒng)的性能優(yōu)化方案,核心研究對(duì)象是Hadoop 分布式文件系統(tǒng)(HDFS)。通過(guò)分析新型存儲(chǔ)器件的優(yōu)勢(shì)和HDFS的讀寫(xiě)路徑時(shí)序及其方法間的調(diào)用關(guān)系,本文指出了新型存儲(chǔ)器件使用面臨的挑戰(zhàn)和HDFS 的讀寫(xiě)瓶頸,設(shè)計(jì)并實(shí)現(xiàn)了一種數(shù)據(jù)的異步寫(xiě)入方案。該方案主要在DataNode 端加入寫(xiě)入緩沖區(qū),并對(duì)HDFS 的pipeline 寫(xiě)入流程進(jìn)行了并行化處理。通過(guò)實(shí)驗(yàn)測(cè)試可知,此方案將HDFS 的寫(xiě)入性能最高提升了36%。
本文研究還存在一些不足:因市場(chǎng)上現(xiàn)有的NVM 設(shè)備少,本文研究中大部分實(shí)驗(yàn)是以內(nèi)存模擬的方式進(jìn)行的,而NVM 設(shè)備在實(shí)際應(yīng)用過(guò)程中可能出現(xiàn)讀寫(xiě)不對(duì)稱、壽命有限、磨損均衡等問(wèn)題,所以測(cè)量出的性能提升與理想狀態(tài)有一定的差距,未來(lái)可進(jìn)行進(jìn)一步的完善。