記人生第一次線上事故

第一次作爲開發 owner 主持迭代會議,整個過程戴着耳機,昏昏欲睡地聽同事一個接一個講自己的技術方案。疫情期間,技術評審以線上形式進行,三十平的會議室裏只有四個人,彼此隔開兩米以上,勉力維持不能再低的安全感。評審即將結束的時候,mentor 突然問小組 leader 可以離開不,接着解釋說線上出事了,是剛上線的那個服務。

沒什麼可懷疑的,就是我負責的服務。

leader 很淡定,問怎麼了。mentor 已經托起筆記本朝外走,說業務有問題,幾百單卡住了。我腦袋突然熱了一下,有點懵,坐在椅子上沒動彈。三月的深圳氣溫已經達到 20 度,每天來去匆匆沒什麼感覺,活在這個城市卻像個一無所知的過路人。直到 mentor 說線上出事故了,這時候我才渾身發熱,腦門發潮,重新對深圳的溫度有了切身的感受。

leader 依然很淡定,讓我也去看看,他來主持會議。我立即退出線上會議,產品 owner 不明所以,馬上又發來會議邀請,被我乾脆利落地拒絕了。抄起電腦跟着 mentor 出了會議室,在空蕩蕩的走廊上我纔敢問,線上發生什麼故障了。

mentor 是工作十多年的大佬,家裏有個讀小學一年級的兒子,平時沒事就喜歡去海釣,只不過那時候也隨身帶着筆記本。大佬說現在還不清楚,坐回工位立馬就登錄生產機器看錯誤日誌,一邊讓我先把服務腳本停了避免產生更多的錯誤數據,接着把舊服務重新裝在線上啓動起來,儘快恢復服務

沒錯,我負責的是舊服務的遷移重構。舊服務是 C++ 的守護進程,任務是從消息隊列裏面拉消息跑異步流程,我的任務是把它改造成 Java 的異步腳本,由 Saturn 調度。這個東西可以說就是小組裏的業務核心,小組 leader 很重視,上午親自配合完成灰度測試,逐步把舊服務完全停掉了。新服務測試了很久,開發完成就自測了一週,之後測試人員也測了一個禮拜,全量發佈之前我還時不時調度腳本從消息隊列里拉消息跑,沒想到上線還沒幾個小時就出故障了。

這真是出師未捷身先死。

mentor 排查故障很快,錯誤日誌顯示是數據庫執行 SQL 語句的異常,貼了日誌去問 DBA ,很快反饋回來,數據更新唯一鍵衝突。

代碼排查沒有任何難度,日誌裏精確地打印了事故現場。MyBatis-plus 框架,選擇目標狀態的行記錄,用 bean 對象來更新數據。代碼一目瞭然,簡單到沒有給歧義留下容身之處。

LambdaUpdateWrapper<Request> updateWrapper = new UpdateWrapper<Request>().lambda()
                .eq(Request::getStatus, preStatus);
int ret = requestMapper.update(request, updateWrapper);

更新操作包裹在一個事務中,mentor 看了一會,鬆了口氣,說還好,看上去數據不難修。大佬確實就是大佬,遇事不慌,碰到故障首先想的是怎麼修數據,其他話一句沒有。我全程保持靜默,安靜得像只豎起耳朵的兔子,在剛拉起的小羣裏一聲不敢出。儘管如此,面對着電腦屏幕我額頭一直冒汗,腦子裏幾乎沒有成邏輯的思路。

大佬提完線上 SQL 單,leader 也開完技術評審會回來,我作爲開發 owner 主持的第一個會議就這樣無疾而終。數據修完,等待系統重試,mentor 和 leader 一起審查代碼,終於發現了錯誤,更新操作沒有指定唯一條件,導致帶唯一鍵 的 bean 對象去批量更新目標狀態的表數據行,造成了唯一鍵覆蓋的衝突

分析之後也就明白了這個 BUG 爲什麼沒有測試出來。之前在測試環境的時候腳本都是部署一臺機器,數據量比較小,一次更新時處於同一個目標狀態的數據只有一條,更新也就沒有問題。而線上環境腳本在多臺機器上跑,這就會造成同一時間有多條數據處於同一個狀態,根據狀態值去選定數據更新必然會有多條數據同時更新,而採用帶主鍵的 bean 對象去更新多行數據,自然就造成了唯一鍵衝突。修復代碼很簡單,只要指定一個唯一條件就可以了。

LambdaUpdateWrapper<Request> updateWrapper = new UpdateWrapper<Request>().lambda()
                .eq(Request::getStatus, preStatus);
                // 指定唯一鍵條件
                .eq(Request::getId, id)
int ret = requestMapper.update(request, updateWrapper);

人生中的第一次線上事故,沒有想到來得如此簡單直接劈頭蓋臉,讓人都不知道如何自處。

幸好這個故障只導致了流程卡住的問題,對用戶來說幾乎沒有感知,因此對業務的影響也相對較小。也幸好 mentor 和 leader 都是大佬,經驗豐富頭腦清晰,出了事故一句重話都沒說,還在小羣裏安慰只是噁心了一下業務同事,讓他們緊張地跑過來問怎麼回事罷了。尤其是之後又補了一句,小場面,淡定淡定。這像劍客事了拂衣一般風輕雲淡的態度不得不令人佩服,如果大佬嘴上叼了一支菸,此時我就會毫不猶豫地掏出打火機。

總結起來,遇到線上故障首個要點是冷靜,要避免錯誤數據快速大量地堆積,同時儘快恢復正常服務,修復數據,最後纔是排查問題源頭,解決問題。多麼痛的領悟,但願踩過的坑能讓人走更遠的路。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章