表重複更新引起的問題

1. 問題描述

咱們的工程部署在兩個DC上,雙活。兩邊的服務器以及邏輯都是同樣的,也分別都有本身的業務。數據庫用的Oracle,之間有同步,用的是Quest的DB同步產品shareplex。shareplex的原理是,read進程讀取分析數據庫的redo log,把須要更新的數據放到queue裏面,export進程讀取queue的數據,發送到對端的queue裏面,由對端的import進程寫入對端數據庫。數據庫

雖然兩個DC只接收存儲單邊的數據,可是兩邊數據庫都是有完整的數據的。服務器

數據複製

然而最近發現奇怪的問題,兩邊的數據一直對不上,致使不少依賴數據完整性的功能全都錯亂了。併發

2. 問題定位

既然是數據不一致,那咱們就從數據庫同步入手。咱們聯繫了DBA,同時檢查項目裏面有沒有大量的增刪改操做。對併發量大的幾張表有修改的地方咱們都過了一遍,發現並無什麼可疑的地方。3d

等DBA回消息,果真,他們觀察到shareplex的複製隊列有大量的backlog。然而令咱們沒想到的是,堵在隊列裏的居然是對一張數據量並不大的表A的操做。A是一張maintain表,記錄着哪些component正處在維護狀態。每條記錄都必須關聯一個ticket,ticket的狀態有New,InProgress,Done,Completed,Cancelled等等。通常來講這張表的數據只有幾萬條,怎麼會有那麼多增刪改操做在這上面呢?!code

追溯到問題剛開始出現的那個時間節點,咱們是上了一個新功能。簡單描述就是,由於咱們須要保證maintain表A裏的ticket狀態信息是最新的,咱們新加了一個Task,定時從源頭同步ticket狀態。因而咱們仔細看了這塊邏輯,看出了端倪。Code的邏輯是:component

1. 從數據庫取出全部狀態不是Complete的數據
2. foreach處理,從源頭拿到當前數據對應的ticket的狀態信息
3. 執行更新操做,僞代碼以下:update maintain set status = #{status} where ticket = #{ticket}

乍一看,好像是沒什麼問題,可是一細想,咱們的maintain數據跟ticket的關係是多對一的,也就是說,一個ticket能夠跟好多的maintain數據關聯!因而乎,在這種狀況下,每次的update操做都會更新多條數據,並且會更新屢次!若是有100條同樣的ticket,那就會執行100*100也就是一萬次操做。若是是一萬條同樣的ticket呢,那就是一億次更新操做!並且還僅僅是單次的量,考慮到task是定時跑的,量級只能更多。shareplex是撐不住這麼大的量的。blog

3. 問題解決

找到了問題,對症下藥:隊列

1. 只有在ticket狀態有變化的時候纔去更新數據庫 2. 當更新完一個ticket的時候,把ticket放到Set裏面,後續操做若是發現相同ticket已經被更新過了,就直接跳過進程

4. 總結

1. 碰到問題時,要特別留意新增的功能。由於對於比較穩定的項目來講,新增的功能出問題的機率要遠大於老功能。 2. 當遇到在循環裏面更新數據庫的狀況,要特別留意是否是會致使數據重複更新。這不只無故增長了數據庫的壓力,並且可能給數據庫之間的複製帶來災難。部署

相關文章
相關標籤/搜索