下單穩定性治理
1、為什么寫這篇文章
在工作期間,筆者有幸參與了下單鏈路的開發、維護工作,在這期間有經歷下單從0到1的搭建,也有隨著業務發展不得不進行系統重構的經驗。“提交訂單”這一詞大家應該都是再熟悉不過了,不管你是不是軟件研發人員,還是普通使用電商APP購買商品的用戶,只要你在購買商品時必然會遇到。既然“提交訂單”這么頻繁的被使用到,作為任何電商APP來說,那么它的穩定性就尤為重要。
那么站在技術視角看下單鏈路,會發現幾個特點
- 高QPS/TPS,流量大
- 訂單數據正確性要求極高
- 監控告警時快速定位能力
- 結算頁到訂單創建成功的所見即所得
- 易被惡意流量刷單
- 依賴下游服務非常之多
- 業務邏輯很復雜
本篇文章就挑幾個在日常研發中可能會遇到比較明顯的問題,以及是怎么進行應對的。
2、可能遇到的問題
2.1 線上告警頻繁,精準定位問題耗時較長
告警機制,這個大家最熟悉不過的了,作為技術人的對這可以說是又愛又恨吧。即討厭線上頻繁告警的打擾,又擔心真正發生告警時的定位難。常見的主流監控,Zabbix、Promethues、Open-Falcon等主要監控的指標還是以應用維度為主,主要監控指標如下。
- Dubbo接口:請求量、耗時、異常量。
- JVM :GC次數、GC耗時、各個內存區域的大小、當前線程數、死鎖線程數。
- 線程池:活躍線程數、任務隊列大小、任務執行耗時、拒絕任務數。
如圖,類似于這種告警應該是比較熟悉的。那么這里的問題也很明顯,下游接口異常到底影響的是哪個鏈路呢?針對這種特定業務場景,如訂單結算頁、提交訂單,這類接口級別的監控又該怎么做呢?那首先簡單介紹下在一次下單請求中可能遇到的問題
- 下游接口調用告警
- 強依賴接口和業務可降級接口,怎么進行區分?
- 當告警來了,怎么確認是下單鏈路所依賴的接口呢?
- 下游接口告警了,是預期內的業務異常還是非預期內的呢?
- 接口rt&接口QPS抖動告警
!由于熱門商品、大促等活動節日的存在,所以下單鏈路會經常出現這類告警
- AVG RT的下降,怎么識別是否正常?
- QPS的突然升高,升高的原因是啥呢?到底是下單鏈路阻塞了導致用戶一直重試,還是發生了搶購呢?
- 依賴的中間件發生抖動告警
- 怎么快速感知是MQ、Redis、DB等的異常?
- 應用自身出現異常告警
- 普通業務異常:例如當前APP版本不支持XXX新業務,非法請求核心參數缺失
- 非預期異常:新上線的業務代碼整出了異常導致下單阻斷
- 怎么區分普通業務異常和非預期異常?
普通業務異常:例如當前APP版本不支持XXX新業務,非法請求核心參數缺失
非預期異常:新上線的業務代碼整出了異常導致下單阻斷
2.2 當購買期間商品信息發生變更,怎么保障用戶的購買體驗呢
在用戶購買東西時,首先會看到訂單結算頁面,這個上面會展示商品價格,售后保障,到貨時效,優惠信息等,這時用戶在確認條款后會提交訂單,那么在訂單生成后訂單詳情看到的理論是需要和在結算頁看到的信息是完全一致的。但是由于結算頁和提交訂單是分開的請求,那么這個時間GAP以及實現差異終究可能會帶來不一致的情況發生。如果是普通庫存的話,給用戶直接重新展示訂單結算頁也還行,要是搶購商品的話,那這個體驗就會有比較大的影響。
2.3 依賴方數據返回不合法,該如何及時感知
訂單的數據是相當復雜的,需要依賴商品、庫存、營銷、商家等數據信息,不同的業務場景對生成的訂單數據就會存在一定的要求。
那么這件事情的必要性,就在于可以在系統上線之前,通過回歸測試及流量回放驗證來及時發現是依賴方接口導致的問題還是自身系統代碼bug帶來的影響。
3、解決方案
那么問題來了,既然決定好好治理,那么怎么治理呢?怎么以最小的人力、技術成本實現這些治理呢?這個時候大量參考了現在同行業內針對下單場景穩定性相關的方案。現在就逐一介紹以上問題最終選擇的解決方案。
3.1 自定義實現告警機制的基礎日志數據埋點
針對接口級的定制化告警,采用了自定義日志埋點的方式,格式如下:
{current_time}|{trace_id}|{span_id}| {function_name}|{rt}|{error_code}|{error_message}|{user_id}
- function_name:用來具體區分哪個接口
- error_code:接口錯誤碼,用來唯一標識接口異常原因,重點就是這個,這個指標數據輸出的精細程度決定了定位問題的速度
- rt:接口響應時間
這里簡單畫個圖,直觀的體現下需要關注下單鏈路中哪些指標
現在介紹一下每個指標的作用:
- 網關QPS:觀察C端的實時入口流量
- 自身服務QPS:觀察到達服務本身的流量
網關QPS > 自身QPS,可以考慮是否網關側發生了限流
當自身QPS下降過高
網關QPS沒什么波動,那么這個時候考慮網關問題
網關QPS也同步下降,前置導購鏈路流量問題,如商詳/購買浮層 是否發生阻斷性異常
- 自身業務異常:輸出下單阻斷的業務原因,又稱為預期內異常
- 自身其它運行時異常:如NPE,稱為非預期內異常,此時錯誤碼會統一輸出SYS_ERROR,一般此類會重點關注
- 下游接口RPC異常:此時會輸出是下游哪個接口導致的阻斷,如
- 商品查詢接口超時 -> QEURY_SKU(RPC_TIMEOUT)
- 用戶接口查詢網絡異常 -> QUERY_USER(NETWORK_EXCEPTION)
- 下游接口業務異常:如
- 優惠已失效 -> CONSUME_DISCOUNT(INVALID),這里會通過識別下游接口返回的code碼來區分不同的業務異常,所以在日常需求中要求下游接口提供方確保返回碼的含義就是這個原因
- 返回了未約定的code碼,統一會返回如XXX(BIZ_ERR),看到此類錯誤碼的時候,就會及時反饋給下游服務Owner去跟進這個問題
- 中間件訪問異常:
- SQL執行異常
- 網絡連接RST異常
- 自身服務接口AVG RT/SUCCESS RT
- 這里主要說一下SUCCESS RT,這個指標是可以最準確的反饋出最近RT是否存在波動
- 自身服務接口AVG QPS/SUCCESS QPS
- 這里的success qps很重要,當發生搶購的時候,整體QPS會大幅上升,這個時候可以SUCCESS QPS來判斷當前成單量是不是穩定
如果是淺庫存搶購,這個指標不會有太大波動
接口被刷了,這個指標也不會有太大波動,且會出現OPERATION_TOO_FREQUENTLY頻次限流錯誤碼
!通過將接口每次請求的埋點日志輸出到指定文件中,后續經過監控組采集以及分析得到了如下幾個主要的大盤:
1)確認訂單&創建訂單錯誤碼大盤
從圖中可很直觀的發現當前有哪些原因導致的下單失敗,如版本過低限制、庫存售罄、下單頻次過高等原因,這樣就能很直觀的發現
- 從異常名可以看出是有很明顯業務語義的,這樣便于大家理解
- 針對下游接口調用,會輸出具體某個接口(也可以給對應接口定義別名)的某個類型錯誤,如優惠核銷的超時、優惠已失效、優惠已使用
另外還設計了基于機器IP的過濾,這種做法的好處是,在發布過程中,如果下單出現了任何阻塞性異常,都可以很快的感知到,從而可以快速做到SOP響應處理。
對于鏈路中的業務弱依賴接口,這里不會有錯誤碼體現,這里依然還是借助于監告警機制。
2) QPS&RT指標數據
這里主要日常監控觀察主要會注重成功量QPS,特別是發布期間完全可以依賴于這些指標數據。例如發布期間這個時候在搶購,有了這個就能做到心中有數了。這里簡單說明一下成功量就是接口業務執行成功的含義。
3)告警機制
有了如上的這些指標數據,那么基于這些做告警機制就成了順理成章的事情啦,目前已經有如下指標告警:
- 錯誤碼環比漲幅超指定閾值
- 接口RT環比漲幅超指定閾值
- 接口成功量QPS環比下跌超過指定閾值
然后再將這些告警機制接入飛書、短信等通知,那么哪怕是在周末外出游玩的時間,有任何下單鏈路的異常告警,只需要打開手機看一眼就能快速定位到問題的根因所在了,豈不美哉?
以上就是針對下單告警機制的精細化處理了,除此之外,有了這些數據后,也對其它一些指標數據也進行了完善,如:
- 高頻訪問用戶
- 不同入口的實時下單量
- 當前熱門購買商品
3.2 基于版本號的商品信息&數據一致性校驗
1) 商品價格變更
商品改價這個在電商中應該是比較常見的,那么如果是在秒殺時改價,那么此時提示用戶“商品價格”變更可能對用戶的體感就沒那么好。針對這類問題可以采用商品信息+版本號機制。
用戶在訂單結算頁看到的商品數據版本會交由客戶端攜帶至提交訂單,此時提交訂單可以校驗該版本的生效時間是XX秒內,確保這個時間內訂單提交不受改價影響,這樣可以給到用戶一個較好的購買體驗。這個XX時間就需要業務來進行權衡了。
2)數據一致性校驗
通過以上的UML圖可以看到,由于確認訂單和創單是兩次請求,那么保證數據防篡改是第一要求,而且有了這個驗簽機制后,用戶自己通過簡單傳參刷創單接口就變得更加困難了。對于迭代版本中新增生成sign的參數,這邊主要采用version版本的方式,不同的version對應參與生成version的參數有所不同。
- version1,參數 a、b、c
- version2,參數a、b、c、d
有了防篡改的保障后,那么接下來就只需要在下單資源扣減之前,針對這些核心數據進行一致性校驗即可,如訂單金額、展示給用戶的售后標簽等等。這樣的話在出現不一致時可以給到用戶友好的提示,并且對可以及時進行告警通知。
3.3 訂單數據正確性校驗&及時告警機制
一致性校驗節點旨在創單落庫節點前給恒久不變的規則(如:訂單支付金額 = 應收金額 - 優惠 )提供下單前的兜底校驗及可選告警措施。不太適合落地多變的規則。如果是多變規則需要寫到對應業務模塊以異常形式告出。大家自行判斷所屬業務屬于哪一種。
訂單數據完整性校驗致力于保障訂單在整個生命周期中數據的正確性。為用戶打造一站式的校驗、預警解決方案。提供以下能力:
- 可插拔式接入
- 場景定制化
- 動態降級
- 規則、預警可擴展
- 統一流程處理
適用的場景:
- 商家地址返回手機號存在掩碼問題,必要數據缺失
- 優惠接口在某種特定業務場景下未返回對應的優惠信息
- 訂單金額計算是否一致與用戶看到的一致
4、雨過天晴后的??
1)基于錯誤碼大盤及監控機制的問題快速定位
- 核心接口全局監控,高靈敏度感知任何阻塞下單的問題
- 監控機制實時告警
2)下單鏈路一致性機制保障,所見即所得
3)創單數據正確性兜底校驗
5、總結
在下單的穩定性治理過程中,從面對線上告警的盲目無措,逐漸演進到面對日常迭代變更、突發流量場景的鎮定自若。在日常工作中,持續關注、發現線上潛在的問題以及不合理的設計,然后盡量通過合理機制&實現來進行保障。作為一名研發人員,不能確保不犯錯,但能盡最大努力及時發現錯誤,敬畏生產。幾套打完收工,可以手握小茶壺,靜看風波了。