1.問題背景
這個流水號的使用場景是上游系統(tǒng)調(diào)用下游接口時傳入一個唯一 ID,流水號這個參數(shù)在聯(lián)調(diào)或定位問題時很方便。
我們系統(tǒng)中的流水號是一個 32 位的字符串,為了能讓上下游系統(tǒng)聯(lián)動,下游系統(tǒng)接到上游傳過來的這個 ID 后,會取前 23 位,再自己拼接剩下 9 位,傳到自己要調(diào)用的下游系統(tǒng),這樣整個調(diào)用鏈通過請求 ID 就可以快速串起來。
2.流水號使用
在我的系統(tǒng)中,自己定義流水號的后 9 位,為了能夠更清晰地從流水號中看到請求鏈上的系統(tǒng)調(diào)用關系,我們把流水號后 9 位定義成了系統(tǒng)編號(3位) + 子系統(tǒng)編號(2位) + 自增序列(4 位) 。
在我們的業(yè)務場景中,上游系統(tǒng)調(diào)用我的系統(tǒng),我的系統(tǒng)有 10000 個流水號,支撐 10000 筆交易,理論上足夠使用了。
不幸的,系統(tǒng)中的業(yè)務開發(fā)同事并沒有注意到流水號生成規(guī)則,因為流水號生成工具是一個成熟的 util 類,大家直接調(diào)用獲取流水號。
而這一次的事故中,我們的業(yè)務是一個批量業(yè)務,收到上游系統(tǒng)的請求后,我們的處理邏輯是讀取合作方推送的文件,然后對每一個文件調(diào)用下游接口進行處理。每一個文件處理需要調(diào)用下游四個接口,每一個接口都需要新的流水號。
這樣我們就能看到流水號生成工具的瓶頸了,如果超過 2500 個文件,10000 個流水號就會被用完。而流水號生成工具的邏輯是如果流水號用完,就會從 0 開始重新生成,造成了流水號重復。
下游系統(tǒng)會對流水號進行判斷,收到重復的流水號,直接返回接口調(diào)用失敗。因為失敗的調(diào)用比較多,觸發(fā)了生產(chǎn)告警。
3.事故處理
比較慶幸的是,這次事故并沒有造成交易阻斷、現(xiàn)金損失、客戶體驗差等問題。還有一點幸運是正好趕在上線窗口前發(fā)現(xiàn)了,沒有走緊急上線流程。要知道,緊急上線對團隊和個人的績效考核都會產(chǎn)生影響。
但交易失敗的三方文件會影響合規(guī)檢查,必須進行交易補償。
我們團隊做的修復工作是及時修改了流水號生成規(guī)則,我們把后面 6 為定義成自增的序列,這樣足夠滿足所有場景的使用了,而我們保留系統(tǒng)編碼,對系統(tǒng)交易鏈路追蹤是非常必要的。
上線后,請上游系統(tǒng)再次觸發(fā)接口調(diào)用,對之前失敗的三方文件進行補償處理。
4.聊聊事故
無論在國企、銀行還是互聯(lián)網(wǎng)公司上班,生產(chǎn)事故的出現(xiàn),都可能會影響到公司正常業(yè)務的開展,甚至讓業(yè)務遭受損失。嚴重的,事故當事人會收到嚴格處罰,甚至被淘汰掉。
除了對考核的影響,解決故障的過程也是非常耗時的。
4.1 應急措施
在沒有定位到問題之前,必須先采取緊急措施接觸生產(chǎn)告警,以免造成大的業(yè)務損失。應急措施包括但不限于重啟服務、執(zhí)行應急腳本、業(yè)務降級等。
4.2 定位問題
采用應急手段解決故障后,就要開始定位問題了。有的問題可能不太好定位,尤其是一些老代碼,作者已經(jīng)離職,也沒有留下什么詳細的文檔。接手人可能之前看過代碼,但是過了很長時間又記不清了。
4.3 評估業(yè)務影響
再復雜的問題,最終肯定能定位到原因。接著就是評估業(yè)務影響,這一步也是必須要做的,因為多數(shù)情況下,對業(yè)務的影響大小決定了這次事故的級別,這項工作一般會有業(yè)務參與。
比如我過往的一家公司規(guī)定,故障超過 15 分鐘,影響超過 100 筆訂單的故障定義為一級故障。
4.4 向上匯報
接著就是給領導匯報,甚至需要層層匯報。這一步可以說是最難做的。
首先需要明確問題責任人或者責任團隊,因為故障可能會影響到績效考核,所以很多時候會遇到扯皮或帥鍋的情況,沒有一個領導愿意讓自己的團隊背鍋。有時候把鍋甩給中間件,數(shù)據(jù)庫或其他底層組件,也是一個選擇。
撰寫事故報告也是非常耗時的一個工作,領導不可能像技術人員一樣通過看代碼了解事故原因,他們需要故障報告能夠清晰易懂,甚至幾句話就能講明白。
4.5 復盤
事故復盤是為了讓團隊能夠了解到故障的根本原因,作為經(jīng)驗教訓,防止再犯。