餓了么技術運營是如何擺平那些惱人事故的
原創【51CTO.com原創稿件】餓了么平臺不僅做外賣,還有蜂鳥、早餐和未來餐廳,以及很多其他的一些平臺,正處在快速擴張階段。整個外賣的產品鏈條長,從用戶下單到最后配送到達,時間大概是30分鐘左右,對時效性的要求非常強。
從技術的角度來看,餓了么遇到的最大挑戰是事故。本文將圍繞事故展開,分成兩部分內容:技術運營經歷與心得。第一部分經歷又分為三個階段:精細化分工、保穩定(容量和變更)和增效。第二部分心得,是作者對運維服務的理解。
一、技術運營經歷
技術運營的職責是盡最大的努力協同更多的人來達成保穩定的目標,可以劃分為兩個階段:運維保障、運維服務。現在,餓了么處在運維服務的階段,技術運營團隊作為乙方,把開發出來的產品,開發測試后的服務,做維護,保障穩定、調優性能、提高資源的利用率。
在業務快速擴張階段,技術團隊需要做哪些事情呢?
首先,第一階段,精細化分工。
通過精細化分工促進并行提速,讓專業的人利用專業的知識、最有效的工作方式提高工作效率及代碼吞吐量,建立溝通渠道加速決策、信息流通保穩定。
精細化分工分為三部分內容:
第一部分是做數據庫拆分和代碼解耦。技術工作集中在數據庫的拆分,先縱向拆分,不得已才做橫向拆分,為了更快地服務業務的擴張,又夾雜了一些對代碼解耦的工作。
所謂代碼解耦,是把原來的代碼系統想象成一個泥球,把它逐漸拆分成很多塊。現在是有十多個業務模塊,每一模塊里面都有專門的團隊來維護,內部又會劃分域。
餓了么是數據庫、代碼拆分并行在做。然后,啟動了強制接入新發布系統和單實例、單運用,也就是物理拆分。
在整個的代碼解耦和精細化分工的過程當中,他們碰到了很多問題,其中比較典型的兩類事故是:
-
事故1:超時,后端服務慢,引發連鎖反應,導致前端服務雪崩。
用戶的請求耗時依賴于 RPC 調用路徑上服務的響應時間。當其中某個節點變慢,整個集群都不可用,一般救急措施是要按照調用鏈從前往后按順序停服務,然后在從后往前啟動服務。
當這類問題發生的時候,如果沒有熔斷機制,前端的服務因依賴關系造成雪崩,而且服務不能自己恢復。加了熔斷機制之后,當后端問題節點重啟或是網絡抖動恢復后,前端服務也會自己恢復。
-
事故2:連續三天商戶需要不斷重試才能接單,這與Redis治理有關。
當交換機發生 Bug 導致網絡抖動,受影響最大的就是 Redis,在網絡抖動期間積壓的請求會建立太多 Redis 連接,連接過多會導致 Redis 響應延遲從 1ms 飆升到 300ms。由于 Redis 請求慢導致服務的處理速度被拖慢,而外部請求仍在積壓,最后引起雪崩。
剛開始出現故障的時候,因 Zabbix 的監控周期長,運維工程師監控不到。后來,他們用了三天的時間進行壓測復現,才排查出來故障點。事后,運維工程師打造了一種新的基礎設施監控工具,實現方式是每 10 秒鐘把 /proc 目錄下的所有指標收集起來,基本能做到 3 分鐘內定位問題。
還有丟包的重傳也會嚴重影響 Redis 的性能,因為一個 HTTP 引擎到后端有可能產生幾十個甚至上百次的 Redis 請求,其中有一次被命中重試,對服務的影響都是致命的。
精細化分工的第二部分是組建水平團隊,例如大數據是水平團隊,業務線是豎向團隊,劃分之后,從整個業務的發展走勢圖上升曲線非常陡,可以推斷技術并沒有防礙業務的快速發展,也就是技術的吞吐量、新產品研發效率是健康的。
期間,運維工程師還做了幾件事,比如把監控分為 Metric、Log、Trace、基礎設施四個部分。組建 Noc 團隊,負責應急響應,當發現有問題的時候,及時把信息通過 Oncall 通報給各成員。還有梳理各類掃除,接入發布、 SOA,降級熔斷開發等。
大掃除
大掃除的概念是什么呢?就是工程師對歷史的事故進行分析之后,大概做出技術總結,把經常犯的一些錯誤,列成一些可做的規程,給所在部門的骨干進行宣傳。具體內容包括:
-
SOA 的服務治理,這里主要強調的是領域劃分,高內聚低耦合。
-
對公共組件的治理。這里的數據庫 Redis 由兩個專業的團隊組成,一個是 DA,一個是 DBA。DA 治理的主要方案是收集各個產業伙伴的信息,規劃容量,治理開發的使用姿勢,把經驗固化到研發流程里。
-
業務指標的梳理,包括對 TPS 的概念設定(狀態輪轉后再根據返回狀態打點)、狀態的停滯時間和狀態的堆積深度,這個堆積深度主要是后端一些服務的狀態輪轉。
-
對超時鏈的合理設定和重試機制。
-
外部依賴及開關。為什么強調外部依賴呢?外部依賴可以分為兩類,一類是跟其他公司的合作,例如調用其他公司的支付接口。還有一類依賴是團隊之間的依賴,這里請不要相信任何人的服務,Bug 隨時都會發生。
-
關鍵路徑。為什么要設置關鍵路徑呢?一個是熔斷,一個是降級。當非關鍵路徑出現問題的時候,直接把它降掉就行了,不要影響關鍵路徑。另外一個好處是接下來做補償的時候,可以有針對性去做。
-
日志。團隊在日志上發生的事故也很多,可以逐個通過案例進行宣講。
-
正在實現中的制定盲演習目標。因為八九百個技術工程師之間的代碼交互本身是一個復雜系統,業務又是一個非常長的業務鏈,關鍵路徑涉及的服務超過 100個,簡單的功能測試是可以的,但是容量大的時候,將很難定位他們之間存在的問題,比如 A 團隊和 B 團隊之間的代碼耦合驗收。這時想到的解決方案就是盲演習。
盲演習除了在業務方可以做驗收之外,還可以做基礎設施,包括 Redis 集群、 MySQL 集群和網絡。曾經做過一個測試,把一個 Redis 實例上的包量,按照百分之一的丟包率計算,導致整個全站的業務都掉底。當時整個 Redis 集群有12臺,有幾百個實例,其中一個實例有問題,就造成這么大的影響。通過盲演習,技術正在尋求單個節點宕機影響最小化的解決方案。
第二階段,保穩定期。頭號敵人是容量問題。
在業務快速擴張階段,影響系統穩定性最大的敵人是容量,類似溫水煮青蛙,或突然雪崩。因為不同語言判定容量的方式不同,餓了么1000多個服務組成的復雜系統,業務場景快速變換,服務變更頻繁等等因素,導致容量問題困擾了近一年的時間。
最后采用的是定期線上全鏈路壓測的方法,發動了一次百人戰役,歷時一個多月,整改了近 200 個隱患點,基本解決了容量問題。即便在低谷期的時候,也采用全聯路壓制。還可以配合技術在上線前的壓測一起來做,然后把這些數據統籌起來進行分析。
秒殺事故
在 517 秒殺大促準備階段,技術的運營思路是想用日常服務的集群來對抗秒殺,活動前把整個的容量提高了兩倍多。但是當日訂單量飆漲,秒殺開始后的那幾秒鐘,瞬時并發請求達到平常的 50 倍。當流量洪峰到來的時候,洪峰直接把前端 Nginx 的網絡擁塞了。
反思下來,出現問題的原因是秒殺場景的經驗少,對活動帶來洪峰數據的預估過低,URL 的限流未區分優先級等等。改進措施是專門針對秒殺搭建了一套系統,主要做了分級保護、建立用戶端緩存、泳道、云集群和競爭緩存等。
第三階段,增效。通過工具、資源、架構改造,提高效率。
事故1:連續兩周蜂鳥配送出現各類事故
原因是消息不斷的批量重試導致 RMQ 堆積,UDP 句柄耗盡,熔斷判定使用姿勢不對。可以看出,新業務在快速交付過程中,代碼質量、外部組建的使用姿勢是事故高危隱患點。
事故2:MySQL
SQL 慢查詢,從每周的 2 到 3 起,降低到近期很少出現。解決辦法是使用組件治理。組件治理首先是服務化自己的資源、容量。第二個是設限流,做降級。第三個主要是限制開發的一些姿勢。
這三點做完之后,接下來技術做了自動化相關的一些工作,主要是信息、標準化和編排。再一個是前置指標KPI,就是當一些組件剛使用起來時,要做一些量化的考慮。把這幾條做到以后,技術基本上能避免出現大的故障問題。
對于使用姿勢的治理,對穩定的收益最大。這里特別介紹幾個關鍵點:
-
必須要有對組件精通的伙伴,看過源碼,了解社區里碰到的所有的坑,還要深入業務開發一線,了解業務場景,初步判定組件在業務中的使用場景。
-
工程師進行知識傳遞,通過各種渠道把標準化、開發規范、集群化、開發使用姿勢等知識點傳遞到位。
-
盡快把經驗或紅線固化到資源申請、架構評審等流程、工具里。
事故3:RMQ
在餓了么,RMQ 的使用場景非常多,有 Python,也有 Java。2016年年初的時候,工程師雖然做了一個技術、配置的梳理,還是留有很多的場景是沒有想到的,主要涉及的問題有如下幾個:
-
分區,就是技術在做割接的時候,核心交換是升級換設備。當設備網絡割接完了,雖然在 RMQ 集群里面的配置是可以自恢復的,但是仍然還有很多集群沒有做到自恢復。
所以,技術特意預留了一個冷備 RMQ 集群,把現網所有的配置都部署到那一個冷備集群里面去。線上 20 多個 RMQ 集群中,如有一個宕掉的時候,可以及時切過來。
-
隊列堵塞。主要是追查消費能力,因為業務飆升,消費能力不夠,極容易導致隊列堵塞。
-
使用場景。舉例來說,在發送、接收消息的時候,如果每發一個消息,每收一個消息,都重建一次鏈接或者都重建 Queue。這種重建會導致 RMQ 內部的一個Event機制。當請求增長到一定程度的時候,就會直接影響 RMQ 的吞吐量,RMQ 的容量會掉到是原來的十分之一。
老大難:故障定位、恢復效率
故障定位慢的最主要原因是餓了么整個系統的信息量太大,當一個問題出現的時候,主導這個事故定位的工程師拿到的信息非常多,比如拿到三個信息,他很難決定到底是什么故障,需要如何檢測出來。
當前的做法是進行碎片化、地毯式的大掃蕩來排障。什么是地毯式的大掃蕩呢?就是把足夠多的信息先拿到,進行分工,要求涉及的每個工程師都來查看。內容涉及到外賣、商戶、支付和物流,然后還有基礎業務和網絡監控,外網的一些流量,還有服務器的一些負擔等等。
這時,技術工程師的有序自證就變得非常重要,當前能做到的是每一個人能看到當前負責的服務是不是有問題。還需要做的就是提供工具,比如交換機的丟包、服務器的丟包。通過一些工具,讓技術工程師及時發現問題,但是這個過程是需要時間的。
另外一個是在自證的時候,一定要仔細地檢查。作為團隊中的一個成員,每一個技術工程師負責相應的板塊,但一旦因為個人疏忽或是自檢不足造成一些失誤,要自己“刷鍋”。故障定位后,提升恢復效率解決問題才是關鍵。
還有,應急演習很重要。應急演習直接關系到系統恢復的效率,當一個集群出問題的時候,技術能不能快速的恢復。
二、運營心得
本次分享大部分圍繞事故來講。每一次事故的出現都不是偶然的,很多問題是可以通過正確的使用姿勢、提前做容量預估、灰度等方法規避的。如果說技術只是就事論事把這一件事情解決的話,事故往往在另外一個時間點還會出現。
這就要求工程師以思考的方式去做事,比如做事故復盤、事故報道審核,還有驗收小組等。然后,通過在各個階段,多次把一個事故涉及的關鍵點提出來,不斷地進行總結并制定可行的操作規范。
問題的解決往往需要思維模式的轉變,需要伙伴們多想想怎么從日常重要緊急的事務里抽離出時間思考。
還有要敢于折騰。折騰是什么概念呢?就是要不斷的演習、搗亂,工程師對于維護的系統,自己要非常的熟悉,這樣在定位和解決故障的時候,就會非常精準。
最后一個是燈下黑的問題,特別是基礎設施這塊。這在當時讓人很頭疼,查一個問題在基礎設施上花費的時間是十多分鐘到一個小時。后來有一個小伙伴改變思路,做出了一套系統,幫助團隊非常好地解決了這個大問題。所以敢于思考,勤于嘗試是餓了么技術團隊非常重要的一個心得。
作者:徐盎
編輯:孫淑娟
本文選自《CTO說》
餓了么技術運營部、風控管理部高級總監
徐盎,擅長精益運維、精細化風控,通過與公司其他團隊協作、推動并完善運維信息化、標準化、服務化的建設,逐步實現自動化運維及交付,數據可視化,進而做到低成本的保障系統穩定;通過數據與規則適配,以及產品設計、人工審計、風控平臺建設使每一元補貼用在公司既定目標的實現上。
【51CTO原創稿件,合作站點轉載請注明原文作者和出處為51CTO.com】