數據庫分庫分表以後,如何解決事務問題?

咱們須要接受失望,由於它是有限的;咱們不會失去但願,由於它是無窮的。spring

1、概述

隨着時間和業務的發展,數據庫中表的數據量會愈來愈大,相應地,數據操做,增刪改查的開銷也會愈來愈大。所以,把其中一些大表進行拆分到多個數據庫中的多張表中。
本篇文章是基於非事務消息的異步確保的方式來完成分庫分表中的事務問題。數據庫

2、須要解決問題

2.1 原有事務

因爲分庫分表以後,新表在另一個數據庫中,如何保證主庫和分庫的事務性是必需要解決的問題。微信

解決辦法:經過在主庫中建立一個流水錶,把操做數據庫的邏輯映射爲一條流水記錄。當整個大事務執行完畢後(流水被插入到流水錶),而後經過其餘方式來執行這段流水,保證最終一致性。
微信圖片_20200704110755.jpg框架

2.2 流水

所謂流水,能夠理解爲一條事務消息異步

上面經過在數據庫中建立一張流水錶,使用一條流水記錄表明一個業務處理邏輯,所以,一個流水必定是能最終正確執行的.所以,當把一段業務代碼提取流水中必需要考慮到:spa

  • 流水延遲處理性。流水不是實時處理的,而是用過流水執行器來異步執行的。所以,若是在原有邏輯中,須要特別注意後續流程對該流水是否是有實時依賴性(例如後續業務邏輯中會使用流水結果來作一些計算等)。
  • 流水處理無序性。保證即便後生成的流水先執行,也不能出現問題。
  • 流水最終成功性。對每條插入的流水,該條流水必定要保證能執行成功

所以,提取流水的時候:blog

  • 流水處理越簡單越好
  • 流失處理依賴越少越好
  • 提取的流水在該業務邏輯中無實時性依賴

微信圖片_20200704161403.jpg

2.4 流水處理完成

由於流水錶是放在原數據庫中,而流水處理完成後是操做分庫,若是分庫操做完成去更新老表流水消息,那麼又是誇庫事務,如何保證流水狀態的更新和分庫也是在一個事務的?索引

解決辦法是:在分庫中建立一個流水錶,當流失處理完成之後,不是去更新老表狀態,而是插入分庫流水錶中、隊列

這樣作的好處:圖片

  • 通常會對流水作惟一索引,那麼若是流水重複屢次執行的時候,插入分庫流水錶的時候確定因爲惟一索引檢測不經過,整個事務就會回滾(固然也能夠在處理流水事前應該再作一下冪等性判斷)
  • 這樣經過判斷主庫流水是否在分庫中就能判斷一條流水是否執行完畢

微信圖片_20200704161440.jpg

3、流水處理器基本框架

流水處理器其實不包含任何業務相關的處理邏輯,核心功能就是:

  • 通知業務接入方什麼時候處理什麼樣的流水
  • 檢驗流水執行的成功

注:流水執行器並不知道該流水錶示什麼邏輯,具體須要業務系統去識別後去執行相對應業務邏輯。
微信圖片_20200704161509.jpg

3.1 流水執行任務

流水處理調度任務就是經過掃描待處理的流水,而後通知業務系統該執行哪一條流水。

示意圖以下:
微信圖片_20200704161530.jpg

3.2 流水校驗任務

流水校驗任務就是要比較主庫和分庫中的流水記錄,對執行未成功的流水通知業務系統進行從新處理,若是屢次重試失敗則發出告警。

流程示意圖:
微信圖片_20200704161551.jpg

4、爲何不用事務消息

因爲是既有項目(互聯網金融,因此是絕對不容忍有任何消息丟失或者消息處理失敗)進行改造,不使用事務消息有1個緣由

  • 須要額外引入消息隊列,增長系統的複雜度,並且也須要額外的邏輯保證和消息隊列通信失敗的時候處理
  • 其實1不算是主要緣由,而是由於事務消息須要手動的commit和rollback(使用數據庫不須要),那麼問題來了,spring中事務是有傳遞性的,那咱們事務消息什麼時候提交又是個大問題,例如 A.a()原本就是一個事務, 可是另一個事務B.b()中又調用了A.a() 那事務消息提交是放在A.a()仍是B.b()中呢?
相關文章
相關標籤/搜索