一次奇怪的的bug排查過程

peng發表於2021-11-30

公司對底層基礎庫進行了重構,線上穩定跑了幾天,在檢視訂單系統的log時,有幾條error資訊非常的奇怪,

orderID:80320180 statemachine error: no event [Revoked] at current state [Paid]

orderID:81983045 statemachine error: no event [Refund] at current state [Revoked]

訂單有狀態機進行維護

  • 已經被撤消的訂單不能再進行有其他操作,和狀態更改。
  • 已經支付的訂單,不能被撤消,只能退款或者部分退款。

這兩條log雖然沒有太大問題,關鍵問題在於,正常情況下,這條log就不應該被執行,所有對訂單進行操作的介面,都會判斷訂單的狀態,如果訂單已經支付,撤消就會直接當做錯誤的操作,返回給客戶端error,這條log所在的地方是不會被執行到的,總結和排查問題

  • 這個錯誤不是每天都有,偶爾會被報出來
  • 有舊的映象在跑舊的業務程式碼導致的?檢視k8s映象資訊,沒有問題。
  • 併發問題導致的?規定在操作訂單的時候都是行級鎖,再判斷訂單狀態的,但需要排查一下業務程式碼,是不是有哪裡有沒進行鎖行操作,導致程式碼被重入了?好在Log也有鏈路id可以根據trace-id來確定是哪個介面呼叫,就能很快定位到問題所在的地方,

根據trace-id追蹤發現了一個新問題,查不到資料,只有那一條錯誤log,檢視程式碼,這個系統的trace在初始化的時候不知道什麼時候被改錯了。

先修復trace-id的問題,但對當前的問題也沒啥用了,等上線後,還不知道這個問題啥時候能復現呢。
只能用最笨的辦法一點點的排查程式碼了,對所有操作訂單的地方進行檢查,程式碼沒有問題,又檢查了一遍還是沒有問題,突然腦子裡冒出個段子:難道是神密力量導致電纜裡的幾個bit出了問題,導致我們的程式碼執行異常了?哈哈。
又檢查完一遍業務程式碼還是木有問題。資料庫的問題?那還不如是系統的bug呢。
這時候同事匯出一份CDC資料,根據這些資料檢視訂單支付狀態,從2->3->2 變回去了,正常流程下不可能有這樣的情況發生,100%確定就是系統的問題,但業務程式碼中沒有看出問題來哇!

debug看一下資料庫(postgresql)裡事務的執行情況,
找一個事務的pid

到資料庫pg_stat_activity裡觀察執行情況

發現一個更奇怪的現象,無論我執行插入還是執行修改操作query欄位裡一直都是BEGIN READ WRITEsql沒有在事務裡執行?再一步的深入檢視程式碼,一直到基礎庫的程式碼終於發現了問題的原因,公司的資料庫基礎庫封裝的有問題,在建立建立事務的時候正確建立了tx

但在執行具體的sql時沒有使用tx

因為sql沒有在事務裡執行,我們的行鎖也沒鎖住,為了驗證我是正確的,寫gotest建立兩個事務,第一個事務,不提交也不回滾,正常情況下,第二個事務,會一直等待第一個事務。

果然,直接就列印出來兩個結果,沒有鎖住,再結合CDC資料中看到的狀態也就能說通了,程式碼被重入了,哪怕有問題 rollback也不能把已經執行的sql回滾。
終於找到原因了,沒白浪費這麼長時間,修改程式碼

再執行程式碼觀察事務

query裡有正常的資料了。基礎庫的問題,在業務程式碼的各種測試時都是按正常流程進行的,所以也測試不出一來,盲目的相信業務程式碼,雖然業務程式碼確實沒有問題,如果能早一點進行鎖的測試就能更快的定位到基礎庫的問題。提交MR修改引用的專案,等低峰上線。
不起眼的錯誤log資訊,一定要重視,說不定就是個超級大bug在興風作浪,或者是兩個 ( ̄^ ̄)

相關文章