如何做到全年配送 0 故障?盒马揭秘 12个关键技术
簡介:?作者 | 帳篷
一 、穩定大于一切
盒馬的線下作業穩定性要求極高,假如門店pos無法付款了,排起的支付長隊伍能讓人把門店鬧翻,假如配送員無法攬收了,在家里預定的午餐材料的饑腸轆轆的客戶能把投訴電話打爆,甚至會形成廣泛的社會輿論。盒馬安全生產至關重要,穩定大于一切。
?
盒馬配送智能調度負責將訂單指派給騎手,是配送作業實操的第一環節,也是最重要的環節之一,假如調度出現問題,那么會導致大量訂單超時履約,導致客戶投訴,也會造成客戶取消造成的銷售資損。理論上系統不變更就會降低穩定性的風險,然而隨著盒馬配送提效降本的業務訴求和新業務的調度需求,以及配送智能調度上線兩年來補丁重重導致的開發運維困難,急需系統架構重構,使得我們必須在高壓下砥礪前行,對系統進行不斷的重構改造,同時支撐日益發展的業務和提效降本的業務訴求。
配送智能調度系統今年系統完全重構一次,遷移了o2o、b2c、冷鏈等重要業務,上線了mall調度新需求,支撐了預調度和實時運力調度的提效降本需求,支撐了算法數據白盒化改造,在此基礎上將繼續耕耘,已產出了策略化運營方案、仿真改造方案和算法結果智能診斷方案,我們用實際行動表明,在系統飛速發展的同時,也能做到了智能調度系統全年0故障。
二、 智能調度鏈路分析
系統穩定性保障前提是要對系統關鍵鏈路了如指掌,關鍵鏈路包括對外依賴和我們提供的服務,因此在接手智能調度系統升級改造時,我們做了非常全面的智能調度的鏈路分析,并在不斷上線新需求后,及時完善鏈路,使得我們不管在大促期間或者日常監控,不管是我們自己運維還是給團隊伙伴運維backup都能了解系統全貌,基于統一鏈路圖進行討論,并在告警發生時能夠分析和解決問題。
配送O2O智能調度涉及調度系統、壓力系統、基礎資料、騎手平臺、算法策略、分布式計算、路徑規劃、單據分發等系統,涉及DTS、diamond、tair、作業DB、降級DB等存儲和中間件,鏈路非常長,我們繪制了一張o2o智能調度時序圖,基于同一張大圖,產品、技術、測試、算法能在大促和系統變更前評估系統穩定性風險。
三、穩定性因素分析和實踐
有了詳細的系統調用鏈路,我們可以把鏈路中的每條線的穩定性按類別進行梳理。
3.1 DB依賴
(1)慢sql
DB依賴主要分析依賴DB的穩定性,首先,DB有沒有慢SQL,盒馬早期大多數故障原因是慢sql導致,后來對DB的集中治理才使得這塊不穩定因素被逐步瓦解,但是慢SQL治理是長期的事情,不管是上新業務的sql事前分析,還是流量自然增長需要做的DB定時check都至關重要。
(2)邏輯讀行數多
有些sql不是慢sql,但是邏輯讀非常大,比如超過10萬行,那么這些sql在業務自然增長時很可能發展為慢sql,如果不治理,假以時日必定讓你“刮目相看”。
(3)CloudDBA中的屬性(cpu、內存、load、qps趨勢)
查看DB的cpu是否正常,load是否比較高水位,是否有很多qps/tps尖刺。配送智能調度依賴的walle庫在大促前發現db整體水位較低,但是cpu尖刺特別高,尖刺有到達60%,而且非常有規律,經過排查是一個網格任務沒有離散導致。該問題咨詢過DBA如果雙11大促三倍流量,DB扛不住,幸好及時發現,緊急發布做了網格任務離散化。
(4)DB不隔離
DB不隔離常見有核心與非核心數據在一起,非核心qps高或者邏輯讀高影響了整個DB的穩定性,配送從一個庫拆分為核心、次核心、非核心、歸檔庫,就是為了做到業務重要性分層。
冷熱數據不隔離,一個不經常訪問的超慢sql生成的報表使用了核心庫,該case在盒馬發展史上出現多次,常見的有統計報查詢、報表導出使用了核心庫。
讀寫不分離,上述報表類需求、前端展示類需求、看板類需求屬于讀業務,線下實操核心的是寫DB,兩者不隔離也會同樣產生問題。
(5)DB降級
在智能調度系統中,DB依賴核心作業庫中的單據,核心作業穩定性高于智能調度,為了保障核心作業穩定,我們為DB做了降級策略,用精衛同步一份數據到讀庫。DB降級主要衡量DB不穩定對該DB上業務的影響。
(6)上下游同一業務字段存在DB字段大小和類型不一致
上下游DB使用了同一業務字段但容量不一樣會造成極端場景下數據無法寫入。配送關聯發貨單字段是組合字段,包含批次關聯的所有發貨單,正常情況下一個批次關聯1~3個發貨單,在大促期間倉為了作業方便,關聯了7個發貨單,導致配送64位字符串超長,導致關聯發貨單無法寫入,后來緊急變更,將字段改為256位得以解決。商品重量配送的字段是int,表示毫克,某次大促倉庫將一瓶飲料錄入為2噸(商品重量當時無業務應用場景,預留字段),配送子訂單表存儲了多瓶飲料的子訂單,導致配送無法創建運單。
上下游同一業務字段要保持一致,如果有字段轉義,需要做好字段截取、報警、應急預案,在保護好自己的同時,能快速解決異常case。
(7)DB容量、索引等
DBA單表建議小于500萬,不用索引要刪除,以免影響寫入性能。
(8)DB變更導致
改索引、改字段類型、字段擴容會引起鎖表,有的會影響主備同步,假如恰好有業務報表依賴備庫,會造成業務報表不可用。凌晨做的數據結構變更沒有設置停止時間,導致早上7點DB變更還沒結束,影響了業務。數據變更批量改了gmt_modified時間,恰好有該字段的索引導致索引重建,影響庫性能,所有依賴精衛都產生延遲。
DB變更要評估變更影響,自己拿不定主意的要找DBA確認,多找老司機咨詢。
(9)db表非utf8mtd
emoji格式文本存儲到非mtd類型表后,查詢導致emoj無法顯示。
3.2 HSF依賴
(1)hsf服務超時
hsf超時時間不能設置太長,特別是高qps和高可用接口,hsf超時時間過長會導致hsf線程池打滿,智能調度算法數據采集中,由于qps較高,同時訪問ADB容易造成抖動,hsf服務的超時時間設置默認3秒導致hsf線程池打滿,數據采集功能在預發環境中排查出不可用。
(2)hsf超時重試
由于網絡抖動造成的hsf超時可通過重試避免,相對短的超時時間+重試機制比默認超時時間更可靠,在攬單上限hsf服務接口請求時,由于默認3秒超時和沒有重試導致每天五百萬服務攬單上限請求有25次左右失敗率,使用了500ms重試+2次重試機制后一周失敗量才1次。
(3)服務緩存
訪問數據相對穩定的接口,并且耗時較長的接口需要設置前置緩存,減少訪問依賴,同時保證穩定性。強依賴的接口,容易做緩存的接口需要設置后置緩存,當訪問服務失敗后能夠請求緩存數據,同時每次請求成功需要更新緩存。
(4)服務降級
強依賴接口當服務不可用時需要設置降級機制,比如降級到上述緩存,或者降級到其他接口,降級到diamond,降級到內存等等,保證服務鏈路走通的同時,配合接口報警機制,即時發現依賴服務的問題。
(5)服務隔離
核心應用不能依賴非核心服務,同樣,非核心應用不能依賴核心應用,兩者都會造成核心服務被影響,配送倉配一體化調度和o2o智能調度同時使用walle-grid計算服務,但是一體化調度重要程度低,只影響調度效果,o2o服務重要程度高影響指派。我們通過版本號對服務進行隔離,如果有需要可根據分組規則或者自定義路由規則進行隔離。
(6)流量預估和壓測
上新功能增加了依賴,或者會有較大新流量的,需要對流量進行預估,并且按流量進行單接口壓測。配送批次組相似度打分服務上預調度功能時,預估增加0.5倍批次,兩兩計算的笛卡爾積是2.25,估計全量開預調度增加3倍以內流量,當前系統在不增加機器情況下可以扛住洪峰,實際開啟預調度后驗證無問題。
3.3 HSF服務提供
(1)服務超時
相應的服務提供者要提供相對可控的超時時間,以防被人把線程池打滿,承諾的超時時間可根據系統壓測后得到,或者通過線上鷹眼的統計給出一個相對靠譜的超時時間,并不斷優化,默認3秒的超時在高穩定要求領域盡量少用。
(2)限流
除了設置相對靠譜的超時時間,還需要對服務能夠提供的流量進行限定,核心服務一定要增加sentinel做限流。sentinel可根據單機限流,粒度可以是qps或者hsf線程數。一般按qps限流較多,微服務也可按線程數限流。
智能調度請求騎手服務,正常情況下騎手服務性能很高,簡單的db的uk查詢,按理說該服務不會有問題,某次大促時db發生了主備切換(DB當時非單實例,其他DB影響了),導致長時間db不可用,高qps流量過來把騎手服務應用線程池打滿,通過限流措施截斷流量,這時上游調度系統使用后置緩存正常返回,如果沒有限流,騎手服務導致線程池被打滿,整體系統將陷入不可用狀況。
(3)冪等
上游服務重試,下游保證冪等,冪等包含簡單單據冪等,也有比較復雜的冪等邏輯,比如批量請求的接口。和上游約定好冪等邏輯,以及冪等返回值。冪等要返回成功,服務端自己吃掉異常。
(4)服務緩存
服務提供者通過前置緩存提高系統支撐流量,可應用于返回值相對穩定的服務,服務緩存是否設置前置緩存可根據緩存命中率評估,有的為了支撐高qps流量但緩存命中率低也可考慮。配送某個打分服務是一個笛卡爾積類型的服務,n個單據就有n*(n-1)/2次調用,假如20秒調用一次,這時候設置1分鐘緩存,理論命中率雖然只有67%,但提高了2倍流量,可有效減少機器數量。
服務后置緩存通常用來做服務降級邏輯,攬單上限這個核心服務,有三級兜底邏輯,分別是騎手值、城市值、內存值,保證服務端的高可用。
(5)服務隔離:同上
(6)流量預估和壓測:同上
3.4 tair依賴
(1)tair各種產品適用場景
MDB是常用的緩存,常用扛高qps,但是MDB不保證持久化,MDB分單集群和獨立集群,獨立集群有兩個集群數據存儲完全獨立,不能保證數據緩存后能被訪問到,MDB不適合用分布式鎖。LDB持久化存儲,非此場景都不需要用。RDB有同步淘汰策略,當容量不夠時會觸發該策略,導致寫入延遲。批量接口單次請求限制在1024個,建議批量接口單次請求不超過100個。
(2)緩存容量和qps
緩存容量和qps不足時要擴容,MDB一般可支持qps 100萬,RDB10萬。
(3)吞吐量
tair都任何場景都不適合大key和大value的情況,key 1k,value不超過10k,極端情況下會造成數據被拆分,導致數據丟失,批量寫入要減少批次數,skey不超過5120。
(4)緩存超時
緩存一定要設置超時時間,單位是秒,新同學有認為單位毫秒導致超時時間過長緩存超容量的情況。
(5)獨立集群和單集群
MDB獨立集群兩個集群完全獨立,na61只提供給61機房的系統訪問,62訪問不到,由于獨立集群的問題,會導致緩存數據訪問不到。
(6)tair分布式鎖
tair鎖使用put和get方法,鎖的version從2開始,鎖要考慮超時情況,可通過重試機制避免超時造成的影響,鎖網絡超時的ResultCode返回值可能ResultCode.CONNERROR,ResultCode.TIMEOUT,ResultCode.UNKNOW。
(7)緩存數據一致性
簡單的一致性問題比如DB和緩存,db更新成功后可多增加幾個通道保證db執行成功后發出消息,緩存做好冪等,考慮系統掛了的情況可以依賴db變更的精衛消息或者binlog消息做數據對賬。
我們遇到的一致性問題比較隱蔽,某個打分服務做緩存減少笛卡爾積計算,最開始設置緩存Key是單據,value是相似度分數對象,但是算法在使用單據對象的時候,相似度分數類包含了已分配單據對應到站騎手,假如為騎手1,第二次計算的時候,還是拿到的騎手1,但是騎手1已經離站了,導致一個NP問題,后改成單據+騎手的緩存key才解決該問題。
總結一下,會被上下文修改的對象不適合做緩存,緩存對象要做到粒度小,且不被上下文改變。
(8)緩存擊穿
緩存失效訪問DB是一件高風險的事情,特別是高qps情況下,非常容易把DB搞掛,當緩存擊穿之時就是故障來臨之日。設置熱點數據延長過期時間,穩定的數據使用內存緩存兜底,使用加鎖策略保護db,db訪問限流等。
3.5 Metaq依賴
(1)Metaq consumer線上未注冊
該問題會導致注冊后批量消息發送。在消息平臺中短信業務接入后忘記去線上訂閱導致訂閱時短信一起發出去,造成業務大大的黑人問號。可以通過低峰期清理topic的消息后,再進行訂閱。
(2)metaq size限制
單條消息限制128k,超過該限制會發送失敗。
(3)metaq 發送失敗
雖然metaq比較穩定,但是偶爾會有metaq發送時失敗的case,可能是metaq broker集群抖動,網絡問題等,重要的Metaq消息發送要做發送失敗監控,可通過手動補發,或者通過消息對賬,自動重試。
(4)metaq 消費失敗
消費最多重試16次,最大重試間隔2小時,可修改重試間隔減少重試時間,可以設置Metaq循環重試,超過15次后再發送一條metaq,形成metaq循環,不建議死循環,可通過消費時間進行控制。
(5)metaq qps/tps
發送和消費的單topic qps/tps都應小于3000,某次topic tps超過3000被Metaq同學釘釘通知,最后發現是一些廢棄的blink任務在寫,停止后重啟metaq恢復。
(6)metaq 堆積監控
metaq堆積一般是由于業務系統自身處理失敗引起的,少部分原因是metaq的服務端問題導致部分通道無法消費,metaq平臺可配置消費堆積監控,默認值1萬條,重要業務可設置相對較少的堆積條數,比如設置1000條上限左右。
3.6 精衛依賴
(1)精衛數據傳輸亂碼導致無法寫入DB json字段
db有個字段是json格式,通過精衛傳輸到讀庫時,由于中文解析問題導致json格式被破壞,無法寫入db,db字段慎用json格式。
(2)精衛延遲
DB變更,DB索引不一致,字段不一致等導致精衛延遲或者精衛自身問題導致延遲,重要業務需要配置延遲報警,在DBA和精衛同學雙方確認下,可以加大寫入并發,擴大精衛同步tps,追趕延遲數據。
(3)精衛暫停任務
精衛任務暫停可設置檢測自動重啟,或者訂閱精衛delay監控,手動重啟任務。
3.7 DTS依賴?
(1)DTS 網格任務/并行任務離散化
并行類任務需要考慮下游的承載能力做離散化,否則會造成qps熱點。
(2)DTS 降級
可實現一個本地分布式調度任務,在DTS不可用時可降級。
(3)DTS監控
設置DTS超時監控,DTS返回失敗監控,DTS沒有正常啟動監控,除了中間件級別的監控以外,還應該設置DTS運行的應用級別調用量監控,在量級穩定的情況下,DTS每分鐘的調度次數應該在閾值之內。
3.8 開關
(1)開關推送檢查和監控
開關推送要檢查是否生效,推送完開關后要刷新開關頁面,查看當前值,最好做一個開關生效日志監控,推送開關后查看日志是否所有機器都生效。
(2)多個diamond分批發布開關
多個diamond開關分批發布要注意,某個開關分批發布暫停時,其他開關發布無法生效,需等待其他開關發布完成。
(3)開關初始化
開關編碼時要注意初始化影響,在系統啟動時,被依賴的開關沒有初始化會有NP風險。
(4)開關多線程影響
我們的開關基本都是單例在多線程環境中使用,開關發布要注意數據的可見性,比較復雜的數組或map結構,推薦使用影子實例完成開關狀態變更。
(5)開關接入changefree
開關變更最好接入changefree,審批人要設置多個,以防緊急開關推送和開關回滾找不到聯系人。
3.9 監控
(1)流量監控
流量監控包括提供的服務的qps,依賴服務的qps,周期任務的執行次數等,流量監控反應業務穩定期間的大致流量。配置監控包括周同比、天環比、流量閾值。流量監控需要不斷評估和探索業務在合理變化范圍,可用odps統計近一個月的數據,設置相應監控值。
(2)錯誤數量/成功率監控
有些業務流量較低,重要層度卻很高,這時候錯誤數量和成功率監控是最合適的,可以按照分鐘均值來統計,避免網絡原因或系統load抖動造成的正常服務失敗。
(3)錯誤原因監控
錯誤原因監控可快速定位業務錯誤,錯誤日志按照固定格式打印,錯處原因數量按錯誤分類計數。
(4)RT監控
RT是服務時長,反應服務的當前健康度,可按照分鐘均值統計,避免網絡原因或系統load抖動造成的正常服務失敗。
(5)大盤
P級故障具備監控條件的都需要配置在監控大盤,監控大盤能夠總覽所有系統業務監控指標,快速定位具體問題。
(6)系統異常監控
可對所有系統配置NP錯誤監控、數據越界監控、類型轉換錯誤,此類runtime錯誤肯定是系統bug導致,很可能是發布導致的問題,配置該監控能夠第一時間發現發布的問題。
3.10 灰度
(1)系統對服務有多次狀態依賴不可分布發布
一個鏈路中兩次依賴系統中的狀態值(db或tair或內存或其他存儲),系統正在發布中,兩次依賴導致訪問了兩個不同的狀態值,狀態不一致阻塞了系統鏈路。在很多下線作業場景,灰度的粒度是以業務劃分粒度的,而不是以流量,因此某些場景下使用業務單元灰度較合適。
(2)切流前評估流量
在大規模切流前,要評估系統即將承受的流量,在前期切10%左右流量后,能夠近似的根據業務特征對后面90%流量作出合理評估。評估流量后可使用壓測評估機器是否能扛住后續流量。
(3)灰度預期和方案回滾
灰度要有業務預期和系統預期,業務預計比如是否按產品流程執行完成,是否灰度流量覆蓋了所有TC的case,系統預期比如是否系統error數同比和環比一致,是否有新增的異常,是否有NP錯誤。
灰度不符合預期需要立即回滾,不用考慮任何原因和后果,事后再做分析。預調度灰度期,正好盒馬封網,經過層層審批才上線灰度一個站點,灰度開始10分鐘內業務表現正常,但是系統出現了未曾出現的錯誤日志,隨后出現預調度批次不指派,我們立即進行回滾。事后分析了一整天(只在低峰期出現),是緩存對象被改變了導致NP錯誤。
3.11 測試
(1)預發空跑驗證
預發造測試站點流量,驗證功能可行性,預發空跑是測試驗證前期要完成的,按照TC造多個case,驗證是否符合預期。
(2)預發引流驗證
預發從線上引導流量,驗證產品邏輯,預發從線上引流是為了用大流量驗證系統功能。像智能調度如此長的鏈路,我們用引流可以驗證一些數據難造的場景,以及TC之外的場景
(3)線上引流比對
可單獨為線上站點開起新調度和老調度,并對業務最終指派結果進行比對,從日志上分析行為差異性,是正常的時延差異還是系統bug。還可按照統計學的方法對系統核心指標進行比對分析。
3.12 應急響應
沒有完美設計的系統,bug總是存在,當出現線上問題的時候如何應急處理呢?為了避免線上問題出現時手忙腳亂,需要做好“天晴修屋頂”,這里的“修”既包含上述架構治理、監控完善,也包含應急預案梳理和故障演練。
(1)應急預案梳理
應急預案包括系統上的開關、限流工具、降級預案等也包含業務測的應急響應措施,在系統短期無法恢復時,也能正常作業下去,比如配送小票作業,能在配送系統無法攬收時,通過小票完成貨物攬收和配送。
系統上的預案要做到事前驗證,在預案上線后驗證預案的有效性;一鍵推送,通過預案平臺能夠一鍵觸達,快速生效預案;組織培訓,預案要深入人心,讓組內每個同學都掌握如何操作,以及何時操作。
(2)故障演練
為了避免故障來臨時人心慌亂,提高決策效率,縮短問題定位時間,需要在平常做好故障演練。故障演練要當作線上故障對待,由測試在安全生產環境發起,故障演練要做到真實,演練要保密,推薦測試和開發人員使用紅藍對抗實踐故障演練。
為了提高開發應急運維能力,需要有一套故障應對響應機制,盒馬配送從組織、發現、決策、善后四個角度出發,沉淀了一套故障應急響應方法,在故障來臨之際要組織團隊leader和團隊成員停下手頭工作,All In故障處理,首先建立溝通群,其次從大盤監控發現問題點,然后針對問題點決策執行相應預案,當報警恢復時再評估影響面,是否存在故障引起的遺留問題。
(3)故障處理
經過多次故障演練,能有效培養團隊故障發生的應急運維能力,故障發生時切記不要盲目的分析故障原因,而是應以最快速度止血和恢復。80%以上的故障是由變更引起,不管是發布、開關推送、新增配置、上下游有發布等等,少部分是由于流量增長和其他上下文環境變化引起。如果發生故障時存在變更,則需第一時間回滾,如果是其他原因,那么可根據系統癥狀,決策推預案、重啟、擴容等,如果無上述措施,則要分工合作,組織人對外溝通、排查日志、檢查DB、查看服務流量、分析鏈路trace等,以最快的速度定位問題。
四、總結
智能調度在不停發展中,我們接下來還有策略運營、智能診斷、仿真等進行中的項目,除了已有的穩定性作戰經驗之外,我們還將繼續迎接新的穩定性挑戰,探索不同環境下穩定性最佳實踐。
總結
以上是生活随笔為你收集整理的如何做到全年配送 0 故障?盒马揭秘 12个关键技术的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端代码是怎样智能生成的?
- 下一篇: Java经典面试题整理及答案详解(二)