張 晨,鄧玉輝,2+
1.暨南大學(xué)信息科學(xué)技術(shù)學(xué)院計(jì)算機(jī)科學(xué)系,廣州 510632
2.中國科學(xué)院計(jì)算技術(shù)研究所計(jì)算機(jī)體系結(jié)構(gòu)國家重點(diǎn)實(shí)驗(yàn)室,北京 100190
在過去的十年中,Xen、VMware、KVM 和Hyper-V是大多數(shù)云計(jì)算系統(tǒng)使用的虛擬機(jī)管理程序,為云計(jì)算在共享池中快速配置和釋放計(jì)算機(jī)資源提供支撐。隨著操作系統(tǒng)虛擬化的快速發(fā)展,其較強(qiáng)的兼容性和較低的資源開銷吸引Google 和IBM 等企業(yè)使用容器[1]來創(chuàng)建隔離的虛擬環(huán)境[2]。Docke 是Linux平臺(tái)上的一款輕量級容器管理引擎,不僅具有很好的性能優(yōu)勢和安全性,而且能幫助用戶提升持續(xù)集成/持續(xù)交付(continuous integration/continuous delivery,CI/CD)的效率。例如,ING 是全球十大金融服務(wù)公司之一,通過使用Docker 部署高度自動(dòng)化的CD 流水線,為基礎(chǔ)設(shè)施資源節(jié)約了50%的開銷(https://www.docker.com/blog/docker-selected-as-gartner-cool-vendorin-devops)。在業(yè)界對容器技術(shù)強(qiáng)烈的需求導(dǎo)向之下,越來越多的企業(yè)在生產(chǎn)環(huán)境中使用Docker 進(jìn)行大規(guī)模任務(wù)部署。
在實(shí)際項(xiàng)目中,企業(yè)通常利用Docker 提供的注冊表服務(wù)來解決容器鏡像的分發(fā)和存儲(chǔ)問題。目前,市場上有不同云服務(wù)商提供的Docker 注冊表實(shí)例,如Docker Hub(https://hub.docker.com/)、Google Container Registry(https://cloud.google.com/containerregistry/)、IBM Cloud Container Registry 和Amazon Elastic Container Registry(http://aws.amazon.com/cn/ecr/)等,注冊表提供一套R(shí)EST(representational state transfer)接口用于Docker客戶端向注冊表自由發(fā)布鏡像并供他人下載。圖1 是IBM Cloud Registry 的部署架構(gòu),負(fù)載均衡器將用戶請求分配到不同地區(qū)的注冊表服務(wù)器中,注冊表服務(wù)器均采用對象存儲(chǔ)服務(wù)(例如Amazon S3),無沖突地寫入共同的后端存儲(chǔ)[3-4]。據(jù)統(tǒng)計(jì),大型容器公共注冊表至少存儲(chǔ)數(shù)百TB 數(shù)據(jù),每天增加1 500 個(gè)公共鏡像存儲(chǔ)庫[5],并且私人鏡像存儲(chǔ)庫也在不斷更新。有工作表明,從此類規(guī)模的注冊表中拉取鏡像的時(shí)間占容器總啟動(dòng)時(shí)間的76%[6]。
Fig.1 IBM Cloud Registry architecture圖1 IBM Cloud Registry 架構(gòu)
在傳統(tǒng)Docker 注冊表架構(gòu)中,注冊表由負(fù)載均衡器、注冊表服務(wù)器、對象存儲(chǔ)服務(wù)器等組件構(gòu)成,在用戶發(fā)出構(gòu)建容器指令后,Docker 客戶端發(fā)出請求會(huì)遍歷所有組件。圖2 展示了分析IBM 注冊表trace 數(shù)據(jù)集得出用戶拉取鏡像層的延遲分布情況,大約88%的鏡像層拉取延遲小于5 s,拉取單個(gè)鏡像層的最長延遲超過2 min。由于容器啟動(dòng)需要收集完整鏡像,通常鏡像由數(shù)十個(gè)鏡像層組成,且Docker 客戶端最大并行拉取3 個(gè)鏡像層,在大型公共容器注冊表的場景下,拉取鏡像請求的高延遲已經(jīng)大大削弱容器快速啟動(dòng)的特性,因此減少拉取鏡像延遲成為研究的熱點(diǎn)。
Fig.2 Distribution of image layes pulling delay in IBM Cloud Registry圖2 通過IBM 注冊表拉取鏡像層的延遲分布
目前,國內(nèi)針對容器技術(shù)開展了很多研究,例如通過分析以Docker 為代表的自動(dòng)化工具在實(shí)踐中出現(xiàn)的問題,深入探討Docker 對中國DevOps 的影響并提出相關(guān)建議[7],有的研究從技術(shù)架構(gòu)分析容器技術(shù)特點(diǎn),并從容器實(shí)例層、管理層和內(nèi)核資源層梳理操作系統(tǒng)虛擬化的現(xiàn)狀[8],有的研究提出一種服務(wù)質(zhì)量敏感的,基于前饋的容器資源彈性供給方法,解決傳統(tǒng)虛擬化環(huán)境中資源供給時(shí)效差和難以應(yīng)對負(fù)載突變的問題[9]。國外研究聚焦優(yōu)化鏡像拉取延遲問題,如Harter 等人提出的Slacker[6],該方案在拉取鏡像的最初時(shí)刻僅檢索并傳輸啟動(dòng)容器的最小數(shù)據(jù)集,然后采用lazy cloning和lazy propagation的方式從共享NFS(network file system)存儲(chǔ)中提取剩余需要的鏡像數(shù)據(jù),從而縮短了容器的啟動(dòng)時(shí)間,但這種方案需要注冊表與客戶端保持持續(xù)連接,協(xié)作要求較高。Nathan等人[10]提出了一種在一組節(jié)點(diǎn)之間使用P2P 協(xié)議協(xié)作管理Docker 鏡像的系統(tǒng)——CoMICon,該系統(tǒng)在接收到用戶請求時(shí)會(huì)優(yōu)先從鄰近的節(jié)點(diǎn)獲取缺失的層,然后查詢遠(yuǎn)程注冊表,并行拉取鏡像的方法能有效縮短網(wǎng)絡(luò)傳輸延遲,加快容器的啟動(dòng)與部署。
由上述分析發(fā)現(xiàn),現(xiàn)有的研究工作對于中小規(guī)模組織中容器部署場景的優(yōu)化已經(jīng)相當(dāng)成熟,因此從網(wǎng)絡(luò)或存儲(chǔ)驅(qū)動(dòng)等方面對Docker 做出改進(jìn)的空間有限。基于現(xiàn)有云服務(wù)商重新設(shè)計(jì)注冊表架構(gòu)的背景下,本文以注冊表服務(wù)器組件為核心優(yōu)化點(diǎn),從Docker 鏡像結(jié)構(gòu)和注冊表功能出發(fā),提出一種基于鏡像層相關(guān)性的緩存預(yù)取方案,將部分體積較小的熱點(diǎn)鏡像層預(yù)先從后端取回,緩存至注冊表服務(wù)器內(nèi)存中,當(dāng)用戶請求命中時(shí)即可拉取鏡像。本文方案提高了注冊表內(nèi)存資源利用率的同時(shí),減少請求跳數(shù)和后端I/O 壓力,縮短用戶拉取鏡像的流程從而隱藏耗費(fèi)的網(wǎng)絡(luò)延遲,最終加快容器啟動(dòng)速度。這項(xiàng)工作的主要貢獻(xiàn)概括如下:
(1)通過研究鏡像層存儲(chǔ)機(jī)制,利用鏡像層的空間局部性設(shè)計(jì)關(guān)聯(lián)模型,最終實(shí)現(xiàn)一種基于鏡像層關(guān)聯(lián)的Docker 注冊表緩存預(yù)取策略LCPA(layer correlation prefetch algorithm)。
(2)在本文方法中,實(shí)現(xiàn)由鏡像結(jié)構(gòu)提取模塊、拉取請求處理模塊和關(guān)聯(lián)鏡像層計(jì)算模塊為核心的模擬仿真器,并利用基于真實(shí)負(fù)載下的Docker 數(shù)據(jù)集進(jìn)行實(shí)驗(yàn)。
(3)驗(yàn)證了LCPA 策略的正確性和有效性。實(shí)驗(yàn)結(jié)果表明,與LRU(least recently used)、LIRS(low interreference recency set replacement policy)、GDFS(greedy dual frequency size)和LPA(least prefetching algorithm)算法相比,本文提出的預(yù)取策略在緩存命中率和節(jié)省延遲方面有著明顯的性能提高。
隨著對緩存管理的不斷研究,針對不同工作負(fù)載的緩存替換算法相繼提出,通常劃分為以LRU[11]、LFU(least frequently used)[12]、SLRU(size least recently used)[13]、GD(greedy dual)[14]、RAND 為代表的五類算法。雖然LRU 在現(xiàn)有的各種應(yīng)用場景中都能發(fā)揮比較穩(wěn)定的性能,但依舊存在一些不足,例如LRU 對再次訪問的數(shù)據(jù)會(huì)放置隊(duì)首,重置它的緩存周期,從而帶來“緩存污染”,同時(shí)缺少對數(shù)據(jù)多維度的考量,捕捉數(shù)據(jù)體積較大的文件會(huì)導(dǎo)致命中率降低,無法適應(yīng)局部性較弱的訪問模式。
LIRS 是一種突破LRU 限制的算法,使用重用距離作為緩存替換的依據(jù),有效避免了LRU 中冷熱數(shù)據(jù)相同的緩存周期,提高了對未來可能訪問數(shù)據(jù)的命中。LIRS 將緩存劃分成LIR(low inter-reference)堆棧和HIR(high inter-reference)堆棧,將空間較小的HIR堆棧作為二級緩存,捕捉重用距離小的數(shù)據(jù)并送入LIR 棧,替換掉長時(shí)間沒有重復(fù)被命中的數(shù)據(jù)。這個(gè)特性同樣給算法帶來不足,一個(gè)冷數(shù)據(jù)在HIR 棧中短時(shí)間命中兩次之后再無訪問,則該數(shù)據(jù)將在LIR 棧中經(jīng)歷全部數(shù)據(jù)流出后才被替換,造成一定程度的“緩存污染”。
GDFS 算法的核心是利用數(shù)據(jù)的大小、訪問頻率以及訪問代價(jià)建立老化函數(shù),并給參數(shù)分配不同的權(quán)值,最終給每一個(gè)數(shù)據(jù)計(jì)算出相應(yīng)的特征值。考慮到時(shí)間局部性,老化因子是隨時(shí)間而增大的,短期內(nèi)命中的數(shù)據(jù)特征值較大且更新在緩存隊(duì)列中的位置。GDFS 根據(jù)訪問情況每次淘汰掉特征值最小的數(shù)據(jù),但算法并不能跟隨自適應(yīng)工作負(fù)載的變化,向公式添加新的適應(yīng)性參數(shù)會(huì)提高算法復(fù)雜性,帶來較高的性能開銷。
預(yù)取技術(shù)是提高云存儲(chǔ)系統(tǒng)性能的重要研究方向,現(xiàn)代數(shù)據(jù)中心使用分布式內(nèi)存緩存服務(wù)器(https://memcached.org/,https://redis.io/)[15]來提高數(shù)據(jù)庫查詢性能,同時(shí)結(jié)合緩存和預(yù)取[16-17]技術(shù)能顯著地提高緩存命中率。
注冊表通常會(huì)將請求信息存儲(chǔ)在日志中,分析日志可得出對鏡像操作的請求信息,例如請求時(shí)間、響應(yīng)時(shí)間、用戶IP、HTTP 請求方法等,這些信息主要被以時(shí)間相關(guān)性為基礎(chǔ)的緩存算法利用,使得LRU、LIRS 和GDFS 根據(jù)時(shí)間局部性來篩選需要緩存的鏡像。由于Docker 鏡像的分層機(jī)制,用戶向注冊表發(fā)出的請求并不是每次都拉取所有鏡像層,而是根據(jù)用戶本地的存儲(chǔ)情況,拉取缺失鏡像層。為了保證鏡像完整性,即使本地存儲(chǔ)所需的全部鏡像層,客戶端依然會(huì)發(fā)送請求取回鏡像元文件進(jìn)行校驗(yàn),這種模式削弱了鏡像層之間的時(shí)間相關(guān)性,因此本文同時(shí)考慮鏡像層的空間相關(guān)性。
當(dāng)用戶上傳鏡像時(shí),注冊表對鏡像計(jì)算得出為manifest 的元數(shù)據(jù)文件,文件包含了例如鏡像大小、默認(rèn)參數(shù)、鏡像層標(biāo)識(shí)等屬性,通過分析鏡像元數(shù)據(jù)文件能精準(zhǔn)地還原鏡像的存儲(chǔ)結(jié)構(gòu)。注冊表的存儲(chǔ)基本單位是鏡像倉庫,每個(gè)倉庫包含了同一應(yīng)用軟件或不同版本操作系統(tǒng)鏡像,整個(gè)倉庫的鏡像層結(jié)構(gòu)呈樹型,處于不同位置的鏡像層與其周邊的鏡像層存在不同的關(guān)聯(lián)度,用戶往往會(huì)拉取一連串相關(guān)鏡像,此時(shí),如何衡量鏡像的關(guān)聯(lián)度并得出未來可能請求的鏡像層成為問題的關(guān)鍵。
LCPA 策略的核心思想是利用鏡像層存儲(chǔ)的空間局部性,建立關(guān)聯(lián)度模型來預(yù)測與未命中請求可能相關(guān)的鏡像層,預(yù)先從后端存儲(chǔ)服務(wù)器取回緩存在注冊表服務(wù)器中。LCPA 主要解決兩個(gè)難點(diǎn),即如何計(jì)算注冊表中未命中鏡像層的相關(guān)鏡像層和如何設(shè)置預(yù)取操作的觸發(fā)點(diǎn)。因此,策略的設(shè)計(jì)思路也合理地分為兩個(gè)部分:一方面是收集并構(gòu)造每個(gè)容器鏡像的結(jié)構(gòu),將同一倉庫的鏡像結(jié)構(gòu)整合起來,依照鏡像層之間的強(qiáng)關(guān)聯(lián)、弱關(guān)聯(lián)和無關(guān)聯(lián)構(gòu)建關(guān)聯(lián)度模型,還需要考慮時(shí)間和頻率等屬性來輔助計(jì)算相關(guān)鏡像層集合。另一方面是算法分析了用戶拉取鏡像的請求流程,雖然部分請求環(huán)節(jié)均可以設(shè)置為預(yù)取的觸發(fā)點(diǎn),為了達(dá)到最好的效果,觸發(fā)點(diǎn)應(yīng)該設(shè)置為每一個(gè)鏡像倉庫中第二個(gè)未命中鏡像層緩存的拉取請求,能夠有效過濾針對鏡像元文件的冗余請求,從而避免了重復(fù)預(yù)取帶來的性能開銷以及緩存污染的危險(xiǎn)。
本策略充分利用注冊表服務(wù)器的存儲(chǔ)資源,通過關(guān)聯(lián)模型確定鏡像層集合并預(yù)取至注冊表,彌補(bǔ)觸發(fā)預(yù)取操作的未命中損失,整體提升緩存命中率,解決用戶拉取鏡像的延遲問題。為了比較效果,算法的緩存替換部分結(jié)合了LRU,針對鏡像層的場景進(jìn)行了改進(jìn),下面介紹LCPA 模擬仿真器的框架。
圖3 是LCPA 策略模擬仿真器的架構(gòu),其中包含工作流和主要模塊,緩存包含著鏡像層和元數(shù)據(jù)文件。三個(gè)核心模塊為鏡像結(jié)構(gòu)提取模塊(layer select extract,LSE)、拉取請求處理模塊(prefetching request handler,PRH)和關(guān)聯(lián)鏡像層計(jì)算模塊(correlation layer calculate,CLC),各自的工作流如下:
(1)LSE 從元數(shù)據(jù)文件中解析出鏡像層之間的結(jié)構(gòu)關(guān)系,整合同一鏡像倉庫的所有鏡像結(jié)構(gòu),并以鍵值對的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)。
Fig.3 Architecture of LCPA simulator圖3 LCPA 模擬仿真器的架構(gòu)圖
(2)PRH 設(shè)置注冊表緩存的預(yù)取觸發(fā)點(diǎn),并將請求信息發(fā)送到CLC。
(3)CLC 通過鏡像層結(jié)構(gòu)關(guān)系和關(guān)聯(lián)度模型計(jì)算出相關(guān)鏡像層集合,向后端拉取注冊表緩存中缺失的鏡像層,實(shí)現(xiàn)預(yù)取以提高請求命中率。
LCPA 策略的核心是通過鏡像層存儲(chǔ)的空間局部性來計(jì)算相關(guān)鏡像層,那么研究鏡像層存儲(chǔ)機(jī)制并收集鏡像層的結(jié)構(gòu)關(guān)系就尤為重要。圖4 表示鏡像層結(jié)構(gòu)以及鏡像的元數(shù)據(jù)文件,鏡像是由被壓縮為tarball 的鏡像層組成的只讀文件系統(tǒng),每一個(gè)鏡像層包含了可執(zhí)行文件、相關(guān)依賴庫和配置文件,并通過基于SHA256 的內(nèi)容尋址算法生成的digest來對其標(biāo)識(shí)。元數(shù)據(jù)文件包含了父鏡像ID、默認(rèn)參數(shù)、創(chuàng)建日期,以及每個(gè)鏡像層的內(nèi)容可尋址標(biāo)識(shí)符等鏡像基本信息,當(dāng)用戶拉取或推送鏡像時(shí),元數(shù)據(jù)文件作為鏡像基礎(chǔ)信息的描述文件被短時(shí)間存入注冊表服務(wù)器。此時(shí),鏡像結(jié)構(gòu)提取模塊通過解析元數(shù)據(jù)文件,按由底向上的存儲(chǔ)順序,將每個(gè)鏡像層的digest 和鏡像層大小與請求到達(dá)時(shí)間戳以字典數(shù)據(jù)結(jié)構(gòu)存入內(nèi)存中,同時(shí)在每個(gè)新增鏡像層的value 中添加值為1的流行度字段,每當(dāng)拉取請求處理模塊處理有效拉取請求,則向?qū)?yīng)鏡像層的流行度字段修改加1,為關(guān)聯(lián)鏡像層預(yù)取模塊提供每個(gè)鏡像層實(shí)時(shí)的流行度。
Fig.4 Docker image stored architecture圖4 Docker鏡像存儲(chǔ)結(jié)構(gòu)
在圖4 的棧式鏡像存儲(chǔ)結(jié)構(gòu)中,最頂部的鏡像層由用戶根據(jù)業(yè)務(wù)需求制作的可寫容器層轉(zhuǎn)化形成,越靠近頂部的鏡像層越能代表整個(gè)鏡像的專用性,越靠近底部包含越多的依賴庫,最底部的鏡像層一般為包含操作系統(tǒng)的基礎(chǔ)鏡像,被不同鏡像共享使用。雖然鏡像層復(fù)用為注冊表節(jié)省存儲(chǔ)空間,但正是因?yàn)檫@種特性,復(fù)用鏡像層比其他鏡像層有更大的概率被拉取,從而形成熱點(diǎn)鏡像層。假設(shè)預(yù)取策略是按照鏡像層被復(fù)用的概率降序排序,每次將較高復(fù)用率的鏡像層預(yù)取回緩存中,這種方法會(huì)存在明顯的缺點(diǎn):
(1)由于每個(gè)鏡像層在緩存隊(duì)列中的存活期是均等的,高復(fù)用率的鏡像層被頻繁預(yù)取并放置于緩存隊(duì)列的前端,使其獲得比其他鏡像層更久的存活期,較低復(fù)用率的鏡像層很容易被替換掉,從而造成緩存污染。
(2)雖然通過保留較底部的鏡像層來保證一定的命中率,但預(yù)取回的鏡像層并沒有和引起預(yù)取操作的未命中鏡像層產(chǎn)生聯(lián)系,且沒有將復(fù)用率低的鏡像層有效轉(zhuǎn)化為有效命中,策略有較大的提升空間。
LCPA 策略的關(guān)聯(lián)度模型克服了上述缺陷,用關(guān)聯(lián)性將鏡像層連接起來,避免高復(fù)用率的鏡像層使注冊表丟失了其他請求命中,同時(shí)達(dá)到精準(zhǔn)預(yù)取的目的,在2.4 節(jié)將詳細(xì)描述。
本模塊負(fù)責(zé)處理用戶拉取鏡像層的請求,并設(shè)置以第二次未命中緩存的請求為預(yù)取策略觸發(fā)點(diǎn)。在傳統(tǒng)Docker 架構(gòu)中,用戶的一次拉取操作需要遍歷的所有組件,包括代理服務(wù)器,請求流程如下:
(1)Docker引擎中守護(hù)進(jìn)程接收到用戶的拉取命令后,向注冊表發(fā)出Get/v2/
(2)守護(hù)進(jìn)程通過對layers 字段校驗(yàn),已經(jīng)存儲(chǔ)于本地的鏡像層不做改動(dòng),對于需要拉取的缺失鏡像層,守護(hù)進(jìn)程發(fā)出Head 請求方法查詢注冊表后端存儲(chǔ)中是否有該鏡像層。
(3)通過Get 請求方法從注冊表服務(wù)器獲得重定向url,通過新url 在后端存儲(chǔ)中取回鏡像層,在本地用sha256 算法進(jìn)行校驗(yàn),以確保鏡像層完整性。
圖5 中請求的多次跳躍很大程度決定了延遲的下限,特別當(dāng)后端存儲(chǔ)服務(wù)器處于高負(fù)載時(shí),性能下降會(huì)極大地影響拉取鏡像的效率。LCPA 策略將一部分鏡像存入注冊表內(nèi)存中,合理利用注冊表的空閑資源以減輕后端存儲(chǔ)服務(wù)器的負(fù)載。同時(shí),拉取請求處理模塊判斷請求命中注冊表緩存并返回鏡像層,相比傳統(tǒng)的請求流程減少了一半的請求跳躍次數(shù),極大減少了高延遲。
Fig.5 An example of http requests sequence of pulling an image圖5 拉取鏡像的http 請求流程
為了保證LCPA 策略的性能,需要在拉取請求處理模塊中設(shè)置合理的預(yù)取觸發(fā)點(diǎn)。過去的研究中一般設(shè)置為整個(gè)流程的首要操作,在此場景下為拉取元數(shù)據(jù)文件的請求,但這種觸發(fā)點(diǎn)有兩個(gè)缺陷:
(1)用戶需要先從注冊表中取回元數(shù)據(jù)文件到本地校驗(yàn),再發(fā)送缺失鏡像層的拉取請求。由于元數(shù)據(jù)文件只保存鏡像的信息,注冊表無法從拉取元數(shù)據(jù)文件的請求中感知用戶本地的存儲(chǔ)狀態(tài),因此這種預(yù)取觸發(fā)點(diǎn)會(huì)導(dǎo)致預(yù)取回的鏡像層與后續(xù)請求所需的鏡像層偏差較大,造成網(wǎng)絡(luò)資源浪費(fèi)的同時(shí),降低了緩存命中率。
(2)通過對注冊表接收到的拉取請求進(jìn)行分析,如圖6 所示,大于50%的拉取請求是針對鏡像層,但位于syd、fra 和lon 三地的注冊表接收到大于55%的請求是拉取元數(shù)據(jù)文件,數(shù)量遠(yuǎn)遠(yuǎn)大于拉取鏡像的請求,這表明部分用戶因?yàn)榫W(wǎng)絡(luò)擁塞或中斷操作,向注冊表重復(fù)發(fā)送了針對鏡像的拉取請求。在這種元數(shù)據(jù)文件和鏡像層關(guān)聯(lián)割裂的場景下,即使Docker客戶端只需一份元數(shù)據(jù)文件即可校驗(yàn)確定所需鏡像層,但冗余觸發(fā)的預(yù)取操作會(huì)導(dǎo)致資源浪費(fèi)。
Fig.6 Distribution of pulling requests in registry of different geographic locations圖6 不同地理位置的注冊表中拉取請求分布
為了克服上述問題,本模塊以第二次未命中的鏡像層拉取請求為預(yù)取觸發(fā)點(diǎn)。首先,以鏡像層拉取請求為依據(jù)解決了缺點(diǎn)2,同時(shí)讓注冊表服務(wù)器感知到用戶端缺失鏡像層的狀態(tài)。其次,注冊表服務(wù)器第一次接收到某個(gè)鏡像倉庫內(nèi)的未命中請求時(shí),沒有前驅(qū)請求可以建立關(guān)聯(lián),無法準(zhǔn)確判斷是否還有后續(xù)請求以及與其他鏡像層的相關(guān)性。最終,結(jié)合接收的第二個(gè)未命中請求,注冊表通過關(guān)聯(lián)度模型得出關(guān)聯(lián)鏡像層集合并從后端存儲(chǔ)中預(yù)先取回,使得未來接收的請求能更多地命中緩存以彌補(bǔ)損失的命中率,提高注冊表性能。
預(yù)取操作包含關(guān)聯(lián)鏡像層的計(jì)算和拉取,核心關(guān)鍵在于如何計(jì)算出用戶未來最可能拉取的鏡像層。過多的預(yù)取鏡像層可能會(huì)造成網(wǎng)絡(luò)擁塞且浪費(fèi)網(wǎng)絡(luò)流量,淘汰緩存中有效的鏡像層,而僅僅拉取較少關(guān)聯(lián)鏡像層又不能達(dá)到較好的預(yù)取性能,同時(shí)浪費(fèi)了注冊表的計(jì)算資源。為了實(shí)現(xiàn)提升LCPA 效果,本模塊利用鏡像層局部性建立關(guān)聯(lián)模型,下面從兩部分介紹:(1)關(guān)聯(lián)規(guī)則,劃分鏡像層之間的關(guān)系;(2)關(guān)聯(lián)模型,計(jì)算相關(guān)鏡像層,同時(shí)校驗(yàn)緩存得出鏡像層預(yù)取集合。
2.4.1 關(guān)聯(lián)規(guī)則
首先,給出關(guān)聯(lián)規(guī)則的相關(guān)基本概念。
定義1鏡像L是其鏡像層組成的集合,即:
Li={l1,l2,l3,…},i=1,2,…,n
鏡像倉庫R存放著同類型版本的所有鏡像,即:
Rj={L1,L2,L3,…},j=1,2,…,n
定義2對于同屬一個(gè)鏡像倉庫R1的鏡像L1和L2,即L1?R1,L2?R1,當(dāng)L1?L2={l1,l2,l3,…}時(shí),l1,l2,l3等為共享鏡像層,則{l1,l2,l3,…}為L1和L2的共享鏡像層集合。對于倉庫R1中的L3鏡像,當(dāng)l3∈L3,l3?L1?L2時(shí),則l3是L3的專用鏡像層。
定義3一個(gè)預(yù)取窗口包含了未命中的拉取請求的生命周期,即:
PWk={p1,p2,p3,…},k=1,2,…,n
注冊表中每個(gè)鏡像倉庫都是應(yīng)用程序或系統(tǒng)鏡像的不同版本所構(gòu)成的鏡像組,由于注冊表接收兩個(gè)連續(xù)的拉取請求可能針對不同鏡像倉庫,設(shè)置一個(gè)預(yù)取窗口不能有效分析被拉取鏡像層之間的關(guān)聯(lián)性。因此,為每一個(gè)鏡像倉庫設(shè)置獨(dú)立預(yù)取窗口PWk,k=1,2,…,n,將拉取請求處理模塊發(fā)送來的未命中請求保存在相應(yīng)的預(yù)取窗口里,以便記錄和查詢請求之間對應(yīng)的鏡像層是否產(chǎn)生關(guān)聯(lián)。
定義4針對鏡像層之間的關(guān)系分為不同程度:強(qiáng)關(guān)聯(lián)、弱關(guān)聯(lián)和無關(guān)聯(lián)。前提條件有預(yù)取窗口PW1={p1,p2,p3,…},其中任意兩個(gè)未命中的請求對應(yīng)的鏡像層集合為Lx={l1,l2},則描述如下:
(1)若Lx?Li,對于?Lj(i≠j),都有Lx-Lj=?,則Lx中的鏡像層l1和鏡像層l2是強(qiáng)關(guān)聯(lián),例如圖7中鏡像倉庫1 的2 號鏡像與6 號鏡像,Lx的強(qiáng)關(guān)聯(lián)鏡像層集合為Li-(Li?Lj)-Lx。
(2)若Lx?Li,對于?Lj(i≠j),都有Lx-Lj≠?,則Lx中的鏡像層l1和鏡像層l2是弱關(guān)聯(lián),例如圖7中鏡像倉庫2 的1 號鏡像與5 號鏡像,Lx的弱關(guān)聯(lián)鏡像層集合為(Li?Lj)-Lx。
(3)對于?Li,都有Lx?Li,即Lx中的兩個(gè)鏡像層分別為不同鏡像的專用鏡像層,則鏡像層l1和鏡像層l2是無關(guān)聯(lián),例如圖7 中鏡像倉庫2 的15 號鏡像與10 號鏡像。
Fig.7 Storage structure of repository in registry圖7 鏡像倉庫在注冊表中的存儲(chǔ)結(jié)構(gòu)
2.4.2 關(guān)聯(lián)模型
每一個(gè)鏡像倉庫的預(yù)取窗口按照時(shí)間順序保存若干歷史請求,新進(jìn)請求會(huì)與前驅(qū)請求對應(yīng)的鏡像層產(chǎn)生不同程度的關(guān)聯(lián)。通過將鏡像結(jié)構(gòu)提取模塊收集的鏡像結(jié)構(gòu)信息代入關(guān)聯(lián)規(guī)則判斷關(guān)聯(lián)程度,針對不同關(guān)聯(lián)程度,關(guān)聯(lián)模型分別設(shè)置計(jì)算方法得到相關(guān)鏡像層集合,分析如下:
(1)新請求與歷史請求對應(yīng)的鏡像層是強(qiáng)關(guān)聯(lián)時(shí),表明后續(xù)請求序列都傾向于拉取其周邊的鏡像層,通過關(guān)聯(lián)規(guī)則可計(jì)算出新請求對應(yīng)鏡像層所產(chǎn)生的強(qiáng)關(guān)聯(lián)鏡像層集合。
(2)新請求與歷史請求對應(yīng)的鏡像層是弱關(guān)聯(lián)時(shí),由關(guān)聯(lián)規(guī)則可知,新請求對應(yīng)鏡像層被多個(gè)鏡像復(fù)用,無法根據(jù)此請求判斷目標(biāo)鏡像,將其弱關(guān)聯(lián)鏡像層全部拉取可能會(huì)造成資源浪費(fèi),同時(shí)加重網(wǎng)絡(luò)延遲。本文考慮鏡像的其他屬性來精準(zhǔn)計(jì)算關(guān)聯(lián)程度C,如式(1)所示:其中,d表示新請求和歷史請求對應(yīng)鏡像層的間隔鏡像層數(shù)量;Plast表示歷史請求對應(yīng)鏡像層的流行度;Pnow表示新請求對應(yīng)鏡像層的流行度;Tlast表示歷史請求到達(dá)的時(shí)間戳;Tnow表示新請求到達(dá)的時(shí)間戳。
通過鏡像結(jié)構(gòu)提取模塊收集的鏡像層信息代入公式計(jì)算關(guān)聯(lián)程度C,在鏡像倉庫的結(jié)構(gòu)中,選取從新請求對應(yīng)鏡像層至歷史請求對應(yīng)鏡像層方向的C個(gè)鏡像層作為弱關(guān)聯(lián)鏡像層集合。
(3)新請求與歷史請求對應(yīng)的鏡像層無關(guān)聯(lián)時(shí),即新請求無法對要預(yù)取的鏡像層提供信息,則清除該預(yù)取窗口中所有歷史請求,僅保留最新請求,為后繼請求提供關(guān)聯(lián)性參考。
由于注冊表服務(wù)器內(nèi)存中緩存了鏡像層,從關(guān)聯(lián)模型中得到的相關(guān)鏡像層集合并非全部拉取,需要查詢緩存數(shù)據(jù),得出緩存缺失鏡像層的預(yù)取集合,從存儲(chǔ)后端取回注冊表服務(wù)器。
LCPA 策略的算法如算法1 所示。
為了進(jìn)一步驗(yàn)證緩存預(yù)取策略LCPA 的有效性,在仿真模擬器上實(shí)現(xiàn)了LRU、LIRS、GDFS 和LPA 四種算法,由于預(yù)取策略是對緩存策略的擴(kuò)展,LCPA和LPA 均以LRU 為緩存替換算法。實(shí)驗(yàn)采用真實(shí)的注冊表工作負(fù)載trace 數(shù)據(jù)集進(jìn)行測試,分別在不同緩存規(guī)模下測試預(yù)取策略相對緩存策略的提升的緩存命中率和延遲節(jié)省率,以及相比其他預(yù)取算法提高的效果。
本文實(shí)驗(yàn)采用Intel Core i7-6700 的CPU,24 GB DDR3 RAM,和7 200 r/min 500 GB SATA 硬盤,并安裝操作系統(tǒng)CentOS 7.3,Linux 內(nèi)核版本是3.10.0,Docker版本是1.12.0,對應(yīng)的API版本為1.27,采用的編譯語言python 版本為3.5.2。實(shí)驗(yàn)環(huán)境具體參數(shù)如表1 所示。
Table 1 Parameters of experiment environment表1 實(shí)驗(yàn)環(huán)境參數(shù)
使用SNIA trace data files 來測試LCPA 的性能,SNIA trace data files 是從IBM 云注冊表中收集的真實(shí)工作負(fù)載數(shù)據(jù)集,其中包括從2017 年6 月20 日到2017 年2 月9 日間,5 個(gè)不同地理位置的注冊表(另外兩個(gè)是IBM 內(nèi)部使用的注冊表)處理的總計(jì)超過3 800 萬個(gè)請求,總數(shù)量傳輸超過181.3 TB,由于原始日志中部分信息不能公開,經(jīng)過刪除冗余字段并匿名處理后,數(shù)據(jù)集總大小為22.4 GB。數(shù)據(jù)集由http請求組成,每一個(gè)請求都有固定的屬性,包括處理請求的注冊表服務(wù)器的主機(jī)號、請求的響應(yīng)時(shí)間、HTTP 請求方式、用戶IP 地址、請求的URL、用戶使用的Docker 版本、請求狀態(tài)、請求數(shù)據(jù)大小、請求id、請求時(shí)間戳。由于本文提出的預(yù)取策略僅涉及元數(shù)據(jù)文件和鏡像層的操作,對數(shù)據(jù)集處理后僅保留數(shù)據(jù)的拉取和上傳請求,表2 展示本實(shí)驗(yàn)采用的真實(shí)負(fù)載的特性。
Table 2 Characteristics of real workload used in experiments表2 本實(shí)驗(yàn)采用的真實(shí)負(fù)載的特性
為了更好地評估算法的性能,本研究使用請求命中率和延遲節(jié)省率兩個(gè)指標(biāo)。
定義5請求命中率(hit ratio)是指在注冊表服務(wù)器緩存中命中的鏡像層拉取請求占鏡像層拉取請求總數(shù)的百分比。
定義6延遲節(jié)省率(latency saving ratio)。從用戶發(fā)出拉取鏡像請求到所有鏡像被下載到本地的過程中,設(shè)Tregistry為命中注冊表服務(wù)器緩存并拉取鏡像的延遲,Tobject為根據(jù)重定向url 到對象存儲(chǔ)服務(wù)器拉取鏡像的延遲,則計(jì)算延遲節(jié)省率如式(2)所示:
3.3.1 數(shù)據(jù)集命中率測試分析
Fig.8 Hit ratio for LRU,LIRS,GDFS and LCPA圖8 LRU、LIRS、GDFS 和LCPA 算法的請求命中率
圖8 給出的是LCPA 策略與3 種緩存算法LRU、LIRS 和GDFS 在不同數(shù)據(jù)集下實(shí)現(xiàn)的請求命中率,設(shè)置的緩存范圍從50 MB 到12 GB,靈活地展示算法在注冊表資源變動(dòng)時(shí)的性能。
實(shí)驗(yàn)的測試結(jié)果表明:首先,所有算法在不同的注冊表trace 數(shù)據(jù)集上都受到請求順序的影響,例如GDFS 算法在dev 數(shù)據(jù)集上取得了較高的命中率,但在dal 和lon 數(shù)據(jù)集中卻非常低。從橫向上看,隨著緩存容量的增大,每種算法的命中率都有不同程度的提升,其中LRU 和LIRS 在dev 和pre 數(shù)據(jù)集的測試中從極低的命中率快速提升,這是因?yàn)閮蓚€(gè)trace 是IBM 公司內(nèi)部使用的注冊表數(shù)據(jù)集,鏡像種類不夠豐富,注冊表服務(wù)器能緩存大部分熱點(diǎn)鏡像。從縱向上看,LRU 算法由于自身的各種缺陷,平均命中率是最低的,但是在部分?jǐn)?shù)據(jù)集中能與LIRS 算法的命中率相似。GDFS 綜合考慮請求鏡像層的大小、獲取成本等屬性,在請求命中率這個(gè)指標(biāo)中優(yōu)于LRU 和LIRS。最后,本文提出的LCPA 算法在不同的trace數(shù)據(jù)集中的命中率均處于領(lǐng)先位置,總體表現(xiàn)優(yōu)于其他緩存算法,能夠在較小緩存空間中根據(jù)關(guān)聯(lián)規(guī)則預(yù)得到很好的命中率,算法性能平均提升了12%~29%不等。
3.3.2 數(shù)據(jù)集延遲節(jié)省率測試分析
Fig.9 Latency saving ratio for LRU,LIRS,GDFS and LCPA圖9 LRU、LIRS、GDFS 和LCPA 算法的延遲節(jié)省率
圖9 給出了LRU、LIRS、GDFS 和LCPA 算法的延遲節(jié)省率的實(shí)驗(yàn)結(jié)果。從結(jié)果來看,LCPA 算法均比其他算法要節(jié)省更多的延遲。結(jié)合請求命中率來分析,LCPA 在stage 和dal數(shù)據(jù)集中測試時(shí),當(dāng)緩存容量較小,40%左右的請求命中率獲取了不到8%節(jié)省延遲率,原因是這兩個(gè)數(shù)據(jù)集中存在的較小熱點(diǎn)鏡像層在真實(shí)拉取時(shí)均沒有產(chǎn)生較高的延遲,同時(shí)在緩存中的生命周期較短,沒有較大節(jié)省延遲的空間,隨著緩存大小的增加,延遲節(jié)省率會(huì)迅速增加。綜合所有數(shù)據(jù)集結(jié)果,當(dāng)注冊表服務(wù)器資源較少時(shí),四種算法為用戶節(jié)省的延遲相差無幾,但LCPA 總體表現(xiàn)優(yōu)于其他算法,延遲節(jié)省率平均提升21.1%~49.4%。
3.3.3 與LPA 預(yù)取算法比較分析
LPA 算法[8]的基本思想是將注冊表服務(wù)器接收到的PUT 請求信息記錄在查找表中,包含請求中的鏡像層信息、請求到達(dá)時(shí)間以及客戶端地址,當(dāng)注冊表在設(shè)置的時(shí)間閾值內(nèi)從客戶端收到GET manifest請求時(shí),檢查查找表中是否包含manifest 指定的鏡像層,如果是非上傳主機(jī)發(fā)出的請求命中,則從后端對象存儲(chǔ)中實(shí)施預(yù)取。
為了驗(yàn)證兩種預(yù)取算法的性能,實(shí)驗(yàn)選取了7 個(gè)數(shù)據(jù)中心的數(shù)據(jù)集來測試兩種算法的請求命中情況,由于LPA 算法中有兩個(gè)時(shí)間參數(shù)控制鏡像在注冊表中的緩存時(shí)間,使得緩存中鏡像總大小處于變化的數(shù)值,于是對參數(shù)進(jìn)行調(diào)整,盡量使得注冊表服務(wù)器中的緩存處于飽和狀態(tài),結(jié)果如圖10 所示。
Fig.10 Hit ratio for LCPA and LPA圖10 LCPA 與LPA 算法的請求命中率
從圖10 中可以看出,LPA 算法在dev 和prestage數(shù)據(jù)集中表現(xiàn)出極低命中率,這是因?yàn)檫@兩個(gè)數(shù)據(jù)集來自IBM 內(nèi)部開發(fā)和測試所使用的注冊表,注冊表中的鏡像分布較為平均,沒有流行度非常高的鏡像,所以被預(yù)取回注冊表的鏡像層在下一次拉取該鏡像層的請求到來時(shí),其會(huì)在規(guī)定大小的緩存中被快速替換導(dǎo)致未命中,而LCPA 算法在這兩個(gè)數(shù)據(jù)集中的高命中率表明了通過關(guān)聯(lián)性去預(yù)判未來可能被請求命中的鏡像層更加精確。LCPA 的請求命中率總是優(yōu)于LPA,LCPA 的平均命中率是60.3%,最高達(dá)72.8%,比LPA 的平均命中率提升25.6%。
圖11 的實(shí)驗(yàn)結(jié)果表明,與LPA 算法相比,LCPA在7 個(gè)trace 數(shù)據(jù)集中的延遲優(yōu)化效果更好,平均延遲節(jié)省率提高了43.3%。由表2 可知stage 和dal 數(shù)據(jù)集中鏡像的平均拉取延遲較大,但相比其他數(shù)據(jù)集,LCPA 策略的優(yōu)化效果不明顯,這是因?yàn)長CPA 不緩存某些體積巨大的鏡像,則損失了部分可以節(jié)約的拉取延遲。pre 和syd 數(shù)據(jù)集中鏡像的平均鏡像大小和平均拉取延遲均較小,即使LPA 算法的命中率與LCPA 較大,但延遲節(jié)省率的差距有著明顯的縮小。
Fig.11 Latency saving ratio for LCPA and LPA圖11 LCPA 與LPA 算法的延遲節(jié)省率
兩個(gè)實(shí)驗(yàn)結(jié)果不僅體現(xiàn)了LCPA 算法預(yù)測的穩(wěn)定性,同時(shí)也體現(xiàn)了現(xiàn)有算法預(yù)測請求鏡像的不夠精準(zhǔn)以及LCPA 策略在Docker注冊表中的研究意義,突出了LCPA 策略的創(chuàng)新價(jià)值。
Docker 作為云計(jì)算領(lǐng)域中的容器管理工具,具有很強(qiáng)的市場前景。本文針對用戶啟動(dòng)容器延遲逐漸增加的問題,對Docker 生態(tài)中的注冊表服務(wù)器進(jìn)行改進(jìn),設(shè)計(jì)基于鏡像關(guān)聯(lián)的Docker 注冊表緩存預(yù)取策略LCPA。仿真實(shí)驗(yàn)結(jié)果表明,與LRU、LIRS、GDFS 等緩存算法相比,LCPA 通過主動(dòng)式預(yù)取有效提升了注冊表性能,在不同數(shù)據(jù)集中均實(shí)現(xiàn)了較好的請求命中率。與現(xiàn)有的預(yù)取策略LPA 相比,克服了LPA 算法尋找關(guān)聯(lián)性的局限性,并通過關(guān)聯(lián)模型計(jì)算相關(guān)鏡像層集合進(jìn)行預(yù)取,從Docker 注冊表服務(wù)器返回鏡像至客戶端節(jié)省了大量延遲,從而加快了容器啟動(dòng)效率。