本文主要帶你們瞭解服務穩定性的重要性和相關策略。策略大概分兩部分,第一方面從架構層面介紹保障服務穩定性的常見策略(限流,降級,隔離,超時,重試和集羣)。第二個方面是從流程方面(code review, 壓測,灰度和監控)講解怎麼去保證穩定性。php
演講嘉賓簡介:
信海龍(花名滄龍),十餘年的互聯網開發經驗,2013年加入阿里巴巴,深耕於電商、社區相關應用開發與架構。同時也是多個開源項目的開發者和維護者。表明開源做品,tclip,基於人臉識別的圖片裁剪擴展。redis
本次直播視頻精彩回顧,戳這裏!
直播回顧:https://yq.aliyun.com/live/965
PPT分享:https://yq.aliyun.com/download/3530
如下內容根據演講嘉賓視頻和PPT分享整理而成。算法
本次的分享主要圍繞如下三個方面:數據庫
對不少企業來講服務穩定性很是重要,首先穩定性問題會對企業帶來直接的經濟損失。舉例來講,亞馬遜的「Prime Day」當天出現的一個故障,給亞馬遜帶來了高達9900萬美圓的損失。這一個故障損失就多是其它小公司市值的幾倍。因此服務穩定性對公司影響是特別大的。而對於我的來講,服務不穩定性會影響員工的績效,甚至影響我的前程。後端
從架構層面保障穩定性,常見的策略包括限流,降級,隔離,超時,重試和集羣等。緩存
限流目的
限流的目的主要有兩點,第一點是防止系統高負荷運行,第二點是有效利用服務器資源。爲何要作限流?假如不封鎖請求,可能會致使服務器報警,若是平時服務器只能處理100個請求,忽然多出兩個請求服務器或許勉強可以處理,但忽然多了500個請求的話,後面的400個請求只處在積壓狀態,等服務器處理到第500個請求的時候,用戶等待時間就會過長,並且最後積壓部分的請求可能根本就是無效的處理,由於用戶早已流失。
限流算法
常見限流的算法包括漏桶算法和令牌桶算法。漏桶算法以下圖,圖中的例子有個小桶,桶下面有個孔,每流一滴水就能夠認爲是一個請求進去。滴水的速率是同樣的,孔的高度也是固定的。漏桶算法能保證每一個請求的負載時長,即肯定每秒能處理的請求數量。服務器
漏痛算法實現以下圖,能夠設定桶的高度是5個,每秒漏兩個。執行效果中前面5次結果都是true,以後中間一次結果是false,這說明桶已經裝滿,以後又漏了兩滴水,由於false的時候sleep了一秒,因此下面又有兩個true出來。網絡
令牌桶算法
以下圖,令牌桶算法也是有一個桶,可是桶不漏,桶裏面放了一些令牌,每來一個請求就在桶裏拿一個令牌,若是沒有令牌它就能夠等待,令牌滿了就再也不往裏面加令牌。這樣方法基本上也能夠達到一個限流的目的。令牌桶算法和漏桶算法的一個顯著區別是漏桶算法在後端取請求量時,基本上漏的速率是同樣的,可是令牌桶算法中後端部分能夠有突發請求,若是桶滿了,能夠將桶裏全部令牌都拿走。
下圖是令牌桶算法lua代碼實現部分,固然讀者還可使用Nginx,Java腳本或者php腳原本實現。架構
社區降級案例
通常狀況下,系統上線以後總會遇到一些不穩定狀況,好比redis掛掉,甚至後端數據庫My SQL掛掉。當出現不穩定狀況以後,系統如何保證繼續提供這些服務。以社區案例爲例,即使是My SQL掛掉,也要可以保證社區爲用戶提供基本的可讀服務。其中一個策略是將一些熱點數據,即用戶常常瀏覽的信息或者最新的信息緩存起來,當後端服務不可用的時候,把這些數據展示給用戶。大概流程以下圖,數據存儲部分後端會有一個腳本去分析Nginx裏面的日誌,而後去請求Vanish,Vanish再去請求後端,這樣的話Vanish會有一個有效期,可以保證Vanish存進去的數據都是用戶常常訪問的一些數據。第二步,如何保證後端數據庫掛掉的數據時候能遷過去?下圖能夠看到,Nginx中使用lua腳本進行實現,它會檢測後端服務返回的一些狀態,使用計數器計算失敗次數,若是頻繁的達到必定程度的失敗次數,就切換到從Vanish獲取數據,最後推送給用戶。這樣能保證即使是後端的數據庫掛掉,甚至即使全部的php進程都掛掉的時候,社區也能給用戶提供一些基本的服務。併發
降級目的
降級的目的比較簡單,第一個是保障服務器基本可用,第二個是保障服務的核心服務可用。降級是怎麼一個思路呢?通常降級的每一個策略都是針對一個場景,預想特定場景下須要要解決什麼問題;而後再梳理在這個場景下須要保留哪些核心基本服務;最後才選定技術方案,系統化的進行實現。簡單講就是先肯定須要達到什麼目的,再去了解是什麼樣的狀況,最後制定策略或者計劃。好比,系統會調用第三方服務,而第三方服務有可能掛掉,這是一種典型的場景。再好比,系統自己調用推薦服務,可是推薦服務也會掛掉,這種場景下不可以由於沒有推薦數據就不顯示數據,仍是須要展現一些數據,這是一種基本的核心服務。每一年的雙11或者一些大型活動中基本都會存在降級。降級不只僅是存在於資源故障場景下,資源不夠用時也可能會須要降級,由於資源不夠用須要關注重點。如大促活動中,須要先保證交易服務正常運行,其它消耗資源的服務(如對帳)能夠後續再去處理。
超時案例
社區對外提供接口服務,對方的反饋是接口服務較慢。接口部分流程是查一段數據,而後將數據反映過去,其問題點在於系統中超時時間設置過長。好比調用Memcache,可是Memcache已經掛掉,因爲超時設置過長,數據須要等到超時時間結束之後再返回,致使接口一直在等待。那如何設置超時時間才合理?要注意超時時間並非固定的值,而是須要針對整個業務,根據特定場景設置超時時間值。
如何設置超時時間
大致的思路以下圖。第一步,識別業務須要的服務響應時間。好比,須要100毫秒去響應數據,以後統計業務裏面可能須要調多少服務。第二步,統計服務平常的響應時間。第三步,分清主次,即分出哪些是核心服務。由於核心服務一旦失敗,整個鏈路便不可用,因此能夠對核心服務的時間設置的寬鬆一些。若是一些服務調不通,但又不影響整個鏈路,能夠對它的時間設置的相對嚴格。
設置完超時以後須要驗證,藉助模擬手段封端口(以下圖),模擬故障,而後檢查數據返回時間是否在指定的時間內。
隔離案例
下2013年左右,手機客戶端開始逐漸升級起來,不少項目既有PC端也有客戶端,因此同一個服務即要爲PC端又要爲客戶端提供API接口。一旦遇到大型活動或者須要手機推送,服務會遇到不穩定狀況,服務的不穩定會致使PC端也受影響,因此須要將服務進行物理隔離,從原先耦合到一塊的服務器分到不一樣的機器組。隔離目的很是簡單,要限制住不穩定因素致使的風險,中止傳播。
隔離形式
隔離的常見形式包括幾種。第一是秒殺場景,秒殺場景一個高併發的場景,可能帶來的問題也比較多,在高併發場景下秒殺的時候,須要和一些正常的業務區分開來,不建議一臺機器既提供秒殺也提供進程服務。另外,秒殺的時候會產生熱點數據,如售賣數據。數據庫更新比較頻繁,從數據庫層面也能夠進行隔離,將熱點部分和正常服務部分從資源上隔離。第二個場景是慢SQL隔離,一個資源隔離。一條慢SQL會致使整個服務不穩定。每請求一次線程,慢SQL會一直耗着當前線程,因此資源佔用很是大。第三個場景是機房隔離。通常大公司都會作多機房部署,其目的就是確保穩定性。確保穩定性時不要作跨機房調用,不然耦合度會比較高,假如A調B,B掛掉,A服務也會受影響。通常確保穩定性都是作本機房的調用。並且本機房的調用性能也比較快。最後一個場景是進程隔離,由於進程比線程更加穩定。
對小公司而言,一臺機器就提供一個服務,若是機器掛掉服務恢復就會成爲一個問題。通常解決方法是作一個集羣,從原來的一臺機器提供服務變爲能夠用多臺機器提供服務。集羣的目的是爲了解決單點的問題。集羣的形式主要有主備,即同時只有一臺機器提供整個服務,能夠有一臺或者多臺提供備份,備份不只要包含代碼層面,整個服務運行所依賴的資源都要有備份。另一個形式是主從。主是提供一個完整的服務,從是提供部分的服務。還有一種是多主,多主指的是每一臺機器的決策是對等的,都會對外提供一些服務。隨着集羣形式的不一樣,對代碼編寫的併發性上有必定要求。主備只須要考慮單機的併發控制,主從是考慮同時提供服務的部分。好比加鎖,主備上只要加一個本地的技能鎖就能夠,主從或者多主則須要加分佈式鎖。
保證穩定性策略的流程方面上分爲下圖中四個點,code review, 壓測,灰度和監控。
code review目的是在項目上線前及時發現一些問題。經驗比較豐富的人能夠將經驗進行分享。code review基本通過三個階段。第一個階段是頭腦風暴式,一羣開發人員圍着代碼作code review,雖然時間成本較高,效果也不太理想,可是這種方式也有好處,在前期能夠將你們的意見進行整理,制定code review的規範。第二種code review形式是演講式,專家事先把代碼作一下review,整理一些點,而後進行分享。演講式能夠按照輪崗制,相對頭腦風暴式大大節約了時間。目前常見的code review 形式是結對式,由一個或者兩個專家結對,相互review,時間上比較靈活,也不須要佔據會議室資源。
壓測目的
壓測的目的,第一是保證系統穩定性。在高併發的時候,檢測系統是否穩定,由於一些問題在流量比較低的時候發現不了,只有在高併發的時候才能發現這個問題。第二是檢測性能的抗壓能力,檢查系統能承受多大的QPS。
壓測關注點
首先,壓測機器和被壓測服務在同一網段,儘可能避免由於網絡緣由致使壓測的結果不許確。第二點是關注服務器的負載,注意不要把服務器壓到100%,服務器快要崩的時候,獲得的值意義不大。應該是服務器負載達到60%~70%的時候,看QPS是多少。另外,壓測併發數據是逐步遞增的過程,到一個點的時候,併發數據越多表明QPS越低。最後,根據測試環境的壓測結果估算線上的承載能力。估算的公式是線上QPS = 單機QPS 機器數 0.7。後面會乘以一個係數(0.7)是由於線上put上去的時候總會存在一些損耗。
全鏈路壓測
但有一些測試在測試環境下沒法實現壓測,因此如今發展成了全鏈路壓測。全鏈路壓測大概分紅三個核心關注點。第一個是數據模型的構造。全鏈路壓測是模擬線上真正的數據模型,好比說訪問詳情頁的人數,下單的人數,人數比例,登錄人數等等參數,儘可能按照真實數據模擬,構建仿真模型,這樣才能真正的發現線上的一些問題。注意全鏈路壓測不是在測試環境下實現,而是在線上壓測。第二個是壓測工具構建。能夠是藉助開源的壓測工具,阿里自建了壓測平臺,根據數據模型提高流量。第三點是流量的隔離。對流量增長標識,保證不影響線上的數據,將全鏈路測試流量放到測試的存儲中。好比生成一個訂單order表,同時也會生成一個影子表test_order。若是發現是來自於全鏈路壓測的流量,就把這個數據寫到影子表test_order裏面,這樣可以保證存儲。不管是緩存仍是數據庫存儲都可以進行流量隔離。
灰度目的是小範圍試錯,儘可能發現問題。灰度的策略大概有如下幾種,第一個策略是隻讓某一個地區的人先訪問最新的特性,遇到問題的話用戶及時反饋,問題也只會影響特定地區。另一個策略是基於用戶屬性,如一個推薦系統,請求過來的時候能區分新老用戶,它對新老用戶的推薦的策略多是不同的,從而來驗證策略的準確性和有效性。第三種策略是基於數據,從一批用戶中選取幾個用戶進行處理。好比,對供應鏈的供應商的數據作處理,可是通常狀況下不敢保證代碼上線以後100%沒問題。這時先選擇一個供應商處理,驗證數據,確保沒問題再全量處理全部的供應商。最後是基於平臺,通常都發生在客戶端場景下。客戶端與服務端不一樣,服務端通常是針對這個平臺,先指揮這個平臺先發布新版本,反饋不錯再推到整個全面平臺。對於客戶端的灰度技術的實現以下圖,給客戶端集中一個Cookie,請求到了以後在Nginx中去檢查Cookie,根據不一樣的Cookie把情趣轉到不一樣的組。好比組A有新特性,組B是老版本,根據不一樣的Cookie轉到不一樣組,保證只有一部分人能夠看到新的特性。
監控注意點
監控的目的是能夠自動化及時發現問題。監控須要注意幾點問題,第一是全方面監控,系統和服務所有都要監控。第二是報警分級,監控報警的係數設置的要合理。最後一點是在真實環境下作數據收集。好比,A和B服務器,只在B服務器作監控。若是A服務器My SQL數據庫網絡出問題後,由於在監控上B服務器是正常的,監控不會報警。因此要在應用服務器上作監控纔會報警具體哪臺機器哪一個服務出現故障等信息。
自研監控系統
下圖是阿里自研的監控系統。首先肯定對哪些指標進行監控。將整個指標的數據繪製出來,查看指標數據波動。一旦遇到問題,能夠很方便的進行對比。另外要肯定影響,將全部相關的指標聚合起來。好比供應商的團隊操控系統常常會發生倉庫操做卡頓,有不少因素都會致使卡頓,如PC端調用其它接口較慢,服務器load比較高等。倉庫人員沒法關注具體的細節,他們在影響界面查看指標影響值,一眼就能夠知道是哪項指標不合格致使的卡頓。以後對形成的影響進行相應的處理,目前通常的行爲有效報警或短信報警。
原文連接 本文爲雲棲社區原創內容,未經容許不得轉載。