日常Bug排查-讀從庫沒有原子性?
日常Bug排查系列都是一些簡單Bug排查。問題雖小,但經常遇到,了解這些問題,會讓我們少走點彎路,提升效率。說不定有些問題你遇到過哦:)
Bug現場
業務開發同學突然問了筆者一個問題,從庫讀會不會沒有原子性?我下意識的反應怎么可能,只要是遵守MySQL主從Replication協議的原子性至少是能夠保證的。但他們遇到了一個比較詭異的現象。如下圖所示:

這么一看確實像從庫沒有保證原子性。但這個明顯有違背筆者的常識,這個問題背后肯定還有其它的因素沒有挖掘到。
數據庫拓撲
于是筆者看了看這個庫的拓撲,是一主兩從的結構。如下圖所示:

真相大白
看到這個拓撲的那一刻筆者立馬反應過來,是踩了一個主從延遲變種的坑。由于請求B的兩條select是不在事務內的,而且都是select。這兩很有可能路由到兩個不同的從庫,而這兩個從庫的主從延遲是不一樣的。例如一個100ms,一個200ms。那么落到100ms從庫的那條sql就會查到請求A的提交,而200ms從庫的那條sql查不到。以致與錯誤的認為從庫不保證原子性!

應該怎么做
遇到這種情況,其實我們所需要做的只是在某次請求中穩定的路由到某個特定的從庫上面,這樣就能保證原子性(要么能查到,要么都查不到)。

如上圖所示,一般在第一次請求之后,在threadLocal中打上相關粘性標簽(SlaveA),那么在這次線程請求中。后來的從庫select都走SlaveA即可。這個選擇邏輯可以通過重載數據源DataSource的getConnection邏輯來實現。
總結
主從延遲是個非常常見的問題。最常見的是主庫寫入后讀從庫沒有相應的數據,當然也有本文描述的這種看上去”不符合原子性”的變種。看似違背常識的背后可能有其它的隱變量(多從庫不同延遲)。多挖掘一點問題現場的上下文信息就很容易揪出問題的根因。


浙公網安備 33010602011771號