陳 哲 劉釗遠(yuǎn)
(西安郵電大學(xué)計(jì)算機(jī)學(xué)院 西安 710121)
微服務(wù)是當(dāng)下流行的軟件開發(fā)架構(gòu),該架構(gòu)提倡將應(yīng)用按業(yè)務(wù)需求劃分為一個(gè)個(gè)彼此獨(dú)立運(yùn)行的微服務(wù)單元,服務(wù)之間通過輕量級通信機(jī)制進(jìn)行相互協(xié)作[1]。微服務(wù)可以采用不同的編程語言和存儲(chǔ)技術(shù),每個(gè)微服務(wù)可以獨(dú)立部署、資源調(diào)度,從而實(shí)現(xiàn)高度的伸縮性和靈活性。容器是輕量級的虛擬化技術(shù),在資源隔離的同時(shí)共享操作系統(tǒng)內(nèi)核,具有啟動(dòng)速度快、資源利用率高的特點(diǎn)[2]。Kubernetes[3]這樣的容器管理工具還兼具了服務(wù)發(fā)現(xiàn)的功能,因此大規(guī)模微服務(wù)通常采用容器進(jìn)行部署。
微服務(wù)與云計(jì)算結(jié)合,已經(jīng)成為業(yè)界公認(rèn)的云計(jì)算時(shí)代互聯(lián)網(wǎng)應(yīng)用的主要構(gòu)建方式[4]。阿里巴巴、騰訊、Netflix、Amazon 等,均開始采用微服務(wù)構(gòu)建其業(yè)務(wù)應(yīng)用。對云服務(wù)供應(yīng)商而言,用盡可能少的資源保證托管的云上應(yīng)用的服務(wù)等級協(xié)議(Service Level Agreement),可以降低運(yùn)維成本。而對于應(yīng)用開發(fā)者來說,在負(fù)載變化時(shí)及時(shí)調(diào)整資源配置能夠提升服務(wù)質(zhì)量。為了實(shí)現(xiàn)這兩點(diǎn),彈性伸縮技術(shù)不可或缺。容器化的微服務(wù)在水平擴(kuò)展上具有巨大的潛力,然而現(xiàn)有的云平臺仍缺乏能充分發(fā)揮微服務(wù)特性的彈性伸縮策略[5]。
目前業(yè)界主要采用的是基于閾值的響應(yīng)式伸縮策略,該策略需要用戶指定參考的資源指標(biāo)并設(shè)置伸縮閾值,如當(dāng)CPU 利用率超過70%時(shí)觸發(fā)擴(kuò)容,低于40%時(shí)則觸發(fā)縮容。系統(tǒng)定時(shí)檢查相關(guān)資源指標(biāo),將其與閾值進(jìn)行對比并計(jì)算出伸縮所需的資源量。設(shè)置合適的閾值和伸縮規(guī)則需要用戶對應(yīng)用進(jìn)行深入了解,僅憑資源利用率也難以準(zhǔn)確估計(jì)微服務(wù)應(yīng)用的性能,很容易造成無效伸縮和過度伸縮[6]。更重要的是該策略將微服務(wù)看作獨(dú)立的個(gè)體,沒有考慮服務(wù)之間的依賴關(guān)系,伸縮時(shí)也就無法保證應(yīng)用的服務(wù)質(zhì)量。
本文提出了一種基于服務(wù)容量的預(yù)測式彈性伸縮策略,以應(yīng)用層指標(biāo)請求訪問率(request per second)取代資源利用率作為伸縮的主要參考,并通過SVR算法預(yù)測請求率的變化,從而提前制定伸縮計(jì)劃,避免資源初始化期間違反SLA協(xié)議。為了精確地估計(jì)伸縮時(shí)所需的資源量,提出了基于應(yīng)用分析的資源估計(jì)方法,通過一系列壓力測試獲得應(yīng)用在不同負(fù)載強(qiáng)度下資源量與響應(yīng)時(shí)間的關(guān)系,從而給出合適的資源分配方案。實(shí)驗(yàn)驗(yàn)證,本文提出的策略能夠滿足微服務(wù)應(yīng)用對響應(yīng)時(shí)間的要求并充分利用集群資源。
目前關(guān)于彈性伸縮的研究有許多,從伸縮維度上彈性伸縮可以分為水平伸縮和垂直伸縮[7]。水平伸縮是指通過增加或減少服務(wù)實(shí)例來實(shí)現(xiàn)資源重分配,一實(shí)例包括虛擬機(jī)、容器等。垂直伸縮則是通過增加或減少計(jì)算資源來實(shí)現(xiàn)伸縮,計(jì)算資源包括CPU和內(nèi)存等。
從伸縮時(shí)機(jī)上可分為響應(yīng)式和預(yù)測式[7]。響應(yīng)式伸縮是根據(jù)當(dāng)前負(fù)載和性能指標(biāo)是否超過預(yù)定閾值來判斷是否進(jìn)行伸縮。由于資源初始化需要時(shí)間,該方法存在滯后性。響應(yīng)式、橫向伸縮是云平臺主流的彈性伸縮方式[8]。
預(yù)測式伸縮則是根據(jù)負(fù)載的歷史數(shù)據(jù)構(gòu)建預(yù)測模型,通過預(yù)測未來一段時(shí)間內(nèi)的負(fù)載變化,來判斷是否進(jìn)行伸縮。預(yù)測模型的精度是該方法的關(guān)鍵,文獻(xiàn)[9]提出了基于自回歸平均移動(dòng)模型(Auto Regressive Moving Average,ARMA)的負(fù)載預(yù)測方法,該方法要求數(shù)據(jù)屬于平穩(wěn)型序列。文獻(xiàn)[10]采用線性回歸和神經(jīng)網(wǎng)絡(luò)的方法預(yù)測CPU 利用率的變化;文獻(xiàn)[11]利用ARIMA 與RBF 神經(jīng)網(wǎng)絡(luò)對CPU 和內(nèi)存指標(biāo)進(jìn)行預(yù)測。文獻(xiàn)[12]指出采用應(yīng)用相關(guān)指標(biāo)的伸縮策略能夠提供更好的性能。
對于云環(huán)境下的微服務(wù)應(yīng)用,每個(gè)微服務(wù)都能夠進(jìn)行水平擴(kuò)展,應(yīng)用可以表示為不同服務(wù)的副本組合,在特定的負(fù)載強(qiáng)度、性能要求以及資源限制下,并非所有的組合都是最佳的。因此,伸縮時(shí)需要進(jìn)行準(zhǔn)確的資源估計(jì),即伸縮哪種服務(wù)伸縮多少資源性價(jià)比最高。常用的資源估計(jì)方法包括應(yīng)用分析、性能建模、強(qiáng)化學(xué)習(xí)等。文獻(xiàn)[4]采用Jackson排隊(duì)網(wǎng)絡(luò)對微服務(wù)進(jìn)行建模,建立負(fù)載、資源利用率以及響應(yīng)時(shí)間之間的關(guān)系用以指導(dǎo)資源分配。排隊(duì)模型適用于特定的伸縮場景,但是很難在不同應(yīng)用之間推廣[13]。文獻(xiàn)[14]采用馬爾科夫決策描述資源配置,通過強(qiáng)化學(xué)習(xí)算法尋找馬爾科夫決策過程中最優(yōu)的伸縮策略。采用強(qiáng)化學(xué)習(xí)需要較長的訓(xùn)練過程,在集群運(yùn)行前期表現(xiàn)較差。應(yīng)用分析是通過合成或真實(shí)的負(fù)載測定應(yīng)用的資源飽和點(diǎn)的過程,能夠簡單且準(zhǔn)確建立起微服務(wù)的資源估計(jì)[7]。
首先給出服務(wù)容量[15]的定義:微服務(wù)在不違反SLO 的情況下能夠處理的最大請求速率。服務(wù)容量可以定量的描述微服務(wù)在特定資源配置下的性能表現(xiàn)。為了對微服務(wù)應(yīng)用進(jìn)行有效的伸縮,需要知道每種微服務(wù)的服務(wù)容量,以及何時(shí)進(jìn)行伸縮。本文提出的基于服務(wù)容量的預(yù)測式伸縮策略包含如下三步:
1)首先,通過對微服務(wù)應(yīng)用進(jìn)行應(yīng)用分析得到每個(gè)微服務(wù)容器在特定資源配置下的服務(wù)容量。
2)接下來,建立時(shí)間序列預(yù)測模型,根據(jù)過往的訪問數(shù)據(jù),預(yù)測未來短時(shí)間內(nèi)的訪問請求率的變化情況。
3)最后,根據(jù)預(yù)測的結(jié)果結(jié)合當(dāng)前應(yīng)用整體的服務(wù)容量判斷是否應(yīng)當(dāng)進(jìn)行伸縮,在需要伸縮時(shí)根據(jù)步驟1)得到的服務(wù)容量表計(jì)算出最佳的副本數(shù)。
微服務(wù)應(yīng)用可以被描述為如下的模型:應(yīng)用接收外界的請求,將其稱之為系統(tǒng)級請求,每個(gè)系統(tǒng)級請求在應(yīng)用內(nèi)部被分解為內(nèi)部請求交由相應(yīng)的子服務(wù)處理,處理完后會(huì)返回給用戶。對于系統(tǒng)中的每個(gè)子服務(wù),又可以將其看作一個(gè)子系統(tǒng),其余的子服務(wù)作為該子系統(tǒng)的外界環(huán)境。根據(jù)Operational Laws[16],觀察系統(tǒng)可以得到表1列的指標(biāo)。
表1 直接觀測到的指標(biāo)
表2 各個(gè)變量及其含義
從這些直接測量的指標(biāo)可以進(jìn)一步推導(dǎo)出下列重要的量:
吞吐量或者完成率:
利用率:
平均完成每個(gè)請求需要的時(shí)間:
定義訪問量Vi是子服務(wù)i的請求完成數(shù)與系統(tǒng)級請求完成數(shù)的比值:
根據(jù)式(4),子服務(wù)i的吞吐量Xi等于系統(tǒng)總的吞吐量X與子服務(wù)i訪問量Vi的乘積:
定義服務(wù)需求Di是子服務(wù)i上平均完成每個(gè)請求的時(shí)間Si與訪問量Vi的乘積:
根據(jù)式(1)、(2)、(3)、(6),子服務(wù)i的利用率可以表示為
設(shè)系統(tǒng)內(nèi)服務(wù)需求最大的子服務(wù)為b,它的服務(wù)需求為Dmax,則b的利用率可以表示為
因?yàn)槔寐蔝b≤1,所以:
式(9)表明應(yīng)用整體的吞吐量受制于瓶頸服務(wù),因此可以用應(yīng)用整體的吞吐量等同瓶頸服務(wù)的服務(wù)容量。據(jù)此,本文提出了基于壓力測試的服務(wù)容量估計(jì)方法,通過調(diào)整壓力測試強(qiáng)度和各子服務(wù)的副本數(shù),使得不同的微服務(wù)先后進(jìn)入瓶頸狀態(tài),從而得到每個(gè)微服務(wù)的服務(wù)容量。
該方法的具體步驟如下:
1)部署微服務(wù)各子服務(wù)副本數(shù)均為1,預(yù)先指定SLO指標(biāo),本文中設(shè)為響應(yīng)時(shí)間的99%分位數(shù)小于50ms。
2)使用負(fù)載生成器逐步增大負(fù)載強(qiáng)度,直到應(yīng)用的響應(yīng)時(shí)間達(dá)到預(yù)設(shè)的SLO指標(biāo)。
3)檢查各子服務(wù)的資源利用情況并分析應(yīng)用的瓶頸點(diǎn),找出分配相同資源量SLO指標(biāo)提升最多的子服務(wù),此時(shí)的請求率即為該服務(wù)的單位副本的服務(wù)容量。
4)重復(fù)2)~3)步,直到獲取所有子服務(wù)的容量為止。
偽代碼描述如下:
用戶訪問的請求率(request per second,rps)是一類典型的時(shí)間序列數(shù)據(jù)??紤]到彈性伸縮的目的之一是為了節(jié)省集群資源,所以在選擇預(yù)測算法時(shí)應(yīng)避免使用時(shí)間復(fù)雜度過高的算法。預(yù)測的目的是為資源配置爭取時(shí)間,所以主要考慮短期預(yù)測?;谝陨显虮疚倪x擇了SVR[17]算法建立預(yù)測模型。SVR 可以選取不同的核函數(shù)靈活適用于線性和非線性數(shù)據(jù),在樣本量較小時(shí)具有不錯(cuò)的準(zhǔn)確度并且計(jì)算復(fù)雜度低。
將歷史的請求率按照自定的時(shí)間粒度排列成時(shí)間序列。設(shè)訓(xùn)練樣本為Xi為過去n個(gè)單位時(shí)間內(nèi)的請求率:
SVR的模型為
其中?(x)是一個(gè)非線性函數(shù),它將樣本空間映射到高位的特征空間,w和b是待確定的模型參數(shù)。SVR 允許模型輸出f(x)與真實(shí)輸出y有一定偏差?,定義?-不敏感損失函數(shù):
以f(x) 為中心,落在f(x)-?和f(x)+?范圍內(nèi)的樣本都不計(jì)入損失,SVR模型可形式化為
其中ξi,?是松弛變量,c是懲罰系數(shù),用來調(diào)節(jié)間隔和分類準(zhǔn)確度,c越大表示對偏差的容忍度越小,是需要優(yōu)化的指標(biāo)之一。引入拉格朗日乘子將式(10)轉(zhuǎn)化為其對偶問題,并引入核函數(shù)求解后得到回歸方程:
其中k(x,xi)=?(xi)T?(xj)為核函數(shù)。常用的核函數(shù)有線性核函數(shù)、多項(xiàng)式核函數(shù)和高斯核函數(shù)等。令gamma=,其中σ為高斯核函數(shù)的帶寬,gamma越大訓(xùn)練準(zhǔn)確度會(huì)提高,但對未知樣本分類效果下降,容易出現(xiàn)過擬合。gamma越小則無法在訓(xùn)練集上得到較高的準(zhǔn)確率,也會(huì)影響測試集的準(zhǔn)確度。
核函數(shù)、懲罰因子c、gamma(使用高斯核函數(shù)的話)三者的組合是需要優(yōu)化的指標(biāo)。本文使用高斯核函數(shù)并利用網(wǎng)格搜索確定最優(yōu)的模型參數(shù)。
最后使用測試樣本預(yù)測未來的請求率,即可得到預(yù)測序列:
根據(jù)上文分析,各子服務(wù)容量的最小值決定了應(yīng)用整體的服務(wù)容量,通過為瓶頸子服務(wù)進(jìn)行擴(kuò)容,可以提高應(yīng)用整體的容量。當(dāng)預(yù)測的請求率大于應(yīng)用整體服務(wù)容量時(shí)觸發(fā)擴(kuò)容,為了保持系統(tǒng)的穩(wěn)定縮容,采用請求率實(shí)測值觸發(fā),其他步驟類似。以擴(kuò)容為例,觸發(fā)擴(kuò)容后遍歷各子服務(wù)當(dāng)某個(gè)子服務(wù)的容量小于預(yù)測的請求率時(shí),為其擴(kuò)容,直到容量剛好超過預(yù)測值為止,調(diào)整完所有子服務(wù)后本次擴(kuò)容結(jié)束。
偽代碼描述如下:
本次實(shí)驗(yàn)使用三臺虛擬機(jī)搭建的Kubernetes集群作為實(shí)驗(yàn)平臺,一臺master 節(jié)點(diǎn),另外兩臺作為node 節(jié)點(diǎn)。Kubernetes 版本是1.18,Docker 版本是1.40,操作系統(tǒng)是CentOS7。實(shí)驗(yàn)對象是一個(gè)簡單的微服務(wù)應(yīng)用emojivoto[18],它是一個(gè)為表情投標(biāo)的應(yīng)用。該應(yīng)用由三個(gè)微服務(wù)組成:web 負(fù)責(zé)前端頁面,emoji用于查找和列出表情符號。voting 用于記錄投票和排行榜。該應(yīng)用的API 如表3 所示,包括了list,leaderboard 和vote。使用Apache Jmeter模擬用戶訪問。
表3 emojivoto應(yīng)用的API
設(shè)定單個(gè)副本的資源限額,web 服務(wù)的CPU 份額為200m,另外兩個(gè)服務(wù)CPU 份額為50m(Kubernetes中1000m表示一個(gè)核)。
根據(jù)3.2節(jié)描述的算法對應(yīng)用的三個(gè)功能分別進(jìn)行了測試,SLO 指標(biāo)為響應(yīng)時(shí)間99%分位數(shù)≤50ms。表4展示了測試結(jié)果,可以看到應(yīng)用執(zhí)行不同功能時(shí)各子服務(wù)的容量也不盡相同。以查看表情列表功能為例,web 服務(wù)的容量是135 次/s,emoji服務(wù)的容量是110 次/s,執(zhí)行該功能不涉及vote 服務(wù)所以其容量不計(jì)。
表4 服務(wù)容量測試結(jié)果
使用Jmeter模擬用戶使用投票功能,訪問請求率從50 次/s 逐步上升至359 次/s 再下降到220 次/s。將請求率序列重復(fù)10 次后訓(xùn)練SVR 模型,將預(yù)測值作為本文策略的輸入。Kubernetes 原策略則設(shè)置CPU利用率>70%作為擴(kuò)容閾值,CPU利用率<40%作為縮容閾值。
伸縮過程中的副本數(shù)變化如圖1 所示,每組條柱中左側(cè)條柱表示使用本策略各子服務(wù)的副本數(shù)變化,右側(cè)條柱表示使用Kubernetes 原策略各子服務(wù)副本數(shù)的變化情況。根據(jù)預(yù)測的請求率,本文策略在第2min 開始擴(kuò)容,而原策略則滯后1min 才觸發(fā)擴(kuò)容。在第8min請求率從350次/s增大到了359次/s,原策略檢測到web 子服務(wù)的CPU 利用率超過閾值進(jìn)行了一次伸縮,而本文策略估計(jì)當(dāng)前資源分配容量滿足要求故沒有進(jìn)行伸縮。本文策略和原策略都在第11min 觸發(fā)縮容,但是本文策略減少了更多的副本。
圖1 各子服務(wù)副本變化情況對比
圖2展示了伸縮過程中應(yīng)用整體響應(yīng)時(shí)間99%分位數(shù)的變化情況,閾值為50ms。在第3min、4min、5min,由于原策略響應(yīng)滯后以及資源估計(jì)不足,響應(yīng)時(shí)間超出了閾值范圍。在整個(gè)伸縮過程中,本文策略始終保證應(yīng)用響應(yīng)時(shí)間在閾值以內(nèi),且波動(dòng)幅度更小。
圖2 伸縮過程中應(yīng)用響應(yīng)時(shí)間對比
針對微服務(wù)應(yīng)用場景下,傳統(tǒng)基于閾值的響應(yīng)式伸縮策略存在響應(yīng)滯后以及資源估計(jì)不準(zhǔn)的問題,本文提出了一種基于服務(wù)容量的預(yù)測式彈性伸縮策略。通過SVR 預(yù)測工作負(fù)載變化提前進(jìn)行伸縮決策。為了準(zhǔn)確地估計(jì)伸縮所需的資源量,提出了基于應(yīng)用分析的資源估計(jì)方法。實(shí)驗(yàn)表明,相較于基于閾值的響應(yīng)式策略,本文策略在保證應(yīng)用服務(wù)質(zhì)量的同時(shí)有效節(jié)省集群資源。