天天看點

聊聊服務穩定性保障這些事

信海龍(花名滄龍),十餘年的網際網路開發經驗,2013年加入阿裡巴巴,深耕于電商、社群相關應用開發與架構。同時也是多個開源項目的開發者和維護者。代表開源作品,tclip,基于人臉識别的圖檔裁剪擴充。

01

穩定性的重要性

對很多企業來說服務穩定性非常重要,首先穩定性問題會對企業帶來直接的經濟損失。舉例來說,亞馬遜的“Prime Day”當天出現的一個故障,給亞馬遜帶來了高達9900萬美元的損失。這一個故障損失就可能是其它小公司市值的幾倍。是以服務穩定性對公司影響是特别大的。而對于個人來說,服務不穩定性會影響員工的績效,甚至影響個人前程。

聊聊服務穩定性保障這些事

02

保障政策架構篇

從架構層面保障穩定性,常見的政策包括限流,降級,隔離,逾時,重試和叢集等。

聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事
2.1.限流

  • 限流目的

限流的目的主要有兩點,第一點是防止系統高負荷運作,第二點是有效利用伺服器資源。為什麼要做限流?假如不封鎖請求,可能會導緻伺服器報警,如果平時伺服器隻能處理100個請求,突然多出兩個請求伺服器或許勉強能夠處理,但突然多了500個請求的話,後面的400個請求隻處在積壓狀态,等伺服器處理到第500個請求的時候,使用者等待時間就會過長,而且最後積壓部分的請求可能根本就是無效的處理,因為使用者早已流失。

  • 限流算法

常見限流的算法包括漏桶算法和令牌桶算法。漏桶算法如下圖,圖中的例子有個小桶,桶下面有個孔,每流一滴水就可以認為是一個請求進去。滴水的速率是一樣的,孔的高度也是固定的。漏桶算法能保證每個請求的負載時長,即确定每秒能處理的請求數量。

聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事

漏痛算法實作如下圖,可以設定桶的高度是5個,每秒漏兩個。執行效果中前面5次結果都是true,之後中間一次結果是false,這說明桶已經裝滿,之後又漏了兩滴水,因為false的時候sleep了一秒,是以下面又有兩個true出來。

聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事
  • 令牌桶算法

如下圖,令牌桶算法也是有一個桶,但是桶不漏,桶裡面放了一些令牌,每來一個請求就在桶裡拿一個令牌,如果沒有令牌它就可以等待,令牌滿了就不再往裡面加令牌。這樣方法基本上也可以達到一個限流的目的。令牌桶算法和漏桶算法的一個顯著差別是漏桶算法在後端取請求量時,基本上漏的速率是一樣的,但是令牌桶算法中後端部分可以有突發請求,如果桶滿了,可以将桶裡所有令牌都拿走。

聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事

下圖是令牌桶算法lua代碼實作部分,當然讀者還可以使用Nginx,Java腳本或者php腳本來實作。

聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事

2.2.降級

  • 社群降級案例

一般情況下,系統上線之後總會遇到一些不穩定情況,比如redis挂掉,甚至後端資料庫My SQL挂掉。當出現不穩定情況之後,系統如何保證繼續提供這些服務。以社群案例為例,即便是My SQL挂掉,也要能夠保證社群為使用者提供基本的可讀服務。其中一個政策是将一些熱點資料,即使用者經常浏覽的資訊或者最新的資訊緩存起來,當後端服務不可用的時候,把這些資料展現給使用者。大概流程如下圖,資料存儲部分後端會有一個腳本去分析Nginx裡面的日志,然後去請求Vanish,Vanish再去請求後端,這樣的話Vanish會有一個有效期,能夠保證Vanish存進去的資料都是使用者經常通路的一些資料。第二步,如何保證後端資料庫挂掉的資料時候能遷過去?下圖可以看到,Nginx中使用lua

腳本進行實作,它會檢測後端服務傳回的一些狀态,使用計數器計算失敗次數,如果頻繁的達到一定程度的失敗次數,就切換到從Vanish擷取資料,最後推送給使用者。這樣能保證即便是後端的資料庫挂掉,甚至即便所有的php程序都挂掉的時候,社群也能給使用者提供一些基本的服務。

聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事
  • 降級目的

降級的目的比較簡單,第一個是保障伺服器基本可用,第二個是保障服務的核心服務可用。降級是怎麼一個思路呢?一般降級的每個政策都是針對一個場景,預想特定場景下需要要解決什麼問題;然後再梳理在這個場景下需要保留哪些核心基本服務;最後才標明技術方案,系統化的進行實作。簡單講就是先确定需要達到什麼目的,再去了解是什麼樣的情況,最後制定政策或者計劃。比如,系統會調用第三方服務,而第三方服務有可能挂掉,這是一種典型的場景。再比如,系統本身調用推薦服務,但是推薦服務也會挂掉,這種場景下不能夠因為沒有推薦資料就不顯示資料,還是需要展示一些資料,這是一種基本的核心服務。每年的雙11或者一些大型活動中基本都會存在降級。降級不僅僅是存在于資源故障場景下,資源不夠用時也可能會需要降級,因為資源不夠用需要關注重點。如大促活動中,需要先保證交易服務正常運作,其它消耗資源的服務(如對賬)可以後續再去處理。

聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事

2.3.逾時

  • 逾時案例

社群對外提供接口服務,對方的回報是接口服務較慢。接口部分流程是查一段資料,然後将資料反映過去,其問題點在于系統中逾時時間設定過長。比如調用Memcache,但是Memcache已經挂掉,由于逾時設定過長,資料需要等到逾時時間結束以後再傳回,導緻接口一直在等待。那如何設定逾時時間才合理?要注意逾時時間并不是固定的值,而是需要針對整個業務,根據特定場景設定逾時時間值。

聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事
  • 如何設定逾時時間

大體的思路如下圖。第一步,識别業務需要的服務響應時間。比如,需要100毫秒去響應資料,之後統計業務裡面可能需要調多少服務。第二步,統計服務日常的響應時間。第三步,厘清主次,即分出哪些是核心服務。因為核心服務一旦失敗,整個鍊路便不可用,是以可以對核心服務的時間設定的寬松一些。如果一些服務調不通,但又不影響整個鍊路,可以對它的時間設定的相對嚴格。

聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事

設定完逾時之後需要驗證,借助模拟手段封端口(如下圖),模拟故障,然後檢查資料傳回時間是否在指定的時間内。

2.4.隔離

  • 隔離案例

2013年左右,手機用戶端開始逐漸更新起來,很多項目既有PC端也有用戶端,是以同一個服務即要為PC端又要為用戶端提供API接口。一旦遇到大型活動或者需要手機推送,服務會遇到不穩定情況,服務的不穩定會導緻PC端也受影響,是以需要将服務進行實體隔離,從原先耦合到一塊的伺服器分到不同的機器組。隔離目的非常簡單,要限制住不穩定因素導緻的風險,停止傳播。

  • 隔離形式

隔離的常見形式包括幾種。第一是秒殺場景,秒殺場景一個高并發的場景,可能帶來的問題也比較多,在高并發場景下秒殺的時候,需要和一些正常的業務區分開來,不建議一台機器既提供秒殺也提供程序服務。另外,秒殺的時候會産生熱點資料,如售賣資料。資料庫更新比較頻繁,從資料庫層面也可以進行隔離,将熱點部分和正常服務部分從資源上隔離。第二個場景是慢SQL隔離,一個資源隔離。一條慢SQL會導緻整個服務不穩定。每請求一次線程,慢SQL會一直耗着目前線程,是以資源占用非常大。第三個場景是機房隔離。一般大公司都會做多機房部署,其目的就是確定穩定性。確定穩定性時不要做跨機房調用,否則耦合度會比較高,假如A調B,B挂掉,A服務也會受影響。一般確定穩定性都是做本機房的調用。而且本機房的調用性能也比較快。最後一個場景是程序隔離,因為程序比線程更加穩定。

聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事

2.5.叢集

對小公司而言,一台機器就提供一個服務,如果機器挂掉服務恢複就會成為一個問題。一般解決方法是做一個叢集,從原來的一台機器提供服務變為可以用多台機器提供服務。叢集的目的是為了解決單點的問題。叢集的形式主要有主備,即同時隻有一台機器提供整個服務,可以有一台或者多台提供備份,備份不僅要包含代碼層面,整個服務運作所依賴的資源都要有備份。另外一個形式是主從。主是提供一個完整的服務,從是提供部分的服務。還有一種是多主,多主指的是每一台機器的決策是對等的,都會對外提供一些服務。随着叢集形式的不同,對代碼編寫的并發性上有一定要求。主備隻需要考慮單機的并發控制,主從是考慮同時提供服務的部分。比如加鎖,主備上隻要加一個本地的技能鎖就可以,主從或者多主則需要加分布式鎖。

聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事

03

保證政策流程篇

保證穩定性政策的流程方面上分為下圖中四個點,code review, 壓測,灰階和監控。

聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事

3.1.Code Review

code review目的是在項目上線前及時發現一些問題。經驗比較豐富的人可以将經驗進行分享。code review基本經過三個階段。第一個階段是頭腦風暴式,一群開發人員圍着代碼做code review,雖然時間成本較高,效果也不太理想,但是這種方式也有好處,在前期可以将大家的意見進行整理,制定code review的規範。第二種code review形式是演講式,專家事先把代碼做一下review,整理一些點,然後進行分享。演講式可以按照輪崗制,相對頭腦風暴式大大節約了時間。目前常見的code review 形式是結對式,由一個或者兩個專家結對,互相review,時間上比較靈活,也不需要占據會議室資源。

3.2.壓測

  • 壓測目的

壓測的目的,第一是保證系統穩定性。在高并發的時候,檢測系統是否穩定,因為一些問題在流量比較低的時候發現不了,隻有在高并發的時候才能發現這個問題。第二是檢測性能的抗壓能力,檢查系統能承受多大的QPS。

  • 壓測關注點

首先,壓測機器和被壓測服務在同一網段,盡量避免因為網絡原因導緻壓測的結果不準确。第二點是關注伺服器的負載,注意不要把伺服器壓到100%,伺服器快要崩的時候,得到的值意義不大。應該是伺服器負載達到60%~70%的時候,看QPS是多少。另外,壓測并發資料是逐漸遞增的過程,到一個點的時候,并發資料越多代表QPS越低。最後,根據測試環境的壓測結果估算線上的承載能力。估算的公式是線上QPS = 單機QPS 機器數 0.7。後面會乘以一個系數(0.7)是因為線上put上去的時候總會存在一些損耗。

聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事
  • 全鍊路壓測

有一些測試在測試環境下無法實作壓測,是以現在發展成了全鍊路壓測。全鍊路壓測大概分成三個核心關注點。第一個是資料模型的構造。全鍊路壓測是模拟線上真正的資料模型,比如說通路詳情頁的人數,下單的人數,人數比例,登陸人數等等參數,盡量按照真實資料模拟,建構仿真模型,這樣才能真正的發現線上的一些問題。注意全鍊路壓測不是在測試環境下實作,而是線上上壓測。第二個是壓測工具建構。可以是借助開源的壓測工具,阿裡自建了壓測平台,根據資料模型提升流量。第三點是流量的隔離。對流量增加辨別,保證不影響線上的資料,将全鍊路測試流量放到測試的存儲中。比如生成一個訂單order表,同時也會生成一個影子表test_order。如果發現是來自于全鍊路壓測的流量,就把這個資料寫到影子表test_order裡面,這樣能夠保證存儲。無論是緩存還是資料庫存儲都能夠進行流量隔離。

聊聊服務穩定性保障這些事

3.3.灰階

灰階目的是小範圍試錯,盡量發現問題。灰階的政策大概有以下幾種,第一個政策是隻讓某一個地區的人先通路最新的特性,遇到問題的話使用者及時回報,問題也隻會影響特定地區。另外一個政策是基于使用者屬性,如一個推薦系統,請求過來的時候能區分新老使用者,它對新老使用者的推薦的政策可能是不一樣的,進而來驗證政策的準确性和有效性。第三種政策是基于資料,從一批使用者中選取幾個使用者進行處理。比如,對供應鍊的供應商的資料做處理,但是一般情況下不敢保證代碼上線之後100%沒問題。這時先選擇一個供應商處理,驗證資料,確定沒問題再全量處理所有的供應商。最後是基于平台,一般都發生在用戶端場景下。用戶端與服務端不同,服務端一般是針對這個平台,先指揮這個平台先釋出新版本,回報不錯再推到整個全面平台。對于用戶端的灰階技術的實作如下圖,給用戶端集中一個Cookie,請求到了之後在Nginx中去檢查Cookie,根據不同的Cookie把情趣轉到不同的組。比如組A有新特性,組B是老版本,根據不同的Cookie轉到不同組,保證隻有一部分人可以看到新的特性。

聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事

3.4.監控

  • 監控注意點

監控的目的是可以自動化及時發現問題。監控需要注意幾點問題,第一是全方面監控,系統和服務全部都要監控。第二是報警分級,監控報警的系數設定的要合理。最後一點是在真實環境下做資料收集。比如,A和B伺服器,隻在B伺服器做監控。如果A伺服器My SQL資料庫網絡出問題後,因為在監控上B伺服器是正常的,監控不會報警。是以要在應用伺服器上做監控才會報警具體哪台機器哪個服務出現故障等資訊。

聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事
  • 自研監控系統

下圖是阿裡自研的監控系統。首先确定對哪些名額進行監控。将整個名額的資料繪制出來,檢視名額資料波動。一旦遇到問題,可以很友善的進行對比。另外要确定影響,将所有相關的名額聚合起來。比如供應商的團隊操控系統經常會發生倉庫操作卡頓,有很多因素都會導緻卡頓,如PC端調用其它接口較慢,伺服器load比較高等。倉庫人員無法關注具體的細節,他們在影響界面檢視名額影響值,一眼就可以知道是哪項名額不合格導緻的卡頓。之後對造成的影響進行相應的處理,目前一般的行為有效報警或短信報警。 

聊聊服務穩定性保障這些事
聊聊服務穩定性保障這些事

通過以上的介紹,希望大家能夠全面了解服務穩定性的重要性和相關政策。熟悉保障服務穩定性的常見政策(限流,降級,隔離,逾時,重試和叢集)以及保障政策的流程。

聊聊服務穩定性保障這些事