背景
云主機創(chuàng)建有兩種方式,一種通過鏡像下載來創(chuàng)建,另一種通過快照回滾來創(chuàng)建, 前者是通用的傳統(tǒng)方式,后者依賴于CBS云盤能力。 隨著CBS云盤使用越來越廣泛,騰訊云主機創(chuàng)建也由原來的鏡像下載切換到CBS云盤快照回滾模式。
通過傳統(tǒng)鏡像下載的方式來創(chuàng)建云主機,在云主機拉起前,需要將整個鏡像文件都下載到宿主機上,所以云主機的創(chuàng)建時間很大程度上依賴所選取的鏡像和當(dāng)時下載鏡像的帶寬。當(dāng)遇到比較大的鏡像時,云主機創(chuàng)建時間經(jīng)常會達到幾百秒,這樣的用戶體驗不是太好; 另外,當(dāng)批量創(chuàng)建時,需要消耗大量的內(nèi)網(wǎng)帶寬資源,需要在盡量占用網(wǎng)絡(luò)帶寬的同時做好Qos,保證不影響用戶的正常使用。
使用云盤快照回滾的方式來創(chuàng)建云主機,不需要提前下載鏡像,而是在云主機拉起時,優(yōu)先將要訪問的數(shù)據(jù)從快照系統(tǒng)搬遷到CBS云盤系統(tǒng)中。 我們觀察到,云主機拉起過程中訪問的數(shù)據(jù)量和鏡像大小并不是嚴(yán)格的線性關(guān)系,即便是較大的鏡像,在云主機拉起時也只會訪問到很少一部分?jǐn)?shù)據(jù),搬遷流程如下:
圖1. 云盤快照數(shù)據(jù)搬遷流程
當(dāng)有快照回滾請求時,我們首先會在后臺啟動一個任務(wù),將快照數(shù)據(jù)按順序從COS讀出寫入到存儲池中,同時我們不會阻礙用戶對回滾磁盤的正常讀寫。 當(dāng)有用戶請求過來時(步驟1),會先在driver中檢查對應(yīng)lba的快照數(shù)據(jù)是否已經(jīng)被寫入,如果寫入則IO直接下發(fā)(步驟7),否則,會阻塞IO并先給scheduler發(fā)送trigger請求(步驟3),scheduler會優(yōu)先將trigger請求處理,交給搬遷模塊將對應(yīng)的快照數(shù)據(jù)從COS讀出,寫入到存儲池(步驟3、4、5),等寫入完畢后,scheduler先記錄搬遷bitmap到zk并給driver返回trigger response和當(dāng)前的快照數(shù)據(jù)回滾進度(步驟6),driver收到后則不再阻塞io, 讓其正常下發(fā)(步驟7)。
聚焦延遲和并發(fā),云主機創(chuàng)建優(yōu)化之路
云盤快照回滾優(yōu)先搬遷關(guān)鍵數(shù)據(jù)這種機制為我們批量創(chuàng)建云主機奠定了基礎(chǔ),在此基礎(chǔ)上,我們還圍繞著延遲和并發(fā)這兩點做了一系列優(yōu)化。
transfer增加cache
子機批量創(chuàng)建時,經(jīng)常是使用同一個鏡像克隆出幾百或上千臺子機,如果所有數(shù)據(jù)都從COS系統(tǒng)拉取,對COS的讀壓力會非常大,會觸發(fā)COS的Qos流控。為了讓批量創(chuàng)建時讀取鏡像的流量不再受限于COS的帶寬, 我們在transfer中增加了cache,每個transfer中都緩存鏡像的部分?jǐn)?shù)據(jù)塊,一旦命中transfer的cache就不再從COS拉取數(shù)據(jù),這樣每個transfer只需拉取一次鏡像; 當(dāng)cache流量達到瓶頸時,可以通過臨時增加節(jié)點來增加帶寬,具備水平擴展能力。
在增加了cache后,我們對transfer部署也做了優(yōu)化,每個zone都部署了若干個節(jié)點,當(dāng)有數(shù)據(jù)塊搬遷請求時,任務(wù)總是會優(yōu)先落到和CBS盤底層存儲節(jié)點相同zone的transfer上,這樣就可以實現(xiàn)就近搬遷。
通過cache優(yōu)化,可以將單個數(shù)據(jù)塊的搬遷耗時從100+ms降低到10+ms, 大大降低了IO延遲。
圖2. transfer cache
scheduler性能優(yōu)化
在快照回滾創(chuàng)建云主機過程中,核心處理邏輯在scheduler,因為client端每個IO trigger請求都要經(jīng)過scheduler, 并且由于每個由trigger觸發(fā)的快照數(shù)據(jù)塊搬遷都要在zk里記錄起來, 所以scheduler的負(fù)載以及zk寫入能力會直接影響到整個快照系統(tǒng)的吞吐。
首先,我們優(yōu)化了scheduler,將請求接收、處理以及與后端交互部分的邏輯拆開來,形成流水線,盡量減少因某個請求處理慢導(dǎo)致其他請求排隊的情況, 每個部分都由一個線程池來并行處理,盡量將整機的計算能力利用起來;
其次,針對zk寫入壓力大的問題,我們將寫入zk的數(shù)據(jù)做了分類,變化不頻繁的一些元數(shù)據(jù)還是寫入zk; 而記錄trigger搬遷狀態(tài)的那些元數(shù)據(jù),需要頻繁修改,這部分?jǐn)?shù)據(jù)不適合存zk,我們將其offload到一個qps更高的存儲系統(tǒng)上,這樣一來,scheduler的處理能力得到了成倍的增長。
另外,為防止回滾的流量影響到其他用戶對磁盤的正常使用,我們在scheduler做了必要的Qos。 首先限制落到同一個副本組的回滾帶寬, 在整個副本組帶寬空閑時,回滾流量不能超過限制; 而當(dāng)整個副本組的帶寬達到上限時,回滾帶寬會自動回退,優(yōu)先保證用戶的正常IO延遲。其次,當(dāng)同時有順序搬遷任務(wù)和trigger請求任務(wù)時,優(yōu)先處理trigger請求任務(wù),保證用戶體驗。
最后,我們通過對scheduler改造,做到水平可擴展, 使其不再成為性能瓶頸。
圖3. scheduler 拆分
買盤調(diào)度
當(dāng)用快照回滾的方式批量創(chuàng)建云主機時, 會將快照數(shù)據(jù)寫入新創(chuàng)建的所有CBS云盤。 如果大量的云盤落在同一個副本組,則會造成這個副本組寫入流量過大,觸發(fā)前一節(jié)提到的副本組回滾帶寬限制。為避免這個問題,我們加入一個調(diào)度系統(tǒng),在批量購買云盤時,從副本組剩余容量、已創(chuàng)建的volume數(shù)、回滾帶寬、副本組寫入帶寬四個緯度綜合考量,把同一批次創(chuàng)建的CBS云盤盡量打散到多個副本組。這樣一來,首先可以保證在創(chuàng)建時,單個副本組不會成為流量熱點;其次可以在一定程度上保證所有的副本組在創(chuàng)建時流量均衡,將整個存儲池的帶寬充分利用起來;最后,同一批次購買的CBS云盤打散,可以將用戶因為某個副本組出故障受到的影響降到最低。
減少子機拉起時的數(shù)據(jù)量
前面主要從降低延遲和增大回滾帶寬角度去考慮如何優(yōu)化,目的是讓后端系統(tǒng)能夠承載更大的回滾帶寬,提升快照數(shù)據(jù)搬遷效率。如果在快照數(shù)據(jù)搬遷過程中,CBS云盤有IO訪問到還未搬遷的數(shù)據(jù)塊,就會產(chǎn)生一個trigger請求,后臺系統(tǒng)需要優(yōu)先搬遷trigger請求對應(yīng)位置的快照數(shù)據(jù),這對scheduler會造成額外的負(fù)擔(dān),所以如何減少子機拉起時產(chǎn)生的IO trigger,減少對后端系統(tǒng)的壓力,對云主機并發(fā)創(chuàng)建很有意義。
對子機拉起過程進行分析,我們發(fā)現(xiàn),在子機拉起過程中,文件系統(tǒng)擴容和配置文件修改都會在后端產(chǎn)生不少io trigger。 文件系統(tǒng)擴容一般發(fā)生在快照里的文件系統(tǒng)size小于要回滾的CBS云盤size,在這種場景下,需要先將原文件系統(tǒng)的元數(shù)據(jù)全部讀到內(nèi)存中,修改后再寫入。像ext系列文件系統(tǒng)的元數(shù)據(jù)是散落在每個塊組中的,所以讀元數(shù)據(jù)會變成隨機讀操作,幾乎每個隨機讀都會產(chǎn)生一個trigger,觸發(fā)后端快照數(shù)據(jù)塊搬遷,而文件系統(tǒng)的block大小遠(yuǎn)小于快照粒度,這里相當(dāng)于發(fā)生了讀寫放大; 為此,我們通過修改文件系統(tǒng)配置,讓所有元數(shù)據(jù)集中,這樣讀元數(shù)據(jù)就變成了順序讀寫,這樣就可以將請求合并,從而減少后端壓力。 經(jīng)過優(yōu)化后,文件系統(tǒng)擴容時,后端IO壓力可以降低到原來的五分之一,耗時降低到原來的四分之一。
其次,對于配置文件修改,如果直接在原文件上修改,既要讀寫文件元數(shù)據(jù),又要讀寫文件數(shù)據(jù),開銷比較大;所以改成刪除+寫新文件的方式,這樣不需要讀文件數(shù)據(jù),可以有效減少IO。
總結(jié):
通過上述幾個層面的技術(shù)優(yōu)化,目前,騰訊云已經(jīng)可以做到八千臺子機并發(fā)創(chuàng)建,為客戶提供更好的服務(wù)體驗。后續(xù),我們的優(yōu)化還會一直進行下去,歡迎大家給我們提出寶貴意見。