公司對底層基礎庫進行了重構,線上穩定跑了幾天,在檢視訂單系統的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 WRITE
,sql
沒有在事務裡執行?再一步的深入檢視程式碼,一直到基礎庫的程式碼終於發現了問題的原因,公司的資料庫基礎庫封裝的有問題,在建立建立事務的時候正確建立了tx
但在執行具體的sql時沒有使用tx
因為sql
沒有在事務裡執行,我們的行鎖也沒鎖住,為了驗證我是正確的,寫gotest
建立兩個事務,第一個事務,不提交也不回滾,正常情況下,第二個事務,會一直等待第一個事務。
果然,直接就列印出來兩個結果,沒有鎖住,再結合CDC
資料中看到的狀態也就能說通了,程式碼被重入了,哪怕有問題 rollback
也不能把已經執行的sql回滾。
終於找到原因了,沒白浪費這麼長時間,修改程式碼
再執行程式碼觀察事務
query
裡有正常的資料了。基礎庫的問題,在業務程式碼的各種測試時都是按正常流程進行的,所以也測試不出一來,盲目的相信業務程式碼,雖然業務程式碼確實沒有問題,如果能早一點進行鎖的測試就能更快的定位到基礎庫的問題。提交MR
修改引用的專案,等低峰上線。
不起眼的錯誤log
資訊,一定要重視,說不定就是個超級大bug在興風作浪,或者是兩個 ( ̄^ ̄)