營春曉
摘 要: 在大型網(wǎng)站和軟件系統(tǒng)中,由于業(yè)務(wù)的復(fù)雜性,常采用服務(wù)組件化的架構(gòu)策略來達到解耦和可擴展的目的。在服務(wù)按業(yè)務(wù)功能切分后,如何提高整個系統(tǒng)的可用性是一個非常重要的問題。文章在對大型網(wǎng)站服務(wù)組件化設(shè)計架構(gòu)研究的基礎(chǔ)上,結(jié)合服務(wù)組件之間強弱依賴關(guān)系的特點與典型場景,總結(jié)了服務(wù)隔離技術(shù)的基本思想和維度,提供了服務(wù)調(diào)用解耦與隔離方法、容器級別服務(wù)故障隔離方法、組件服務(wù)間接依賴故障隔離方法等來提高系統(tǒng)的可用性。
關(guān)鍵詞: 系統(tǒng)高可用性; 強弱依賴; 故障隔離; 服務(wù)組件化
中圖分類號:TP391.12 文獻標(biāo)志碼:A 文章編號:1006-8228(2015)04-21-02
Abstract: Because of the complexity of business, the large web sites and software system use service component architecture to get ultra-scalable and highly decoupling purpose. According to the business service functional segmentation, how to improve availability of the whole system is a very important problem. Based on the research of large web site service component architecture, combined with the characteristics of strong-weak dependence and typical scene, this paper provides the service call decoupling method, the container services fault isolation method and the component services fault isolation method to improve the system availability.
Key words: high availability; strong-weak dependency; fault isolation; service component
0 引言
大型網(wǎng)站及軟件系統(tǒng),其高可用性直接影響客戶體驗,這是大型網(wǎng)站都需要面對的基礎(chǔ)性課題。高可用性涉及到IT基礎(chǔ)設(shè)施、軟硬件架構(gòu)、開發(fā)測試、運維等各個方面。目前,大型網(wǎng)站通常是領(lǐng)域業(yè)務(wù)多元化,面臨高并發(fā)、高流量的挑戰(zhàn)。為了獲得更好的性能和可擴展性,按照服務(wù)組件化設(shè)計思想,以領(lǐng)域業(yè)務(wù)為功能單元做垂直切分,各模塊之間提供服務(wù)接口關(guān)聯(lián)起來,這樣可以提高整個系統(tǒng)的可用性。然后隨著應(yīng)用規(guī)模的擴大,服務(wù)之間的依賴關(guān)系更為復(fù)雜,如何在系統(tǒng)出現(xiàn)故障或異常時,避免由“點故障”到“面故障”的擴散,避免不同領(lǐng)域業(yè)務(wù)相互影響,避免非核心影響核心,是開發(fā)者在做應(yīng)用架構(gòu)設(shè)計與物理部署架構(gòu)設(shè)計時必須要考慮的問題。
本文結(jié)合日常項目中的實踐經(jīng)驗,提出在服務(wù)組件化的過程中,如何做服務(wù)級故障隔離的原則和方法,提升網(wǎng)站可用性這一需求。
1 服務(wù)級隔離基本思想
形式上,系統(tǒng)與系統(tǒng)之間,服務(wù)與服務(wù)之間(無論是兩個服務(wù)是否為同一業(yè)務(wù)組件)存在以下兩種依賴關(guān)系。
⑴ 強依賴。所謂A系統(tǒng)強依賴于B系統(tǒng)是指,A系統(tǒng)必須依賴B系統(tǒng)的處理結(jié)果,才能正常的完成邏輯;簡單的來說,如果B不能提供服務(wù),A也無法正常工作。從高可用性設(shè)計的角度出發(fā),在這種依賴關(guān)系下,A與B系統(tǒng)需要達到如下幾點目標(biāo):對于B系統(tǒng),A直接RPC調(diào)用,B在承諾的SLA基礎(chǔ)上,做好自我保護;B系統(tǒng)宕機時,A盡管不能使用,但要保證機器不掛掉;B系統(tǒng)故障恢復(fù)時,A可以自動快速恢復(fù);B故障時,A可以自動檢測,自動降低或關(guān)閉對B的訪問,防止情況惡化。
⑵ 弱依賴。所謂A系統(tǒng)弱依賴于B系統(tǒng),是指B系統(tǒng)如果發(fā)生了故障,A系統(tǒng)可以繼續(xù)提供正常的服務(wù)。弱依賴通常有這些特點:可以不等待B結(jié)果的返回(比如發(fā)送消息、ajax區(qū)域加載);B是非核心功能,結(jié)果不返回不影響A的關(guān)鍵流程(合理超時時間的控制),A、B的調(diào)用可以是異步(隊列、線程的FutureTask、協(xié)程akka);對B的服務(wù)調(diào)用可通過功能開關(guān)實現(xiàn)降級。
針對強依賴與弱依賴的不同特點,在架構(gòu)和設(shè)計時,為避免故障或異常時由“點故障”到“面故障”的擴散,我們考慮在區(qū)分核心與非核心(服務(wù)、組件、產(chǎn)品重要度分級)、按功能組與后臺依賴隔離、同一容器內(nèi)服務(wù)間隔離、按客戶群體DNS層隔離、引入異步模式隔離服務(wù)調(diào)用者與提供者等層面和場景下提供服務(wù)故障隔離策略和方法。
2 具體隔離策略與方法的設(shè)計
本節(jié)根據(jù)服務(wù)之間的依賴關(guān)系以及物理部署結(jié)構(gòu)等特點,總結(jié)服務(wù)間如何做隔離和解耦的策略和方法。
2.1 服務(wù)間依賴隔離與解耦
在服務(wù)A與B存在強依賴的情況下(如圖1所示),描述RPC與基于Queue兩種方式的區(qū)別。
正常情況:A系統(tǒng)對外承諾500的TPS,系統(tǒng)的平均響應(yīng)時間為100ms,這時候只需要50個線程并行即可支撐。
故障情況:B系統(tǒng)變慢,導(dǎo)致A的平均響應(yīng)時間變?yōu)?000ms,現(xiàn)在A系統(tǒng)的線程數(shù)是500。
B系統(tǒng)的異常,在直接RPC的調(diào)用情況會導(dǎo)致A系統(tǒng)宕機,同時B系統(tǒng)由于A系統(tǒng)的并發(fā)訪問數(shù)由50變?yōu)?00,B系統(tǒng)進一步惡化。由此可見,在RPC的調(diào)用方式下,無論是同步調(diào)用還是異步調(diào)用,對于服務(wù)器端都是直接壓力傳導(dǎo),在A與B是強依賴的情況下,如果是同步RPC調(diào)用,超時控制在異常時刻是決定性問題。在強依賴的情況下,除了需要在采用RPC調(diào)用的時候合理的設(shè)置超時外,在架構(gòu)時可用采用基于消息隊列的方式,來達到服務(wù)間由于容量不匹配導(dǎo)致的強耦合(如圖2所示)。圖2中,如果調(diào)用者不需要服務(wù)方返回結(jié)果,則橢圓框的部分是不需要的。
與基于RPC的方式相比,隊列模式有如下特點。
⑴ 為服務(wù)調(diào)用者與服務(wù)提供者解耦,隊列模式尤其適合弱依賴情況下的異步單相消息模式。
⑵ 引入隊列中間層可以對任務(wù)做優(yōu)先級、丟棄策略、持久化等,同時由于中間節(jié)點的存在,也引入了復(fù)雜性,從響應(yīng)時間來看,與RPC方式相比會有所增加。
⑶ 在應(yīng)對突發(fā)尖峰流量時,服務(wù)端可以實現(xiàn)壓力逐步釋放的目標(biāo),保持穩(wěn)定吞吐率,達到“穩(wěn)定消化能夠處理的量,快速丟掉不能消化的量”,客觀上達到了服務(wù)組件間解耦的目的。
2.2 同一容器內(nèi)服務(wù)間線程隔離
在系統(tǒng)服務(wù)化的切分過程中,通常是以業(yè)務(wù)領(lǐng)域的切分為依據(jù),屬于同一業(yè)務(wù)領(lǐng)域的服務(wù)在部署時基本部署在同一個容器中。由于各個服務(wù)對于資源的消耗不同,響應(yīng)時間與關(guān)聯(lián)組件也不相同,導(dǎo)致在容器線程總數(shù)固定情況下,其中一個服務(wù)突然變慢會占用大量線程,導(dǎo)致線程耗盡。同時線程數(shù)飆升,引起Context Switch[1]加劇,在JAVA平臺下,還會引起對象生命周期變長,F(xiàn)ull GC頻繁,CPU Load Average和Usage高企[2],最終容器整體宕機。
為解決容器內(nèi)的服務(wù)線程隔離問題,在實踐中首先需要根據(jù)歷史訪問數(shù)據(jù)及系統(tǒng)容量規(guī)劃的數(shù)據(jù),計算出每個服務(wù)的峰值與均值并發(fā)數(shù)、響應(yīng)時間、交易吞吐率等,具體的數(shù)據(jù)采集與分析過程在本文中不作詳述。對于服務(wù)隔離策略的設(shè)計可以采用定額與彈性資源配置兩種方式。
⑴ 悲觀策略:對于每個服務(wù)設(shè)定固定的最大資源量,任何一種服務(wù)當(dāng)訪問量達到最大時,即使總資源存在富余也不能使用。
⑵ 樂觀策略:在保證每種服務(wù)預(yù)留最低資源的情況下,允許任務(wù)依據(jù)一個彈性配額去爭搶線程資源,達到線程利用率的最大化。
2.3 核心與非核心服務(wù)隔離
組件A與組件B都強依賴于組件C,同時組件C強依賴于組件D。其中組件A屬于非核心業(yè)務(wù)組件,B屬于核心業(yè)務(wù)組件。由于C組件總體處理能力是固定有限的(假定平均響應(yīng)時間100ms,最大TPS為3000/s),當(dāng)A組件由于突發(fā)流量的影響,對C組件訪問量變大,或者A組件的某些請求會耗費C組件較多的資源時,導(dǎo)致C組件不能處理B組件的請求,級聯(lián)導(dǎo)致B系統(tǒng)出現(xiàn)故障的情況發(fā)生。在這個場景下,雖然A與B在物理部署上已經(jīng)做了隔離,但是復(fù)雜的關(guān)聯(lián)組件依賴關(guān)系,間接導(dǎo)致因為非核心業(yè)務(wù)組件影響核心業(yè)務(wù)組件的事例。為避免上述問題的發(fā)生,可以考慮以下兩種隔離策略。
⑴ 如果C組件及其關(guān)聯(lián)組件水平伸縮后,可以支持更高的性能,推薦采用路由隔離方式進行,即A組件與B組件分別訪問不同C組件服務(wù)群組。
⑵ C系統(tǒng)不具備進一步水平擴展的能力(比如瓶頸點不在C,而在于C所依賴的系統(tǒng)D);這個時候可以在C系統(tǒng)上設(shè)置流量控制和功能開關(guān)標(biāo)志位,在異常情況下可以限制或關(guān)閉非核心系統(tǒng)對C的訪問。
2.4 服務(wù)功能開關(guān)與降級的設(shè)計
在各種服務(wù)隔離策略中,當(dāng)異常流量發(fā)生時,在了解全局服務(wù)依賴關(guān)系和服務(wù)重要度排列的基礎(chǔ)上,架構(gòu)設(shè)計中通常使用功能開關(guān)和服務(wù)降級的策略來分解流量,達到“丟卒保車”的目的來應(yīng)對突發(fā)狀況。在具體的實踐中主要考慮三個方面。
⑴ 管理全局性服務(wù)組件的依賴關(guān)系,識別各服務(wù)調(diào)用鏈中的關(guān)鍵路徑。在大型網(wǎng)站中,通常存在上千級別的組件,服務(wù)之間的依賴關(guān)系異常復(fù)雜,大部分網(wǎng)站都實現(xiàn)了基于Google的Dapper[3]系統(tǒng)的分布式系統(tǒng)監(jiān)控與依賴分析系統(tǒng)。
⑵ 功能開關(guān)的設(shè)計。在設(shè)計實現(xiàn)時,存在單機與集群的區(qū)別。單機實現(xiàn)時,對于JAVA平臺建議使用JMX標(biāo)準(zhǔn)實現(xiàn),這樣做的好處是可以納入統(tǒng)一的監(jiān)控體系,使用JConsole等通用JMX Client可以處理;集群實現(xiàn)時,由于需要對大量節(jié)點統(tǒng)一管控,建議使用Zookeeper之類的配置管理系統(tǒng)來實現(xiàn)。
⑶ 自動降級與手動降級的設(shè)計與運用。自動功能開關(guān)的設(shè)計主要是首先確定判斷異常情況的閾值,比如單位時間內(nèi)服務(wù)調(diào)用超時或失敗比例超過70%,或者連續(xù)失敗或超時達到20。此時系統(tǒng)可以把訪問窗口按指數(shù)降低,直到降為1;服務(wù)恢復(fù)類似于TCP的慢啟動[4],窗口逐漸打開。對于封閉點,應(yīng)該盡可能提前;對于一些關(guān)鍵系統(tǒng),如支付類系統(tǒng),最好避免使用自動開關(guān),在接到監(jiān)控系統(tǒng)報警后,人工介入決定是否需要降級和關(guān)閉。
3 結(jié)束語
目前新華網(wǎng)要求整體可用性達到99.99%級別,這意味著全年計劃停機時間加上非計劃停機時間不到53分鐘。系統(tǒng)的高可用性是一個系統(tǒng)性工程,除了IT基礎(chǔ)設(shè)施外,在軟件層面要具備快速發(fā)現(xiàn)定位的監(jiān)控系統(tǒng),要擁有完善的容量規(guī)劃與評測方法,要有應(yīng)對峰值流量的策略和手段等,這些會涉及到軟件過程與基礎(chǔ)軟件建設(shè)的各個方面。本文提出了在實踐中總結(jié)出來的方法與策略可以為有相似需求的系統(tǒng)提供參考與借鑒。
參考文獻:
[1] DANIELP.BOVET&MARCO CESATI.深入理解LINUX內(nèi)核[M].中國電力出版社,2007.
[2] 林昊.分布式Java應(yīng)用基礎(chǔ)與實踐[M].電子工業(yè)出版社,2011.
[3] SIGELM, N B, BARROSO L, BURROWS M, et al. Dapper, ALarge-Scale Distributed Systems TracingInfrastructure.[R].Google,2010.
[4] W.Richard Stevens.TCP/IP Illustrated Volume 1:The Protocols[M]. Boston: Addison-Wesley,December 15,1993(1):233-240