佟業(yè)新,曲新奎
(中航信移動科技有限公司,北京 100029)
隨著業(yè)務(wù)的發(fā)展,企業(yè)規(guī)模擴(kuò)大,單體的架構(gòu)已經(jīng)無法滿足企業(yè)對系統(tǒng)的需求,需要根據(jù)組織的實(shí)際情況進(jìn)行相應(yīng)的架構(gòu)調(diào)整[1].采用微服務(wù)架構(gòu)的系統(tǒng)是由一系列協(xié)同工作且獨(dú)立的服務(wù)組成[2],與傳統(tǒng)的的單體架構(gòu)相比,微服務(wù)架構(gòu)具有很多的優(yōu)點(diǎn),如靈活性更高,具有更高的彈性和擴(kuò)展性,各個(gè)模塊獨(dú)立開發(fā)部署,互不影響等.
同時(shí)也帶來了一些問題,采用微服務(wù)架構(gòu)的應(yīng)用屬于分布式系統(tǒng),復(fù)雜性較高.在實(shí)際應(yīng)用過程中,會碰到如下的一些問題,包括服務(wù)調(diào)用鏈條較長,存在重復(fù)資源調(diào)用問題;對異常時(shí)協(xié)議的容錯(cuò)處理不足,被依賴的服務(wù)出現(xiàn)異常時(shí),協(xié)議的失敗率波動很大魯棒性差;對一些服務(wù)依賴程度較高,缺少降級策略;服務(wù)調(diào)用的參數(shù)定義的不合理,少量的服務(wù)調(diào)用導(dǎo)致整體服務(wù)不可用.
鑒于上述問題,與單體架構(gòu)相比,在實(shí)際的應(yīng)用中,需要有更多的技術(shù)手段如分布式追蹤、熔斷隔離、實(shí)時(shí)監(jiān)控等來保證微服務(wù)架構(gòu)可靠性[3].為了保證系統(tǒng)的可靠性,文中制定了質(zhì)量評價(jià)指標(biāo),圍繞這些指標(biāo),文中通過多線程并發(fā)調(diào)用以及分布式緩存的方法實(shí)現(xiàn)縮短響應(yīng)服務(wù)時(shí)間的目的.為了提升服務(wù)的可靠性,從服務(wù)調(diào)用失敗處理,熔斷隔離保護(hù)以及無損上線三個(gè)方面進(jìn)行了研究,并提出了熔斷隔離參數(shù)的計(jì)算模型,以對服務(wù)調(diào)用過程中的熔斷隔離參數(shù)進(jìn)精細(xì)化計(jì)算,以便更加合理的調(diào)配多個(gè)服務(wù)對線程池等資源的使用.這些研究在實(shí)際的項(xiàng)目中進(jìn)行應(yīng)用,在服務(wù)質(zhì)量提升方面起到了很好的效果.
本文中服務(wù)質(zhì)量的保障,重點(diǎn)圍繞縮短服務(wù)響應(yīng)時(shí)間和提升服務(wù)可靠性展開,同時(shí)需要提供實(shí)時(shí)的服務(wù)質(zhì)量監(jiān)控及評估和改進(jìn),以達(dá)到服務(wù)質(zhì)量的持續(xù)提升,并在服務(wù)質(zhì)量評價(jià)指標(biāo)方面達(dá)到一定的標(biāo)準(zhǔn).
在實(shí)際的生產(chǎn)運(yùn)行中,服務(wù)運(yùn)行的速度、成敗等因素直接影響到用戶的體驗(yàn),因此將響應(yīng)時(shí)間以及失敗率作為本文重點(diǎn)關(guān)注服務(wù)質(zhì)量評價(jià)指標(biāo)進(jìn)行定義.同時(shí)系統(tǒng)的處理量會對響應(yīng)時(shí)間以及失敗率的指標(biāo)產(chǎn)生影響.
在文中提出熔斷隔離參數(shù)的計(jì)算模型,以實(shí)際生產(chǎn)中的文中提到的關(guān)鍵質(zhì)量指標(biāo)為基礎(chǔ)進(jìn)行設(shè)計(jì),由于生產(chǎn)數(shù)據(jù)每時(shí)每刻都在變化,為了應(yīng)對這種情況,需要進(jìn)行實(shí)時(shí)數(shù)據(jù)的收集,并基于模型進(jìn)行實(shí)時(shí)計(jì)算,并將計(jì)算結(jié)果在線推送給業(yè)務(wù)方,進(jìn)行在線生效變更.
質(zhì)量評價(jià)指標(biāo)用于對系統(tǒng)的實(shí)際運(yùn)行情況進(jìn)行量化,以實(shí)現(xiàn)對服務(wù)質(zhì)量的監(jiān)控以及評估[4].本文針對服務(wù)質(zhì)量的保障,重點(diǎn)關(guān)注如下幾個(gè)指標(biāo):
1) 平均響應(yīng)時(shí)間(avg):在一段時(shí)間內(nèi)所有請求響應(yīng)時(shí)間的平均值,平均響應(yīng)時(shí)間越小,說明處理速度越快,服務(wù)效率越高.
2) 95 線響應(yīng)時(shí)間(95Line):在一段時(shí)間內(nèi)95%請求響應(yīng)時(shí)間的最大值.
3) 99 線響應(yīng)時(shí)間(99Line):在一段時(shí)間內(nèi)99%請求響應(yīng)時(shí)間的最大值.
4) 失敗率:在一段時(shí)間內(nèi)失敗次數(shù)與總請求量的比值,失敗率越高說明服務(wù)可靠性越低.
5)QPS:在一段時(shí)間內(nèi)的服務(wù)器每秒所處理的查詢量.
1.2.1 多線程并發(fā)調(diào)用
策略一.多線程調(diào)用,靜態(tài)托底
(1) 應(yīng)用場景:需要對多個(gè)不同數(shù)據(jù)源的服務(wù)進(jìn)行調(diào)用,并對資源進(jìn)行聚合,需要在有限時(shí)間內(nèi)完成.
(2) 策略描述:多個(gè)服務(wù)通過多線程同時(shí)發(fā)起請求,對返回的結(jié)果進(jìn)行聚合.設(shè)定響應(yīng)時(shí)間的閾值,對于超過閾值的服務(wù),對服務(wù)進(jìn)行丟棄,并對該服務(wù)中需要的數(shù)據(jù)進(jìn)行容錯(cuò)處理.
(3) 優(yōu)點(diǎn):解決了多服務(wù)并行調(diào)用帶來的性能問題,在服務(wù)質(zhì)量得到保證的同時(shí)在規(guī)定時(shí)間內(nèi)返回內(nèi)容.
(4) 應(yīng)用案例:航旅縱橫APP 中的首頁,需要以服務(wù)推薦的形式為不同的業(yè)務(wù)提供運(yùn)營位置,進(jìn)行功能展示.各個(gè)服務(wù)需要按照要求提供服務(wù),由服務(wù)推薦模塊進(jìn)行服務(wù)聚合,此處采用了該策略,在規(guī)定時(shí)間內(nèi)不滿足性能要求的服務(wù),將無法獲得推薦,并保證了性能正常的服務(wù)可以正常展示.調(diào)用過程如圖1所示.
圖1 多線程調(diào)用過程
策略二.多路保證,優(yōu)先選用
(1)應(yīng)用場景:可用性和響應(yīng)時(shí)間有極高要求的服務(wù),同時(shí)存在多個(gè)提供相似數(shù)據(jù)源的服務(wù).
(2)策略描述:對于一次服務(wù)請求,多個(gè)獨(dú)立服務(wù)提供支持,在請求處理過程中,多路并發(fā)調(diào)用,優(yōu)先選用先返回的結(jié)果;
(3)優(yōu)點(diǎn):多路保證系統(tǒng)的穩(wěn)定性;以最先返回的結(jié)果優(yōu)先,一定程度上,提高了響應(yīng)時(shí)間;
(4)缺點(diǎn):多路調(diào)用,資源的消耗會根據(jù)同時(shí)調(diào)用的服務(wù)數(shù)量而倍數(shù)增長;
(5)案例:在航旅縱橫APP 中為旅客提供高可用的安檢服務(wù),響應(yīng)時(shí)間需要在100 ms 以下,并達(dá)到容錯(cuò)高可用能力,考慮服務(wù)壓力以及系統(tǒng)資源的情況下,往往使用速度較快的服務(wù)代替資源緊張的服務(wù).
1.2.2 分布式緩存
內(nèi)存的訪問性能明顯優(yōu)于磁盤.把數(shù)據(jù)放入內(nèi)存中,可以提供更快的讀取效率.但在互聯(lián)網(wǎng)業(yè)務(wù)的場景下,將所有數(shù)據(jù)數(shù)據(jù)都裝入內(nèi)存,顯然是不明智的[5].
同時(shí)大部分的業(yè)務(wù)場景下,80%的訪問量都集中在20%的熱數(shù)據(jù)上(適用二八原則).因此,通過引入緩存組件,將高頻訪問的數(shù)據(jù),放入緩存中,可以大大提高系統(tǒng)整體的承載能力,提高響應(yīng)速度,提高用戶體驗(yàn).原有單層DB 的數(shù)據(jù)存儲結(jié)構(gòu),也變?yōu)镃ache+DB 的結(jié)構(gòu),如圖2所示.
圖2 Cache+DB 結(jié)構(gòu)圖
在數(shù)據(jù)層引入緩存,有以下幾個(gè)好處:
(1)提升數(shù)據(jù)讀取速度;
(2)提升系統(tǒng)擴(kuò)展能力,通過擴(kuò)展緩存,提升系統(tǒng)承載能力;
(3)降低存儲成本,Cache+DB 的方式可以承擔(dān)原有需要多臺DB 才能承擔(dān)的請求量,節(jié)省機(jī)器成本.
根據(jù)業(yè)務(wù)場景,通常緩存有以下幾種使用方式:
(1)懶漢式(讀時(shí)觸發(fā)):寫入DB 后,然后把相關(guān)的數(shù)據(jù)也寫入Cache;
(2)饑餓式(寫時(shí)觸發(fā)):先查詢DB 里的數(shù)據(jù),然后把相關(guān)的數(shù)據(jù)寫入Cache;
(3)定期刷新:適合周期性的跑數(shù)據(jù)的任務(wù),或者列表型的數(shù)據(jù),而且不要求絕對實(shí)時(shí)性;
(4)實(shí)時(shí)刷新:通過監(jiān)聽數(shù)據(jù)表的實(shí)時(shí)變更,旁路推送到應(yīng)用,并進(jìn)行緩存的實(shí)時(shí)更新.
提升服務(wù)質(zhì)量的另外一個(gè)重要任務(wù)是提升服務(wù)的可靠性.重點(diǎn)對服務(wù)調(diào)用失敗以及流量異常的處理方式進(jìn)行了研究.
1.3.1 服務(wù)調(diào)用失敗處理
針對調(diào)用失敗有Failfast 和Failover 兩種處理方式.
(1) Failfast:快速失敗只發(fā)起一次調(diào)用,失敗立即報(bào)錯(cuò),現(xiàn)在服務(wù)調(diào)用方的默認(rèn)調(diào)用方式;
(2) Failover:失敗自動切換,當(dāng)出現(xiàn)失敗,重試其它服務(wù)器.此種情況也支持,慎用,在某個(gè)服務(wù)提供方出現(xiàn)故障后,會放大壓力.
在實(shí)際應(yīng)用中,F(xiàn)ailfast 和Failover 兩種方式都進(jìn)行了實(shí)現(xiàn),失敗的處理方式通過分布式配置中心進(jìn)行配置,默認(rèn)使用Failfast.如果各個(gè)業(yè)務(wù)有個(gè)性化需求,可配置為Failover 模式,并設(shè)置重試次數(shù)的配置key FailoverRetryCount,即可實(shí)時(shí)切換為該模式.
1.3.2 熔斷隔離保護(hù)
1.3.2.1 熔斷隔離介紹
服務(wù)熔斷,類似于電路中的“保險(xiǎn)絲”,是指由于某些原因(如用戶大量請求、程序Bug、硬件故障等)造成目標(biāo)服務(wù)調(diào)用慢或者有大量超時(shí),此時(shí)停用對該服務(wù)的調(diào)用,等到服務(wù)情況好轉(zhuǎn)時(shí)再恢復(fù)調(diào)用[6].
線程池隔離就是艙壁隔離模式,貨船通常利用艙壁將不同的船艙隔離起來,防止一個(gè)船艙進(jìn)水對其他船艙的影響,這種資源隔離減少風(fēng)險(xiǎn)的方式就是艙壁隔離模式的一種應(yīng)用場景.該模式使用一個(gè)線程池來存儲當(dāng)前的請求,線程池對請求作處理,設(shè)置任務(wù)返回處理超時(shí)時(shí)間,堆積的請求堆積入線程池隊(duì)列,需要為每個(gè)依賴的服務(wù)申請線程池,有一定的資源消耗,好處是可以應(yīng)對突發(fā)流量.
1.3.2.2 熔斷隔離參數(shù)計(jì)算
在實(shí)際應(yīng)用中,可以引入Hystrix 組件,該組件采用線程池隔離機(jī)制,實(shí)現(xiàn)對系統(tǒng)對穩(wěn)定性保護(hù).通過隔離服務(wù)之間的依賴關(guān)系,限制對其中任何一個(gè)的并發(fā)訪問.
客戶端請求會在單獨(dú)的線程中執(zhí)行,執(zhí)行依賴代碼的線程與請求線程分離,這樣在某個(gè)依賴調(diào)用執(zhí)行時(shí)間很長時(shí),請求線程可以自由控制離開的時(shí)間.Hystrix 通過為每個(gè)依賴服務(wù)分配獨(dú)立的線程池進(jìn)行資源隔離,當(dāng)某個(gè)服務(wù)不可用時(shí),即使為該服務(wù)獨(dú)立分配的線程都處于等待狀態(tài),也不會影響其他服務(wù)的調(diào)用.
服務(wù)啟用線程池和熔斷功能,需要配置線程池大小和超時(shí)時(shí)間.參數(shù)的準(zhǔn)確程度會直接影響到熔斷隔離的實(shí)際效果.為了提升準(zhǔn)確性,結(jié)合現(xiàn)有的應(yīng)用監(jiān)控?cái)?shù)據(jù),設(shè)計(jì)了服務(wù)調(diào)用參數(shù)的計(jì)算公式.如公式(1) 所示,該公式用于計(jì)算被調(diào)用服務(wù)需要配置的線程數(shù):
其中,s(thread)代表應(yīng)用所依賴服務(wù)的線程數(shù),m代表計(jì)算的冗余度,95Line表示某一天的95 線響應(yīng)時(shí)間,max(QPS)表示某一天的QPS峰值.通過該公式計(jì)算的數(shù)值,具有一定的冗余度,可以保證在QPS達(dá)到峰值,服務(wù)響應(yīng)時(shí)間達(dá)到95Line時(shí),線程數(shù)可以足夠使用.
如式(2) 所示,用于計(jì)算服務(wù)的調(diào)用超時(shí)時(shí)間:
其中,s(timeout)代表應(yīng)用所依賴服務(wù)的超時(shí)時(shí)間,使用99Line作為時(shí)間基準(zhǔn),n為時(shí)間冗余度,通過調(diào)整n的數(shù)值,保證99%以上的請求不會因?yàn)槌瑫r(shí)而導(dǎo)致失敗.
兩個(gè)式子中計(jì)算的數(shù)值在極端情況下可能存在一定的沖突,通過95Line作為基數(shù)計(jì)算的線程數(shù),如果使用99Line作為基數(shù)作為超時(shí)時(shí)間,全部超時(shí)的情況下,線程肯定不夠用.但實(shí)際中,絕大多數(shù)請求都在平均響應(yīng)時(shí)間上下,同時(shí)通過應(yīng)用監(jiān)控系統(tǒng)及時(shí)發(fā)現(xiàn)調(diào)用的波動情況,可以將響應(yīng)時(shí)間控制在一定范圍內(nèi),保證了服務(wù)的穩(wěn)定運(yùn)行.
圖3的參數(shù)計(jì)算流程展示了基于計(jì)算模型從數(shù)據(jù)收集到最終應(yīng)用的全過程.
圖3 參數(shù)計(jì)算流程
(1) 從生產(chǎn)系統(tǒng)中實(shí)時(shí)收集到業(yè)務(wù)運(yùn)行監(jiān)控?cái)?shù)據(jù),主要包括模型計(jì)算所需要的95Line,99Line以及QPS.
(2) 參數(shù)計(jì)算模型使用收集到的數(shù)據(jù)進(jìn)行并行計(jì)算,得到每個(gè)應(yīng)用所依賴服務(wù)所需的線程數(shù)s(thread)以及超時(shí)時(shí)間s(timeout).
(3) 考慮到系統(tǒng)性能問題,設(shè)定所有被調(diào)用服務(wù)的線程數(shù)s(thread)之和需要小于系統(tǒng)所在容器如Tomcat所設(shè)定的線程數(shù)c(thead),如果超出了c(thread)則進(jìn)行系統(tǒng)報(bào)警,提醒當(dāng)前所需線程數(shù)總和超過了最大容量,需要進(jìn)行干預(yù).
(4) 如果被調(diào)用服務(wù)的線程數(shù)s(thread)之和小于c(thread),則在線更改配置并實(shí)時(shí)生效.
(5) 生效以后,進(jìn)入下一個(gè)計(jì)算周期.
在進(jìn)行參數(shù)計(jì)算的過程中,考慮到實(shí)時(shí)收集數(shù)據(jù)數(shù)值的波動,計(jì)算所用數(shù)值采用一段時(shí)間的數(shù)據(jù),在實(shí)際應(yīng)用中為每隔1 分鐘會基于前1 分鐘的數(shù)值進(jìn)行計(jì)算,并將計(jì)算的結(jié)果根據(jù)上述流程進(jìn)行計(jì)算和應(yīng)用,整個(gè)過程可以在秒級完成,以保證系統(tǒng)安全,及時(shí)應(yīng)對流量突變.
1.3.3 無損上線
1.3.3.1 優(yōu)雅停機(jī)
在應(yīng)用重啟過程中,需要保證正在處理的請求能正常結(jié)束,并且在停機(jī)前主動通知調(diào)用方不在繼續(xù)向?qū)⒁C(jī)的服務(wù)器發(fā)送新請求,待所有請求處理完畢之后,進(jìn)行應(yīng)用的重啟.流程如圖4所示.
圖4 優(yōu)雅停機(jī)流程
通過這樣的流程,避免了在應(yīng)用重啟或者上線過程中的請求失敗,提高服務(wù)質(zhì)量.在航旅微服務(wù)體系中,主要通過在Web 容器中添加Socket 服務(wù)接收停止指令,在收到停止指令后,主動在Zookeeper 上下線該服務(wù)器對應(yīng)的所有相關(guān)服務(wù),利用Zookeeper 的實(shí)時(shí)通知機(jī)制,通知到所有調(diào)用方停止向這臺機(jī)器發(fā)送新的請求,并保證處理完所有已經(jīng)接收的請求后,進(jìn)行Web 容器的重啟.
1.3.3.2 流量預(yù)熱
在Web 容器啟動結(jié)束之后,端口已經(jīng)暴露成功,但是部分應(yīng)用會進(jìn)行基礎(chǔ)數(shù)據(jù)的預(yù)熱加載,而且JVM 也需要預(yù)熱加載相關(guān)的類,所以在Web 容器啟動后,并不完全具備承載高并發(fā)請求的能力,這種請求下如果有大量流量涌入,輕則部分請求響應(yīng)超時(shí),重則拖垮整個(gè)應(yīng)用.針對此類問題,在航旅微服務(wù)體系中,增加了啟動預(yù)熱模塊,針對某個(gè)服務(wù)的某臺機(jī)器重啟之后,根據(jù)服務(wù)注冊的時(shí)間,前5 分鐘之內(nèi)(可在分布式配置中心進(jìn)行動態(tài)調(diào)整),服務(wù)調(diào)方會根據(jù)啟動時(shí)間和這臺機(jī)器的具體權(quán)重,計(jì)算出一個(gè)相對合理的預(yù)熱權(quán)重,QPS會在5 分鐘內(nèi)逐步遞增到正常速度.預(yù)熱過程中的權(quán)重計(jì)算如式(3) .
其中,w代表預(yù)熱權(quán)重,now表示當(dāng)前請求時(shí)間,registerTime表示服務(wù)重新注冊時(shí)間,timeWindow表示預(yù)熱時(shí)間窗口,weight表示當(dāng)前機(jī)器權(quán)重.
通過本文研究的內(nèi)容在航旅縱橫中進(jìn)行了實(shí)際應(yīng)用,通過近一年的時(shí)間,對航旅縱橫的200 多個(gè)應(yīng)用,1000 多個(gè)服務(wù)質(zhì)量的改造,通過文中的研究成果提升服務(wù)的響應(yīng)時(shí)間,對協(xié)議調(diào)用鏈條中的響應(yīng)時(shí)間、線程數(shù)進(jìn)行計(jì)算和個(gè)性化設(shè)置,更大程度的保障協(xié)議的成功率和系統(tǒng)穩(wěn)定性.
如表1和表2所示,針對航旅縱橫APP 中的3 個(gè)核心業(yè)務(wù)航班動態(tài)、值機(jī)、行程改造前和改造后的數(shù)據(jù)進(jìn)行了對比:
如表1和表2中數(shù)據(jù)所示,改造前與改造后的數(shù)據(jù)相比,3 個(gè)業(yè)務(wù)的服務(wù)可靠性大幅提升,失敗率降低了至少一個(gè)數(shù)量級,絕大多數(shù)都降到了0.001%以下.響應(yīng)時(shí)間也有了較大的提高,其中航班動態(tài)以信息查詢?yōu)橹?,由提供?shù)據(jù)源的多個(gè)服務(wù)聚合而成,改造后響平均響應(yīng)時(shí)間和95 線縮短了1/2,值機(jī)響應(yīng)時(shí)間縮短接近1/3.
表1 改造前
表2 改造后
本文在圍繞微服務(wù)架構(gòu)中的服務(wù)質(zhì)量保障展開研究,定義了服務(wù)質(zhì)量的評價(jià)指標(biāo).圍繞評價(jià)指標(biāo),提出了縮短響應(yīng)時(shí)間以及提升服務(wù)可靠性的方法,并在業(yè)務(wù)系統(tǒng)中進(jìn)行了實(shí)際應(yīng)用,取得了不錯(cuò)的效果.通過本文的研究內(nèi)容,形成了一套提升服務(wù)質(zhì)量的標(biāo)準(zhǔn)方法,研發(fā)人員只需要遵循該方法,便可以開發(fā)出高質(zhì)量的服務(wù),可以將更多的精力投入到實(shí)際業(yè)務(wù)的研發(fā)中,大大提升了企業(yè)的研發(fā)效率.