蘑菇街的稳定性实践
https://opentalk.upyun.com/329.html
促銷情況下的穩定性保障流程
蘑菇街是一個電商平臺,每年會做四次大促,3.21、6.18、雙11、雙12。大促保障涉及到流量評估、依賴梳理、單鏈路壓測、全鏈路壓測等。蘑菇街大促的基本流程,基本是按照系統峰值評估、依賴關系梳理、單鏈路壓測、系統擴容、全鏈路壓測等幾個環節展開的。
在保障大促穩定性工作的時候,穩定性團隊會有一個KPI:這次大促不能出某個級別以上的故障,如果出了這個級別以上的故障這個KPI就掛掉了。第一次接到穩定性工作,我也是很迷?!芏嗍虑槭瞧渌麍F隊小伙伴做的事情,萬一他們的疏忽出了一個故障,這個也要我一起背嗎?后來逐漸摸索出一套應對大促帶來大流量,行之有效的大促穩定性保障方案。
評估系統峰值
機器和成本總是有限的,因此在每次大促之前必須要估出一個合理的峰值,根據峰值合理地擴容。每次大促開始前,必須找到運營方溝通大促的業務目標:大促GMV,包括預估的PV、UV、客單價、轉化率。根據運營給出的數據,推算出所有系統的峰值,其中最重要是下單系統的峰值。
倒金字塔梳理系統峰值
下單峰值的評估,有點像我們做應用題一樣。已知運營給出大促的目標,包括PV、UV、GMV,要求推算出下單交易系統峰值。這里分享一個經驗公式,“預估大促GMV/歷史大促GMV×歷史客單價/預估客單價”,一般就等于歷史大促峰值。通過這個可以算出這次下單大概峰值是多少。
算出了下單峰值之后,再套入一個倒金字塔的模型。電商場景都是有一定特點的:最前面流量會從會場、首頁、外部分享頁進來,然后進店鋪頁面、圖墻頁面、搜索頁面。到了這些頁面之后會進入詳情頁;到了這里用戶可以加入購物車,做購物車的操作;然后就可以下單、支付了。瀏覽了詳情頁后,有多少人基本會下單,這個比例我們稱之為“轉化率”,轉化率可以預估出來了。
?
?
根據一定的比例關系,一旦確定好下單數額之后,就可以倒推出每個系統在本次大促是要承擔多少QPS,把每個系統的峰值算出來。推算出每個系統QBS之后,再根據以往經驗進行對比,比如對比3.21大促的預估峰值跟實際峰值,假如當時估值偏低,那在下次大促時稍微調高一點,這樣就會確定本次大促各自系統峰值是多少。
關注運營玩法和架構的變化
電商平臺的運營玩法層出不窮,一定要關注運營玩法和架構上的新變動,這對預估峰值來說很重要!蘑菇街吃過這方面的虧。
比如今年3.21大促的時候,運營在晚上10點時候會上線有一波游戲,App會有信息推送,首頁會會彈出直達這個游戲的提示框,有好幾種方法可以把流量迅速導到游戲會場去。在游戲開始之前我們沒有太關注這個游戲的玩法,只是按照以往的經驗簡單估了一下這個值。但是游戲的流量比預估值高上一倍!那次大促有一半的KBS直接被限掉了,這對客戶體驗非常不好。
后來總結經驗,對于這些玩法的變動,一定要做大促穩定性保障,一定要了解的細致,不能只是很泛泛地去問一下:玩法有沒有新變動?是不是跟以前一樣的?要具體到運營的每一個步驟,不問清楚很有可能對流量預估產生影響。
架構上有新變動帶來的影響更不要說了,比如你以前應用是部署在物理機上的,現在部署在虛擬機上了;或者之前用A中間件,現在用是B中間件。架構上的變動一定要重點關注。
梳理依賴關系
一旦業務變大或服務化細致之后,依賴關系會變得非常復雜,梳理起來很麻煩。有時候某一個應用掛了,可能是某一個依賴方掛了;你負責的應用掛了之后又會導致所有調用此應用的應用也掛了。
在全鏈路監控系統上線之前,做依賴關系的梳理其實是一個非常麻煩的事情,假如開發人員出現了流動,新人接手這個系統,只有看代碼才能知道依賴關系,對代碼不太熟悉的話還會出現漏判的情況。有些代碼因為業務邏輯關系非常復雜,很難判斷和梳理,用比例無法精確計算。
依賴關系不明確,萬一帶大促的時候這個依賴發生了狀況,但沒有做預案處理,可能對系統本身的穩定性會產生影響。
?
?
現在蘑菇街是通過全鏈路監控系統來梳理依賴關系,因為全鏈路監控系統可以知道一條鏈路下來的每次調用,通過計算可以知道調用者和被調用者之間的調用比例關系,甚至可以詳細到接口。
通過全鏈路監控系統梳理出來的全站應用拓撲,最前端的應用是Web Trode Order,調用了很多的應用。只要把這個關系出來就一目了然,再也不用看代碼,而且直接知道它們之間的關系。
系統壓測和擴容
蘑菇街的步驟是,先做單鏈路壓測,再做擴容,最后做全鏈路壓測。
在沒有統一的全鏈路壓測平臺之前,業務方都是自己組織壓力測試的,各種各樣的壓測工具都有。這里有幾個注意點,一個是當你需要壓到很高的QPS的時候,本身有限制,QPS不是很穩定。另外如果壓測數值很高,業務方手里沒有機器,他要跑到PE去申請,PE一般也不會給機器,這怎么辦?基于這個問題,蘑菇街開發了全鏈路壓測平臺,把機器當成一種資源:只要告訴鏈路定義、場景定義和任務定義,簡單定義之后就可以壓測了。
單鏈路壓測
在單鏈路壓測階段,各業務方把各自需求應用全部做完100%流量的壓測,并且要驗證所有的流量、限流策略是否正確。
單鏈路壓測的時候有一個“局部集中”的概念,在做單鏈路壓測的時候,電商基礎相關的業務壓測要盡量放在一起壓,比如詳情、促銷、優惠、交易、下單,之前都是各自壓測,但這些應用互相都是有交互情況的,最好在同一天單鏈路壓測的時候就一起進行調。如果有問題可以提前發現解決掉,而不會把這些問題推到全鏈路壓測的時候去解決。
系統擴容靠單機壓測
單鏈路壓測完了之后就開始做系統擴容。蘑菇街做系統擴容,必須要由單機壓測系統提供水位報告,有數據說話,拒絕拍腦袋,才能夠減少機器、降低成本。
比如有些應用壓測出來要扛5千QPS,但是我只能抗3千,這就需要找PE擴容機器。擴容要盡量節約成本。業務方為了自己的應用更安全一點,通常會多要幾臺機器,能扛多一點,心里安全一點。如果對每一個業務方都心慈手軟的話,你就放出去太多機器了,成本沒法控制,必須要求業務方要拿著單機水位壓測包來擴容,不能拍腦袋說“再給我5臺機器,讓我更安全一點”。
為此蘑菇街做了單機壓測系統,它有兩種方法,一種可以把線上真實流量全部會聚到其中某一臺機器上去,這樣可以測這臺機器的真實水位到底是多少。另外一種情況,可以利用全鏈路壓測平臺,打模擬流量到一臺機器上去,這樣也可以測出這臺機器真實水位是多少。
打流量的時候也不是一次打,假如你預測這臺機器單機水位大概能達到1千KPS,我可能從100開始打,100打完了打200,直到測出你這個系統單機水位。這里的判斷標準和預值通常是讓業務方自己測,比如他測試CUO到了一定值之后,比如到了80%,就可以認為到極限了。業務方完成單機壓測后,方可拿到機器進行擴容。
全鏈路壓測要盡量真實
擴容之后要進行全鏈路壓測。各自做單鏈路壓測是不行的,因為在所有流量會聚到一起的時候,對整個系統某些平行點可能會發生意想不到的情況。所以在單鏈路壓測做完之后,一定要把所有系統會聚在一起做全鏈路壓測,一般會做兩到三次。
一般認為全鏈路壓測知道壓過就OK,其實不是,全鏈路壓測都夠了,后來大促發現了問題,問題在哪里呢?因為全鏈路壓測是模擬流量,平日的真實流量沒有到大促那一天這么大,沒有那么多的數據用于模擬流量數據庫;比如線上商品有10萬,業務方為了簡單化,后來在測試數據庫里只有2萬的商品,所以在做全鏈路壓測的時候沒有發現這個問題,測試時的網卡流量雖然比較大,但是沒有把網卡打爆。但是在真正大促當天,10萬商品的流量一下子下來之后,就把網卡打爆了。
進行反思后,蘑菇街要求全鏈路壓測數據要盡量真實,盡量模擬現場的情況。但是全鏈路壓測的成本也要考慮好,這之間的度要把握好。
?
?
全鏈路壓測是一個苦活,通常在晚上12點之后,持續四到五個小時,一直到凌晨。這里要提高人效、降低成本,蘑菇街盡量減少晚上壓測的成本,如果白天壓測50%的量,晚上可以從75%開始壓了,這樣就可以節約了晚上的壓測時間,就不用到凌晨4點、5點,一般凌晨2點就可以手工了。
2017年蘑菇街也在想一些辦法,可不可以在白天也做一些全鏈路壓縮;白天做全鏈路壓測的方向是有的,就是隔離出兩個動態環境,一部分環境是線上流量,另一部分環境專門用于壓測,這樣互相不影響。這個方案還在可行性驗證當中。
以上工作準備充分以后,還要準備一份預案評審和作戰手冊。
預案是為了大促如果真發生了事情到底怎么辦,包括前面做依賴梳理的時候,一個系統如果有三個依賴的話,需要對每個依賴都要做好一個預案:這個依賴如果掛了怎么辦,降級還是別的處理方案?
作戰手冊就比較簡單明了,出現什么問題,團隊成員能夠在作戰手冊里第一時間找到應對方案和措施,及時應對,解決突發情況。
lurker:蘑菇街全鏈路監控平臺
為了加強穩定性工作,蘑菇街開發了一個全鏈路監控平臺工具——lurker。取這個名字的初衷,是希望它埋伏在地底下,在設計和使用的時候,盡量地減少業務方對這個東西的感知,但實際上lurker又幫助他們解決了實際問題。
在開發lurker的時候,蘑菇街95%代碼以上還是PHP,部分代碼做了PHP服務化,服務可以互相去調用的。比如想監控PHP服務里面的每一個函數,到底是不是每一個函數時間過長。所以我們當時想了一個辦法,Facebook有一個xhprof的工具,可以監控每個函數,通過PHP擴展實現。我們在xhprof的基礎上改了一下,就變成蘑菇街的lurker,它的原理是什么?PHP有一個綻裂引擎,有一個函數執行指針,把這個指針替換成蘑菇街的hook函數,然后做了一些處理,可以讓業務方判定哪些函數是需要監控的。此外還修改了curl以及php-curl的實現。
全鏈路監控的原理最早是由Google Dappen提出的,是一個分布式的監控系統。當本身的應用逐步服務化的時候,服務拆分會越來越細,現在蘑菇街有大幾百個應用,應用之間互相有很復雜的調用。某一條復雜的鏈路可能要涉及到幾百次調用,如果一次調用IP超時的話,怎么知道這么復雜的鏈路里面到底哪個超時了?
它的原理,每次調用都有一個全局唯一的Trace lD,它里面包括了一些業務含義,比如當時請求進來的機器IP、請求發生時間、進程ID等等,這些信息的加入,本身是為了保證全局唯一的特性。
另外一個是Span lD,是為了區分調用中是一個順序關系或者嵌套層次的關系。Trace Context是在哪里產生的?因為所有的請求進來都是在nginx,所以蘑菇街直接在nginx端做了插件,插件里面會產生Trace Context,它就會從請求進來的最前方開始一直傳到最后面;它通過Servlet Filter去實現在前端加入外部應用。
全鏈路監控系統架構
蘑菇街全鏈路監控系統的架構如圖所示。通過插件放在應用集群,不管是PHP還是Java,日志都會在本地落款。本地落款相對通過網絡上傳會更安全一點,出問題概率會小一點。
日志在本地落款之后再實時收集到Kafka,進入Kafka之后數據分三份:
· 一份數據進入Storm,然后進入ES Index里;
· 一部分原始日志直接放在Infobright;
· 一部分數據進入到HPS
這個系統要支持多維查詢,數據一開始放到支持全文檢索的ES里,但ES數據不做壓縮,存儲成本很高。當時數據一天有好幾T,存不了多久。后來用了Infobright,節約了很多成本,很好用。但Infobright是開源版,有一個人為設置,寫數據的時候不能讀。另外它只能單線,速度很慢,讀一條日志需要6、7秒的情況。今年Q2,蘑菇街模仿Infobright做了一個類似存儲的東西,現在已經差不多完成了,測試的結果性能還是相當不錯的,壓測率和Infobright差不多,速度很快。
Kafka另外一部分數據進入到HPS,主要是適應不適合用Storm做實時計算的情況。
全鏈路監控系統的作用
在蘑菇街 lurker 示意圖里,左邊可以看到整個鏈路呈豎狀的結構,1是1.1、1.2、1.3、1.4和1.5,1.4里面又有1.41,1.5調了1.51,每次調用服務、方法都寫在這里,時間后面有Timeline,整個調用關系一目了然。
?
除了調用關系之外, lurker 還能統計應用信息。每次調用和被調用者都有一條固定的認證關系,可以算出每個應用的直接應用來源、去向應用的數量,蘑菇街稱之為“法拉力應用”,每個時間點上QPS到底是多少,有沒有出錯,都可以在應用信息統計上看到。假如調用了一個前端應用,還可以看到URL是多少。假如調用了一個后端服務,還能看到最最前面的應用,就是最早進來的URL,或者來源于哪幾個應用。
利用監控系統,可以畫出所有應用之間互相依賴的關系,并且把互相調用的比例也算出來。
lurker 帶有一個多維查詢的功能,有些業務方可能想根據某些特殊條件,比如應用名、服務名、方法名、業務響應碼或者是IP,都可以通過多維查詢搜出來。多維查詢的要求還是很高的,因為后續查詢、后續數據存儲都是需要解決的問題。
lurker?尚需解決的問題
在開發 lurker 的過程中,蘑菇街也碰到了一些問題:
· 數據存儲
· 跨線程傳遞trace context
· 前端應用接入不全,導致后端應用QPS不準確
· 周期性任務,鏈路路過?長,展示有問題
數據存儲問題如上文所說,歷經幾版,希望我們最近研發的產品能夠撐住平臺上產生的巨大數據量。
第二是跨線程傳遞,因為trace context從前端要往最后端傳,為了給業務方不產生影響,或者讓它們盡量沒有感知,我們就把trace context放在這里面。但會出現一個問題,假如中間的一些工具有自己的現成詞句,那就傳不過去,信息就丟失了,鏈路到這一步就斷掉了。我們想了幾個辦法,第一把trace context做的東西放進去,但是業務方不知道去用,他們不愿意去用,覺得比較麻煩。第二去修改現成詞,直接把這些數據弄進去,但是修改以后業務方覺得修改后的這些東西到底靠不靠譜?所以目前碰到這個問題的時候,基本上建議業務方手工傳一下,要不然在里面看不到。
第三個問題:前端應用接入不全。在推這個產品的時候,沒有強制去接入,監控系統強大了之后,所有的前端用戶都接入了,到后面的調用就沒有被記錄下來,所以后端應用QPS不準確。
最后是一些周期性任務。有一些任務鏈路比較長,比如一次跑一個小時,可能調個1萬字也有可能,這個內容展示會有些問題。
全面分析全鏈路壓測系統
全鏈路壓測的意義在前文已經講過了,在于驗證瓶頸是否存在,以及找出可能的瓶頸,具體來說有以下幾點:
· 對線上真實環境進行大流量演練
· 驗證鏈路在超大流量系統里,容量和資源分配是否合理
· 找出鏈路中可能存在的瓶頸
· 驗證網絡設備、集群容量和預案、限流策略
建立壓測模型
為了找到這個瓶頸,使蘑菇街的系統更加靈活,在設計壓測模型的時候會有一些考慮:壓測鏈路、壓測場景、流量模型、壓測任務、壓測腳本。
所謂鏈路,一個URL就是一個鏈路,場景是鏈路上一層的概念,一個場景可以有單個或者多個鏈路組合而成。在電商環境下,某些場景是可以復用的。
壓測場景以后,加上流量模型就可以構成一個壓測任務,流量模型就是壓測的時候流量怎么來,是一條直線比值壓,還是要階梯爬坡?
壓測任務又會轉化成壓測腳本,這是一一對應的。
?
?
以支付里面的一個場景為例。支付收單是一個鏈路,流量從虛擬根節點進來之后,100%流量會去到支付收單節點,然后100%流量又會進入到收銀臺渲染節點,5%的流量會去A節點,40%去B節點,55%去C節點,最后100%去D節點。通過鼠標拽一下,一旦規定了入口接點是多少,就可以把整個場景規定下來。
?
?
電商場景是可以嵌套,比如3.21交易之后的全鏈路,里面包括了促銷壓測模型、交易模型、支付模型、支付成功頁,這些全部可以復用。假如說業務場景的邏輯不變,下次大促時這一個場景直接可以附在上面。
壓測腳本做了二次改造,能夠支持這四種不同的協議。第一會做腳本的確認,第二是數據確認,可以上傳一些壓測數據。第三是開始之后狀態的檢控以及結果的展示。
全鏈路壓測系統架構解析
?
蘑菇街的全鏈路壓測系統基于master slave開發,搭建速度很快。
這里有一個比較坑的地方,系統僅僅是支持單master,一套系統部署起來只支持一個master,我們要盡量避免單點。當時全鏈路壓測系統剛完成1.0版,第二周就要壓測,當時我們擔心這個master會不會貴?結果果真貴了。貴的原因是什么?它和slave有交互,全鏈路壓縮大概有100臺壓測機,特別是當壓力壓的比較大的時候,容易出錯。
之后做了一些改造,包括實時回傳、發起壓測命令、上傳壓測數據、觀察壓測進度、收集壓測結果。改造之后master好了很多。生成完了之后有一個數據工廠,它會自動生成要壓測的那些數據,比如商品流數據、交易數據、促銷數據都是從這個數據工廠里面來。
全鏈路壓測系統還有一個OSS Storage,用于存儲壓測腳本和壓測數據。OSS Storage有好幾個備份,而且能夠保障數據文件的安全,不需要再次關注。
全鏈路壓測系統也碰到一些問題。蘑菇街的場景非常大,場景里面有很多內容定義,腳本會編譯成JVM方法,大小不能超過65535。解決方法是——拆場景,比如把交易支付拆成一個場景,把搜索拆成一個場景。假如有100臺機器,每一臺機器跑一個腳本,這樣就繞開腳本大小的限制了。
整個全鏈路壓測系統要表面單點,它沒有辦法加載太大的壓測數據文件。有一些業務方會要求回訪現場數據,一拿回來就是幾個G,這會需要非常長的時間,所以不推薦。蘑菇街現在的應對做法是把數據分割開。
轉載于:https://www.cnblogs.com/davidwang456/articles/9294920.html
總結
- 上一篇: Redis 的源码分析
- 下一篇: 记一次redis规模化运维讨论会