現在而今眼目下,互聯網越來越發達,大家不管是幾乎每天24小時不離手的手機,還是工作時每天要打開的電腦,還是我們使用的各種社會工具和衣食住行的方方面面,各種軟件應用已經成為我們生活中必不可少的一部分。軟件的功能是否能滿足需求,是我們關心的首要問題,軟件是否穩定,也是一個重要的指標,也就是軟件系統的可用性如何,在遇到一些問題時,系統的容錯性如何,是否仍然能夠對外提供服務,以及服務的效率如何,是迅速就能返回還是要等待很久。
回顧剛過去的2019年一年,全球大型互聯網公司發生了數十起宕機事故,google、Microsoft、Amazon 、Facebook、阿里、騰訊等無一幸免,短則數分鐘,長則數小時,有的是天災,有的是人禍。對于用戶上億的商業應用來說,哪怕是一分鐘的宕機,損失都非常巨大,一個中等嚴重的故障可能會讓你損失一輛車,一個outage可能就會讓你損失數座房子了。騰訊2018年宕機4小時,據估算損失了5000多萬。
如何衡量軟件的可用性呢?
其度量方式,是根據系統損害、無法使用的時間,以及由無法運作恢復到可運作狀況的時間,與系統總運作時間的比較。計算公式為:
A=MTBF/(MTBF+MDT)
A(可用性),MTBF(平均故障間隔),MDT(平均修復時間)
可用性為99.999%的系統,一年故障時間為5分15秒;可用性為99.99%的系統,一年故障時間為5分34秒;可用性為99.9%的系統,一年故障時間為8小時46分。
在線系統和執行關鍵任務的系統通常要求其可用性要達到5個9標準(99.999%)。
當然,除了這個數據之外,我們也要看宕機發生在什么時候,才能綜合評估事故影響的嚴重性,造成的損失到底有多大。當我們不得不主動的關閉或重啟一些服務的時候,如何把影響減到最小。
軟件應用一旦進入生產系統,接入了大量的用戶,我們就得盡量保證它是24小時可用的,為用戶提供不間斷的服務。軟件的高可用性(High availability -- HA),是一項非功能特性,在大型產品的架構設計階段就需要專門納入進來考慮。軟件系統會劃分為多個不同的模塊,重要的組件或模塊,都需要列出HA的Feature實施計劃。
為了實現軟件系統的高可用性,都有哪些關注點和技術手段呢?
1. 冗余設計和Fail over
冗余設計的核心目的是為了避免單點故障導致整個系統不可用,在不同的層級增加冗余,當單點故障發生時,可動態的把服務切換到正常的上面,從而能夠繼續為用戶提供服務。冗余設計可以從幾個方面進行考量:
1. 地理環境,如果你的所有服務器都在同一個地方,一場洪水或地震將讓你的整個系統和數據化為烏有。大型系統通常都會把服務器或數據中心分布在不同的地域。這將有助于提高系統的可用性。
2.硬件,高可用的服務器必須對諸如停電,硬件損壞(如硬盤損壞,網卡損壞)等具有承受能力。
3. 軟件,從操作系統到應用程序本身的整個軟件棧,都需要設計來能應對非預期的失敗而必須重啟的情況。
4.數據,由于硬盤故障帶來的數據丟失和數據不一致的情況,如何處理。高可用性系統必須要把故障情況下的數據安全考慮進來。
5.網絡,非預期的網絡中斷是系統可能遇到的另一個問題。網絡冗余策略也是非常有價值的。
先來看看軟件設計層面應當如何考慮冗余,一個比較典型的B/S 架構的應用如下圖所示。
我們在其每一層,都可以做冗余處理。
在網關層,我們可以配置多個網關,用keepalived管理起來,給它們分配一個浮動IP,當主網關出問題時,我們可以把浮動IP分配給備用網關,這樣仍然可以繼續對外提供服務。
在Web應用層,可以配置多個web后端,比如使用Nginx做網關層的反向代理時,它可以配置多個web后端,并且能夠檢測到多個后端的存活性,當一個web服務掛了時,nginx可以自動進行故障轉移,將流量遷移到其他的web服務上。
業務服務層也可以實現冗余,在web應用層通過建立服務連接池來與下游的服務建立多個連接,每次請求可以隨機的選擇連接來訪問下層的服務。當某一個service掛了的時候,連接池的管理器能夠檢測到,并自動進行故障轉移。
大型系統的服務層下通常會有一個緩存層,數據緩存也可以實現冗余來達到高可用,
我們在每一個邏輯層,都可以增加冗余。如果其中一個服務掛了,可以通過自動的故障轉移(fail over),讓其他服務點繼續提供服務。通過緩存數據的冗余實現的,常見實踐是緩存客戶端雙讀雙寫,或者利用緩存集群的主從數據同步與sentinel保活與自動故障轉移;更多的業務場景,對緩存沒有高可用要求,可以使用緩存服務化來對調用方屏蔽底層復雜性
數據庫層的冗余可以采用”主從同步,讀寫分離”的架構,可以把它分為“讀庫高可用”和“寫庫高可用”兩類。“讀庫高可用”的常見實踐是通過db-connection-pool來保證自動故障轉移,“寫庫高可用”則是通過寫庫的冗余實現的,常見實踐是keepalived + virtual IP自動故障轉移。
文件存儲部分,對于上層文件系統而言,邏輯上是一個整體,我們可以使用分布式文件系統,利用分布式集群,提供對文件系統的支持,對外提供統一的命名空間,文件系統內部也實現了各種冗余和負載均衡操作,有比較好的容錯性,提高了文件系統的可用性。
分布式文件系統廣泛流行前,對存盤數據的高可靠性,可以引入RAID(獨立冗余磁盤陣列)。RAID 技術將多個單獨的物理硬盤以不同的方式組合成一個邏輯硬盤,同一份數據會以一定組合方式,寫入多塊磁盤。即使其中部分磁盤損壞,仍然可以保證數據的可用性。
2. 無狀態設計
要想服務能夠切換,做故障轉移(fail over或fail back),很重要的一點就是不要保存業務的上下文信息,而僅根據每次請求提交的數據進行相應的邏輯處理,這樣的話,多個服務實例之間就是完全對等的,請求提交到任意服務器,處理的結果是完全一樣的。在這個情況下,我們就可以利用負載均衡進行無狀態服務的失效轉移。
但是我們總要管理session信息,這些信息可以下沉到緩存層和數據庫層。這樣服務層就可以根據需要做到動態的Scale-out/Scale-In和高可用了。
3. 負載均衡
上文談到的幾點,都可以看到負載均衡的影子,大型系統的網關層基本都會引入負載均衡,負載均衡可以提高系統并發性支持,反過來說減輕了單一服務的壓力,提高了系統的可用性,通常會有兩種形式:
· 硬件負載—F5 7層或4層網絡代理
· 軟件負載—Nginx, Haproxy等開源的負載均衡軟件。
常用的算法通常有
1. 輪詢法
2. 隨機法
3. 源地址哈希法
4. 加權輪詢法
5. 加權隨機法
6. 最小連接數法
4.冪等設計
什么是冪等性呢,簡而言之就是同樣的請求,即使多次重復,也必須得到相同的結果。
冪等性在支付類場景尤為重要,比如重復的的訂單號,同樣的金額,不做冪等性設計,重復支付可能就會造成金額累加。
對于服務冪等性設計的要點就是一定要效驗請求參數有效性,及已有數據的對比。如果同樣的請求參數已經處理過就不要重復處理,直接返回,這就是冪等性核心點。
5. 超時機制
我們的服務,尤其是微服務化的場景下,通過REST API進行相互調用,為了保證系統的可用性,就需要對調用設置超時機制,一旦被調用服務超時還未返回,主調服務就應該進入超時處理流程。這樣就不至于在某個服務不可用時,整個系統進入阻塞狀態。
6.異步調用
采用異步調用方式調用被調用的服務,有助于將主調服務和被調服務解耦,減少等待時被阻塞的情況,并能提高系統的并發性能。對于不需要關心直接返回結果的請求類型以及當請求流程不是系統的關鍵路徑時,采用異步化是非常有價值的。
7.服務分級與降級
在一個大系統中,一般會有核心服務和次要服務之分,那么對于不同的服務可以采用不同的處理方案,出現故障時應該優先保證核心服務的運行,對于次要的服務,可以延遲服務或在粒度范圍內關閉服務。服務降級一般是關注業務,對業務進行考慮,抓住業務的層級,從而決定在哪一層上進行處理:比如在IO層,業務邏輯層,還是在外圍進行處理。
8.服務熔斷
服務熔斷也叫服務的過載保護,服務熔斷對服務提供了proxy,防止服務不可能時,出現串聯故障(cascading failure),導致雪崩效應。服務熔斷一般是某個服務(下游服務)故障引起,而服務降級一般是從整體負荷考慮;對于設計的任何一個系統,都需要進行容量的預估和最大容量設置,當外部請求量超過最大QPS容量時,應該啟動防雪崩機制,以避免大量外部請求把服務壓跨而不能對外提供服務。
9.系統監控
大型系統的服務模塊眾多,經常會因為各種原因出現進程掛掉,網絡質量不好,機器宕機等現象,我們設計的系統應該具備監控上報和告警的能力,運維和開發能夠通過監控報表實時的查看系統的運行狀態。服務一旦出現問題能夠及時發現,通過自動化處理,或者人工介入處理,從而達到縮短系統的不可用時間,提高可用性。
常見的監控指標有:CPU、帶寬、內存使用率、網絡連接狀態,系統調用錯誤,成功率,PV,UV等。
談了主要的應用治理,解析來要說說數據治理,它對于提高系統的響應效率也非常重要。
10.數據緩存
當讀寫的并發數越來越大時,數據庫很容易成為系統的瓶頸,因此在大型系統中,緩存系統的設計就非常有必要了,設計良好的緩存系統,可以大大提高系統的可用性和并發效率。
11.數據庫優化
我們需要的數據庫不僅是要穩定,能提供服務,也要考慮其提供服務的效率,當數據庫里面的數據有百萬條以上時,查詢效率就變得很低了。不僅需要考慮前面提及的讀寫分離,我們也需要根據業務特點,做出適當的分庫、分表、分區策略,建立合適的索引。從而大大提高數據插入和查詢效率。
前面講了架構設計時應當考慮的高可用的技術手段,還有一點不可忽視的是我們的產品如何部署到生產系統中,尤其是在做產品升級的時候,升級是offline的還是online的?我們能保證不帶來一點down time嗎?如果系統部署到一半失敗了,而線上數據還在源源不斷的進來,怎么處理?如果部署失敗了,系統能在不丟失新數據的情況下回滾嗎?這些都可用性設計時需要考慮的問題,做不好就會帶來糟糕的客戶體驗。