張 晨,鄧玉輝,2+
1.暨南大學信息科學技術學院計算機科學系,廣州 510632
2.中國科學院計算技術研究所計算機體系結構國家重點實驗室,北京 100190
在過去的十年中,Xen、VMware、KVM 和Hyper-V是大多數云計算系統使用的虛擬機管理程序,為云計算在共享池中快速配置和釋放計算機資源提供支撐。隨著操作系統虛擬化的快速發展,其較強的兼容性和較低的資源開銷吸引Google 和IBM 等企業使用容器[1]來創建隔離的虛擬環境[2]。Docke 是Linux平臺上的一款輕量級容器管理引擎,不僅具有很好的性能優勢和安全性,而且能幫助用戶提升持續集成/持續交付(continuous integration/continuous delivery,CI/CD)的效率。例如,ING 是全球十大金融服務公司之一,通過使用Docker 部署高度自動化的CD 流水線,為基礎設施資源節約了50%的開銷(https://www.docker.com/blog/docker-selected-as-gartner-cool-vendorin-devops)。在業界對容器技術強烈的需求導向之下,越來越多的企業在生產環境中使用Docker 進行大規模任務部署。
在實際項目中,企業通常利用Docker 提供的注冊表服務來解決容器鏡像的分發和存儲問題。目前,市場上有不同云服務商提供的Docker 注冊表實例,如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/)等,注冊表提供一套REST(representational state transfer)接口用于Docker客戶端向注冊表自由發布鏡像并供他人下載。圖1 是IBM Cloud Registry 的部署架構,負載均衡器將用戶請求分配到不同地區的注冊表服務器中,注冊表服務器均采用對象存儲服務(例如Amazon S3),無沖突地寫入共同的后端存儲[3-4]。據統計,大型容器公共注冊表至少存儲數百TB 數據,每天增加1 500 個公共鏡像存儲庫[5],并且私人鏡像存儲庫也在不斷更新。有工作表明,從此類規模的注冊表中拉取鏡像的時間占容器總啟動時間的76%[6]。

Fig.1 IBM Cloud Registry architecture圖1 IBM Cloud Registry 架構
在傳統Docker 注冊表架構中,注冊表由負載均衡器、注冊表服務器、對象存儲服務器等組件構成,在用戶發出構建容器指令后,Docker 客戶端發出請求會遍歷所有組件。圖2 展示了分析IBM 注冊表trace 數據集得出用戶拉取鏡像層的延遲分布情況,大約88%的鏡像層拉取延遲小于5 s,拉取單個鏡像層的最長延遲超過2 min。由于容器啟動需要收集完整鏡像,通常鏡像由數十個鏡像層組成,且Docker 客戶端最大并行拉取3 個鏡像層,在大型公共容器注冊表的場景下,拉取鏡像請求的高延遲已經大大削弱容器快速啟動的特性,因此減少拉取鏡像延遲成為研究的熱點。

Fig.2 Distribution of image layes pulling delay in IBM Cloud Registry圖2 通過IBM 注冊表拉取鏡像層的延遲分布
目前,國內針對容器技術開展了很多研究,例如通過分析以Docker 為代表的自動化工具在實踐中出現的問題,深入探討Docker 對中國DevOps 的影響并提出相關建議[7],有的研究從技術架構分析容器技術特點,并從容器實例層、管理層和內核資源層梳理操作系統虛擬化的現狀[8],有的研究提出一種服務質量敏感的,基于前饋的容器資源彈性供給方法,解決傳統虛擬化環境中資源供給時效差和難以應對負載突變的問題[9]。國外研究聚焦優化鏡像拉取延遲問題,如Harter 等人提出的Slacker[6],該方案在拉取鏡像的最初時刻僅檢索并傳輸啟動容器的最小數據集,然后采用lazy cloning和lazy propagation的方式從共享NFS(network file system)存儲中提取剩余需要的鏡像數據,從而縮短了容器的啟動時間,但這種方案需要注冊表與客戶端保持持續連接,協作要求較高。Nathan等人[10]提出了一種在一組節點之間使用P2P 協議協作管理Docker 鏡像的系統——CoMICon,該系統在接收到用戶請求時會優先從鄰近的節點獲取缺失的層,然后查詢遠程注冊表,并行拉取鏡像的方法能有效縮短網絡傳輸延遲,加快容器的啟動與部署。
由上述分析發現,現有的研究工作對于中小規模組織中容器部署場景的優化已經相當成熟,因此從網絡或存儲驅動等方面對Docker 做出改進的空間有限?;诂F有云服務商重新設計注冊表架構的背景下,本文以注冊表服務器組件為核心優化點,從Docker 鏡像結構和注冊表功能出發,提出一種基于鏡像層相關性的緩存預取方案,將部分體積較小的熱點鏡像層預先從后端取回,緩存至注冊表服務器內存中,當用戶請求命中時即可拉取鏡像。本文方案提高了注冊表內存資源利用率的同時,減少請求跳數和后端I/O 壓力,縮短用戶拉取鏡像的流程從而隱藏耗費的網絡延遲,最終加快容器啟動速度。這項工作的主要貢獻概括如下:
(1)通過研究鏡像層存儲機制,利用鏡像層的空間局部性設計關聯模型,最終實現一種基于鏡像層關聯的Docker 注冊表緩存預取策略LCPA(layer correlation prefetch algorithm)。
(2)在本文方法中,實現由鏡像結構提取模塊、拉取請求處理模塊和關聯鏡像層計算模塊為核心的模擬仿真器,并利用基于真實負載下的Docker 數據集進行實驗。
(3)驗證了LCPA 策略的正確性和有效性。實驗結果表明,與LRU(least recently used)、LIRS(low interreference recency set replacement policy)、GDFS(greedy dual frequency size)和LPA(least prefetching algorithm)算法相比,本文提出的預取策略在緩存命中率和節省延遲方面有著明顯的性能提高。
隨著對緩存管理的不斷研究,針對不同工作負載的緩存替換算法相繼提出,通常劃分為以LRU[11]、LFU(least frequently used)[12]、SLRU(size least recently used)[13]、GD(greedy dual)[14]、RAND 為代表的五類算法。雖然LRU 在現有的各種應用場景中都能發揮比較穩定的性能,但依舊存在一些不足,例如LRU 對再次訪問的數據會放置隊首,重置它的緩存周期,從而帶來“緩存污染”,同時缺少對數據多維度的考量,捕捉數據體積較大的文件會導致命中率降低,無法適應局部性較弱的訪問模式。
LIRS 是一種突破LRU 限制的算法,使用重用距離作為緩存替換的依據,有效避免了LRU 中冷熱數據相同的緩存周期,提高了對未來可能訪問數據的命中。LIRS 將緩存劃分成LIR(low inter-reference)堆棧和HIR(high inter-reference)堆棧,將空間較小的HIR堆棧作為二級緩存,捕捉重用距離小的數據并送入LIR 棧,替換掉長時間沒有重復被命中的數據。這個特性同樣給算法帶來不足,一個冷數據在HIR 棧中短時間命中兩次之后再無訪問,則該數據將在LIR 棧中經歷全部數據流出后才被替換,造成一定程度的“緩存污染”。
GDFS 算法的核心是利用數據的大小、訪問頻率以及訪問代價建立老化函數,并給參數分配不同的權值,最終給每一個數據計算出相應的特征值??紤]到時間局部性,老化因子是隨時間而增大的,短期內命中的數據特征值較大且更新在緩存隊列中的位置。GDFS 根據訪問情況每次淘汰掉特征值最小的數據,但算法并不能跟隨自適應工作負載的變化,向公式添加新的適應性參數會提高算法復雜性,帶來較高的性能開銷。
預取技術是提高云存儲系統性能的重要研究方向,現代數據中心使用分布式內存緩存服務器(https://memcached.org/,https://redis.io/)[15]來提高數據庫查詢性能,同時結合緩存和預取[16-17]技術能顯著地提高緩存命中率。
注冊表通常會將請求信息存儲在日志中,分析日志可得出對鏡像操作的請求信息,例如請求時間、響應時間、用戶IP、HTTP 請求方法等,這些信息主要被以時間相關性為基礎的緩存算法利用,使得LRU、LIRS 和GDFS 根據時間局部性來篩選需要緩存的鏡像。由于Docker 鏡像的分層機制,用戶向注冊表發出的請求并不是每次都拉取所有鏡像層,而是根據用戶本地的存儲情況,拉取缺失鏡像層。為了保證鏡像完整性,即使本地存儲所需的全部鏡像層,客戶端依然會發送請求取回鏡像元文件進行校驗,這種模式削弱了鏡像層之間的時間相關性,因此本文同時考慮鏡像層的空間相關性。
當用戶上傳鏡像時,注冊表對鏡像計算得出為manifest 的元數據文件,文件包含了例如鏡像大小、默認參數、鏡像層標識等屬性,通過分析鏡像元數據文件能精準地還原鏡像的存儲結構。注冊表的存儲基本單位是鏡像倉庫,每個倉庫包含了同一應用軟件或不同版本操作系統鏡像,整個倉庫的鏡像層結構呈樹型,處于不同位置的鏡像層與其周邊的鏡像層存在不同的關聯度,用戶往往會拉取一連串相關鏡像,此時,如何衡量鏡像的關聯度并得出未來可能請求的鏡像層成為問題的關鍵。
LCPA 策略的核心思想是利用鏡像層存儲的空間局部性,建立關聯度模型來預測與未命中請求可能相關的鏡像層,預先從后端存儲服務器取回緩存在注冊表服務器中。LCPA 主要解決兩個難點,即如何計算注冊表中未命中鏡像層的相關鏡像層和如何設置預取操作的觸發點。因此,策略的設計思路也合理地分為兩個部分:一方面是收集并構造每個容器鏡像的結構,將同一倉庫的鏡像結構整合起來,依照鏡像層之間的強關聯、弱關聯和無關聯構建關聯度模型,還需要考慮時間和頻率等屬性來輔助計算相關鏡像層集合。另一方面是算法分析了用戶拉取鏡像的請求流程,雖然部分請求環節均可以設置為預取的觸發點,為了達到最好的效果,觸發點應該設置為每一個鏡像倉庫中第二個未命中鏡像層緩存的拉取請求,能夠有效過濾針對鏡像元文件的冗余請求,從而避免了重復預取帶來的性能開銷以及緩存污染的危險。
本策略充分利用注冊表服務器的存儲資源,通過關聯模型確定鏡像層集合并預取至注冊表,彌補觸發預取操作的未命中損失,整體提升緩存命中率,解決用戶拉取鏡像的延遲問題。為了比較效果,算法的緩存替換部分結合了LRU,針對鏡像層的場景進行了改進,下面介紹LCPA 模擬仿真器的框架。
圖3 是LCPA 策略模擬仿真器的架構,其中包含工作流和主要模塊,緩存包含著鏡像層和元數據文件。三個核心模塊為鏡像結構提取模塊(layer select extract,LSE)、拉取請求處理模塊(prefetching request handler,PRH)和關聯鏡像層計算模塊(correlation layer calculate,CLC),各自的工作流如下:
(1)LSE 從元數據文件中解析出鏡像層之間的結構關系,整合同一鏡像倉庫的所有鏡像結構,并以鍵值對的數據結構存儲。

Fig.3 Architecture of LCPA simulator圖3 LCPA 模擬仿真器的架構圖
(2)PRH 設置注冊表緩存的預取觸發點,并將請求信息發送到CLC。
(3)CLC 通過鏡像層結構關系和關聯度模型計算出相關鏡像層集合,向后端拉取注冊表緩存中缺失的鏡像層,實現預取以提高請求命中率。
LCPA 策略的核心是通過鏡像層存儲的空間局部性來計算相關鏡像層,那么研究鏡像層存儲機制并收集鏡像層的結構關系就尤為重要。圖4 表示鏡像層結構以及鏡像的元數據文件,鏡像是由被壓縮為tarball 的鏡像層組成的只讀文件系統,每一個鏡像層包含了可執行文件、相關依賴庫和配置文件,并通過基于SHA256 的內容尋址算法生成的digest來對其標識。元數據文件包含了父鏡像ID、默認參數、創建日期,以及每個鏡像層的內容可尋址標識符等鏡像基本信息,當用戶拉取或推送鏡像時,元數據文件作為鏡像基礎信息的描述文件被短時間存入注冊表服務器。此時,鏡像結構提取模塊通過解析元數據文件,按由底向上的存儲順序,將每個鏡像層的digest 和鏡像層大小與請求到達時間戳以字典數據結構存入內存中,同時在每個新增鏡像層的value 中添加值為1的流行度字段,每當拉取請求處理模塊處理有效拉取請求,則向對應鏡像層的流行度字段修改加1,為關聯鏡像層預取模塊提供每個鏡像層實時的流行度。

Fig.4 Docker image stored architecture圖4 Docker鏡像存儲結構
在圖4 的棧式鏡像存儲結構中,最頂部的鏡像層由用戶根據業務需求制作的可寫容器層轉化形成,越靠近頂部的鏡像層越能代表整個鏡像的專用性,越靠近底部包含越多的依賴庫,最底部的鏡像層一般為包含操作系統的基礎鏡像,被不同鏡像共享使用。雖然鏡像層復用為注冊表節省存儲空間,但正是因為這種特性,復用鏡像層比其他鏡像層有更大的概率被拉取,從而形成熱點鏡像層。假設預取策略是按照鏡像層被復用的概率降序排序,每次將較高復用率的鏡像層預取回緩存中,這種方法會存在明顯的缺點:
(1)由于每個鏡像層在緩存隊列中的存活期是均等的,高復用率的鏡像層被頻繁預取并放置于緩存隊列的前端,使其獲得比其他鏡像層更久的存活期,較低復用率的鏡像層很容易被替換掉,從而造成緩存污染。
(2)雖然通過保留較底部的鏡像層來保證一定的命中率,但預取回的鏡像層并沒有和引起預取操作的未命中鏡像層產生聯系,且沒有將復用率低的鏡像層有效轉化為有效命中,策略有較大的提升空間。
LCPA 策略的關聯度模型克服了上述缺陷,用關聯性將鏡像層連接起來,避免高復用率的鏡像層使注冊表丟失了其他請求命中,同時達到精準預取的目的,在2.4 節將詳細描述。
本模塊負責處理用戶拉取鏡像層的請求,并設置以第二次未命中緩存的請求為預取策略觸發點。在傳統Docker 架構中,用戶的一次拉取操作需要遍歷的所有組件,包括代理服務器,請求流程如下:
(1)Docker引擎中守護進程接收到用戶的拉取命令后,向注冊表發出Get/v2/
(2)守護進程通過對layers 字段校驗,已經存儲于本地的鏡像層不做改動,對于需要拉取的缺失鏡像層,守護進程發出Head 請求方法查詢注冊表后端存儲中是否有該鏡像層。
(3)通過Get 請求方法從注冊表服務器獲得重定向url,通過新url 在后端存儲中取回鏡像層,在本地用sha256 算法進行校驗,以確保鏡像層完整性。
圖5 中請求的多次跳躍很大程度決定了延遲的下限,特別當后端存儲服務器處于高負載時,性能下降會極大地影響拉取鏡像的效率。LCPA 策略將一部分鏡像存入注冊表內存中,合理利用注冊表的空閑資源以減輕后端存儲服務器的負載。同時,拉取請求處理模塊判斷請求命中注冊表緩存并返回鏡像層,相比傳統的請求流程減少了一半的請求跳躍次數,極大減少了高延遲。

Fig.5 An example of http requests sequence of pulling an image圖5 拉取鏡像的http 請求流程
為了保證LCPA 策略的性能,需要在拉取請求處理模塊中設置合理的預取觸發點。過去的研究中一般設置為整個流程的首要操作,在此場景下為拉取元數據文件的請求,但這種觸發點有兩個缺陷:
(1)用戶需要先從注冊表中取回元數據文件到本地校驗,再發送缺失鏡像層的拉取請求。由于元數據文件只保存鏡像的信息,注冊表無法從拉取元數據文件的請求中感知用戶本地的存儲狀態,因此這種預取觸發點會導致預取回的鏡像層與后續請求所需的鏡像層偏差較大,造成網絡資源浪費的同時,降低了緩存命中率。
(2)通過對注冊表接收到的拉取請求進行分析,如圖6 所示,大于50%的拉取請求是針對鏡像層,但位于syd、fra 和lon 三地的注冊表接收到大于55%的請求是拉取元數據文件,數量遠遠大于拉取鏡像的請求,這表明部分用戶因為網絡擁塞或中斷操作,向注冊表重復發送了針對鏡像的拉取請求。在這種元數據文件和鏡像層關聯割裂的場景下,即使Docker客戶端只需一份元數據文件即可校驗確定所需鏡像層,但冗余觸發的預取操作會導致資源浪費。

Fig.6 Distribution of pulling requests in registry of different geographic locations圖6 不同地理位置的注冊表中拉取請求分布
為了克服上述問題,本模塊以第二次未命中的鏡像層拉取請求為預取觸發點。首先,以鏡像層拉取請求為依據解決了缺點2,同時讓注冊表服務器感知到用戶端缺失鏡像層的狀態。其次,注冊表服務器第一次接收到某個鏡像倉庫內的未命中請求時,沒有前驅請求可以建立關聯,無法準確判斷是否還有后續請求以及與其他鏡像層的相關性。最終,結合接收的第二個未命中請求,注冊表通過關聯度模型得出關聯鏡像層集合并從后端存儲中預先取回,使得未來接收的請求能更多地命中緩存以彌補損失的命中率,提高注冊表性能。
預取操作包含關聯鏡像層的計算和拉取,核心關鍵在于如何計算出用戶未來最可能拉取的鏡像層。過多的預取鏡像層可能會造成網絡擁塞且浪費網絡流量,淘汰緩存中有效的鏡像層,而僅僅拉取較少關聯鏡像層又不能達到較好的預取性能,同時浪費了注冊表的計算資源。為了實現提升LCPA 效果,本模塊利用鏡像層局部性建立關聯模型,下面從兩部分介紹:(1)關聯規則,劃分鏡像層之間的關系;(2)關聯模型,計算相關鏡像層,同時校驗緩存得出鏡像層預取集合。
2.4.1 關聯規則
首先,給出關聯規則的相關基本概念。
定義1鏡像L是其鏡像層組成的集合,即:
Li={l1,l2,l3,…},i=1,2,…,n
鏡像倉庫R存放著同類型版本的所有鏡像,即:
Rj={L1,L2,L3,…},j=1,2,…,n
定義2對于同屬一個鏡像倉庫R1的鏡像L1和L2,即L1?R1,L2?R1,當L1?L2={l1,l2,l3,…}時,l1,l2,l3等為共享鏡像層,則{l1,l2,l3,…}為L1和L2的共享鏡像層集合。對于倉庫R1中的L3鏡像,當l3∈L3,l3?L1?L2時,則l3是L3的專用鏡像層。
定義3一個預取窗口包含了未命中的拉取請求的生命周期,即:
PWk={p1,p2,p3,…},k=1,2,…,n
注冊表中每個鏡像倉庫都是應用程序或系統鏡像的不同版本所構成的鏡像組,由于注冊表接收兩個連續的拉取請求可能針對不同鏡像倉庫,設置一個預取窗口不能有效分析被拉取鏡像層之間的關聯性。因此,為每一個鏡像倉庫設置獨立預取窗口PWk,k=1,2,…,n,將拉取請求處理模塊發送來的未命中請求保存在相應的預取窗口里,以便記錄和查詢請求之間對應的鏡像層是否產生關聯。
定義4針對鏡像層之間的關系分為不同程度:強關聯、弱關聯和無關聯。前提條件有預取窗口PW1={p1,p2,p3,…},其中任意兩個未命中的請求對應的鏡像層集合為Lx={l1,l2},則描述如下:
(1)若Lx?Li,對于?Lj(i≠j),都有Lx-Lj=?,則Lx中的鏡像層l1和鏡像層l2是強關聯,例如圖7中鏡像倉庫1 的2 號鏡像與6 號鏡像,Lx的強關聯鏡像層集合為Li-(Li?Lj)-Lx。
(2)若Lx?Li,對于?Lj(i≠j),都有Lx-Lj≠?,則Lx中的鏡像層l1和鏡像層l2是弱關聯,例如圖7中鏡像倉庫2 的1 號鏡像與5 號鏡像,Lx的弱關聯鏡像層集合為(Li?Lj)-Lx。
(3)對于?Li,都有Lx?Li,即Lx中的兩個鏡像層分別為不同鏡像的專用鏡像層,則鏡像層l1和鏡像層l2是無關聯,例如圖7 中鏡像倉庫2 的15 號鏡像與10 號鏡像。

Fig.7 Storage structure of repository in registry圖7 鏡像倉庫在注冊表中的存儲結構
2.4.2 關聯模型
每一個鏡像倉庫的預取窗口按照時間順序保存若干歷史請求,新進請求會與前驅請求對應的鏡像層產生不同程度的關聯。通過將鏡像結構提取模塊收集的鏡像結構信息代入關聯規則判斷關聯程度,針對不同關聯程度,關聯模型分別設置計算方法得到相關鏡像層集合,分析如下:
(1)新請求與歷史請求對應的鏡像層是強關聯時,表明后續請求序列都傾向于拉取其周邊的鏡像層,通過關聯規則可計算出新請求對應鏡像層所產生的強關聯鏡像層集合。
(2)新請求與歷史請求對應的鏡像層是弱關聯時,由關聯規則可知,新請求對應鏡像層被多個鏡像復用,無法根據此請求判斷目標鏡像,將其弱關聯鏡像層全部拉取可能會造成資源浪費,同時加重網絡延遲。本文考慮鏡像的其他屬性來精準計算關聯程度C,如式(1)所示:其中,d表示新請求和歷史請求對應鏡像層的間隔鏡像層數量;Plast表示歷史請求對應鏡像層的流行度;Pnow表示新請求對應鏡像層的流行度;Tlast表示歷史請求到達的時間戳;Tnow表示新請求到達的時間戳。

通過鏡像結構提取模塊收集的鏡像層信息代入公式計算關聯程度C,在鏡像倉庫的結構中,選取從新請求對應鏡像層至歷史請求對應鏡像層方向的C個鏡像層作為弱關聯鏡像層集合。
(3)新請求與歷史請求對應的鏡像層無關聯時,即新請求無法對要預取的鏡像層提供信息,則清除該預取窗口中所有歷史請求,僅保留最新請求,為后繼請求提供關聯性參考。
由于注冊表服務器內存中緩存了鏡像層,從關聯模型中得到的相關鏡像層集合并非全部拉取,需要查詢緩存數據,得出緩存缺失鏡像層的預取集合,從存儲后端取回注冊表服務器。
LCPA 策略的算法如算法1 所示。

為了進一步驗證緩存預取策略LCPA 的有效性,在仿真模擬器上實現了LRU、LIRS、GDFS 和LPA 四種算法,由于預取策略是對緩存策略的擴展,LCPA和LPA 均以LRU 為緩存替換算法。實驗采用真實的注冊表工作負載trace 數據集進行測試,分別在不同緩存規模下測試預取策略相對緩存策略的提升的緩存命中率和延遲節省率,以及相比其他預取算法提高的效果。
本文實驗采用Intel Core i7-6700 的CPU,24 GB DDR3 RAM,和7 200 r/min 500 GB SATA 硬盤,并安裝操作系統CentOS 7.3,Linux 內核版本是3.10.0,Docker版本是1.12.0,對應的API版本為1.27,采用的編譯語言python 版本為3.5.2。實驗環境具體參數如表1 所示。

Table 1 Parameters of experiment environment表1 實驗環境參數
使用SNIA trace data files 來測試LCPA 的性能,SNIA trace data files 是從IBM 云注冊表中收集的真實工作負載數據集,其中包括從2017 年6 月20 日到2017 年2 月9 日間,5 個不同地理位置的注冊表(另外兩個是IBM 內部使用的注冊表)處理的總計超過3 800 萬個請求,總數量傳輸超過181.3 TB,由于原始日志中部分信息不能公開,經過刪除冗余字段并匿名處理后,數據集總大小為22.4 GB。數據集由http請求組成,每一個請求都有固定的屬性,包括處理請求的注冊表服務器的主機號、請求的響應時間、HTTP 請求方式、用戶IP 地址、請求的URL、用戶使用的Docker 版本、請求狀態、請求數據大小、請求id、請求時間戳。由于本文提出的預取策略僅涉及元數據文件和鏡像層的操作,對數據集處理后僅保留數據的拉取和上傳請求,表2 展示本實驗采用的真實負載的特性。

Table 2 Characteristics of real workload used in experiments表2 本實驗采用的真實負載的特性
為了更好地評估算法的性能,本研究使用請求命中率和延遲節省率兩個指標。
定義5請求命中率(hit ratio)是指在注冊表服務器緩存中命中的鏡像層拉取請求占鏡像層拉取請求總數的百分比。
定義6延遲節省率(latency saving ratio)。從用戶發出拉取鏡像請求到所有鏡像被下載到本地的過程中,設Tregistry為命中注冊表服務器緩存并拉取鏡像的延遲,Tobject為根據重定向url 到對象存儲服務器拉取鏡像的延遲,則計算延遲節省率如式(2)所示:

3.3.1 數據集命中率測試分析

Fig.8 Hit ratio for LRU,LIRS,GDFS and LCPA圖8 LRU、LIRS、GDFS 和LCPA 算法的請求命中率
圖8 給出的是LCPA 策略與3 種緩存算法LRU、LIRS 和GDFS 在不同數據集下實現的請求命中率,設置的緩存范圍從50 MB 到12 GB,靈活地展示算法在注冊表資源變動時的性能。
實驗的測試結果表明:首先,所有算法在不同的注冊表trace 數據集上都受到請求順序的影響,例如GDFS 算法在dev 數據集上取得了較高的命中率,但在dal 和lon 數據集中卻非常低。從橫向上看,隨著緩存容量的增大,每種算法的命中率都有不同程度的提升,其中LRU 和LIRS 在dev 和pre 數據集的測試中從極低的命中率快速提升,這是因為兩個trace 是IBM 公司內部使用的注冊表數據集,鏡像種類不夠豐富,注冊表服務器能緩存大部分熱點鏡像。從縱向上看,LRU 算法由于自身的各種缺陷,平均命中率是最低的,但是在部分數據集中能與LIRS 算法的命中率相似。GDFS 綜合考慮請求鏡像層的大小、獲取成本等屬性,在請求命中率這個指標中優于LRU 和LIRS。最后,本文提出的LCPA 算法在不同的trace數據集中的命中率均處于領先位置,總體表現優于其他緩存算法,能夠在較小緩存空間中根據關聯規則預得到很好的命中率,算法性能平均提升了12%~29%不等。
3.3.2 數據集延遲節省率測試分析

Fig.9 Latency saving ratio for LRU,LIRS,GDFS and LCPA圖9 LRU、LIRS、GDFS 和LCPA 算法的延遲節省率
圖9 給出了LRU、LIRS、GDFS 和LCPA 算法的延遲節省率的實驗結果。從結果來看,LCPA 算法均比其他算法要節省更多的延遲。結合請求命中率來分析,LCPA 在stage 和dal數據集中測試時,當緩存容量較小,40%左右的請求命中率獲取了不到8%節省延遲率,原因是這兩個數據集中存在的較小熱點鏡像層在真實拉取時均沒有產生較高的延遲,同時在緩存中的生命周期較短,沒有較大節省延遲的空間,隨著緩存大小的增加,延遲節省率會迅速增加。綜合所有數據集結果,當注冊表服務器資源較少時,四種算法為用戶節省的延遲相差無幾,但LCPA 總體表現優于其他算法,延遲節省率平均提升21.1%~49.4%。
3.3.3 與LPA 預取算法比較分析
LPA 算法[8]的基本思想是將注冊表服務器接收到的PUT 請求信息記錄在查找表中,包含請求中的鏡像層信息、請求到達時間以及客戶端地址,當注冊表在設置的時間閾值內從客戶端收到GET manifest請求時,檢查查找表中是否包含manifest 指定的鏡像層,如果是非上傳主機發出的請求命中,則從后端對象存儲中實施預取。
為了驗證兩種預取算法的性能,實驗選取了7 個數據中心的數據集來測試兩種算法的請求命中情況,由于LPA 算法中有兩個時間參數控制鏡像在注冊表中的緩存時間,使得緩存中鏡像總大小處于變化的數值,于是對參數進行調整,盡量使得注冊表服務器中的緩存處于飽和狀態,結果如圖10 所示。

Fig.10 Hit ratio for LCPA and LPA圖10 LCPA 與LPA 算法的請求命中率
從圖10 中可以看出,LPA 算法在dev 和prestage數據集中表現出極低命中率,這是因為這兩個數據集來自IBM 內部開發和測試所使用的注冊表,注冊表中的鏡像分布較為平均,沒有流行度非常高的鏡像,所以被預取回注冊表的鏡像層在下一次拉取該鏡像層的請求到來時,其會在規定大小的緩存中被快速替換導致未命中,而LCPA 算法在這兩個數據集中的高命中率表明了通過關聯性去預判未來可能被請求命中的鏡像層更加精確。LCPA 的請求命中率總是優于LPA,LCPA 的平均命中率是60.3%,最高達72.8%,比LPA 的平均命中率提升25.6%。
圖11 的實驗結果表明,與LPA 算法相比,LCPA在7 個trace 數據集中的延遲優化效果更好,平均延遲節省率提高了43.3%。由表2 可知stage 和dal 數據集中鏡像的平均拉取延遲較大,但相比其他數據集,LCPA 策略的優化效果不明顯,這是因為LCPA 不緩存某些體積巨大的鏡像,則損失了部分可以節約的拉取延遲。pre 和syd 數據集中鏡像的平均鏡像大小和平均拉取延遲均較小,即使LPA 算法的命中率與LCPA 較大,但延遲節省率的差距有著明顯的縮小。

Fig.11 Latency saving ratio for LCPA and LPA圖11 LCPA 與LPA 算法的延遲節省率
兩個實驗結果不僅體現了LCPA 算法預測的穩定性,同時也體現了現有算法預測請求鏡像的不夠精準以及LCPA 策略在Docker注冊表中的研究意義,突出了LCPA 策略的創新價值。
Docker 作為云計算領域中的容器管理工具,具有很強的市場前景。本文針對用戶啟動容器延遲逐漸增加的問題,對Docker 生態中的注冊表服務器進行改進,設計基于鏡像關聯的Docker 注冊表緩存預取策略LCPA。仿真實驗結果表明,與LRU、LIRS、GDFS 等緩存算法相比,LCPA 通過主動式預取有效提升了注冊表性能,在不同數據集中均實現了較好的請求命中率。與現有的預取策略LPA 相比,克服了LPA 算法尋找關聯性的局限性,并通過關聯模型計算相關鏡像層集合進行預取,從Docker 注冊表服務器返回鏡像至客戶端節省了大量延遲,從而加快了容器啟動效率。