概述
為了保證系統的穩定性,最近在核心庫與非核心庫的隔離,在做的過程需要調整數據庫的部署,涉及到數據庫的遷移,本文是來自在內部分享截取。
數據庫遷移
如下圖假設service調用db1,現在需要將db1遷移到db2,遷移完成之后service將調用db2。總體來說遷移數據庫步驟如下:
- 修改應用的數據庫鏈接字符串
- 將原來的數據庫中數據遷移至新的數據庫
- 發布應用啟用鏈接新的數據庫
- 通知下游系統,使用新的鏈接
總來來說遷移數據庫遷移步驟還算明確的,但是這4步中有個關鍵的一步,就是第3步,何時啟用新的數據庫鏈接直接關系到數據一致性。
按照上面的步驟遷移,要思考的一個問題就是如何判斷數據是否遷移完成。假設service時時刻刻在調用db1進行寫操作,那么就是說數據同步一直在進行永遠不會完成。如何解決呢?
- 如果不等數據遷移同步完,遷移到接近完成就開始將service和db1的鏈接斷掉,將請求打到db2,這樣沒有數據進到db1,db1數據總會全部同步到db2的。這樣不就行了嗎?這樣的問題是啥呢?這樣的會造成數據不一致,舉個例子,比如有條記錄insert操作在斷掉鏈接1之前,insert完成之后,馬上斷掉了鏈接1啟用了鏈接2,此時對這條記錄有update操作,如果同步任務還沒有將這條記錄同步到db2,那么update是失敗的,造成數據不一致。
- 鑒於上面會造成數據不一致,那么如果采用雙寫模式模式呢,即不斷開鏈接1,啟用鏈接2,往兩個數據庫寫,db1一定是完成的數據,跑上一段時間如果db2有數據不一致記錄,那么用db1的記錄去覆蓋db2的記錄,看起來似乎是可行,但是如何判斷db2的數據不一致呢?這樣理論上是可行,但是操作上難度系數太高。那么有沒有更簡單的方式呢。
- 既然要數據一致,為何不在遷移之前就保證數據是一致的呢,但是前面又說了數據是源源不斷寫到db1,無法確定哪一刻db1和db2的數據是一致的。這樣可以把service寫db1的鏈接斷掉,等待db1和db2數據完成之后在啟用db2.這樣數據就是一致的了。縮短db1斷開到db2啟用的時間段,在流量低峰操作,在c端透出友好提示,這樣最少限度的影響客戶的使用又能做到簡單的數據庫遷移替換。
基於3的思路,如何縮短db1斷開到db2啟用的時間段呢?可以從如下角度考慮。
- ,提前全量同步db1的數據到db2.全量同步完成之后,開啟增量同步, 在流量低峰,db1寫入的數據不多。那么db2與db1的偏移量很低,如果停掉db1寫操作,那么db1和db2的數據很快能保持一致。
- 快速切換。快速斷開db1,同時也能快速啟用db2,那么發應用顯得慢,要做動態開關。
做到上面兩點基本上就能將db1斷開到db2啟用的時間段縮的很短可以做到分鍾級別,甚至秒級別的。
如何切斷原數據源
這個問題要具體業務具體分析,C端用戶訪問功能,就要從接口層面先臨時短暫做降級通過sentinel配置接口訪問0,給用戶友好的提示,等數據遷移完成快速切換數據源並放開並放開接口層面的限制,由此用戶端短暫不可用,所以此類數據庫一定要挑選深夜用戶訪問量少的情況發布,減少對業務的影響。
如何動態切換數據源
目前我們的項目都是通過mybatis框架來訪問和操作數據庫,我們知道程序通過配置 SqlSessionTemplate 使用SqlSessionTemplate來訪問底層的datasource來訪問和操作數據庫的,那么可以采用如下思路:
- 繼承SqlSessionTemplate 並重寫 這里記DynamicSqlSessionTemplate
- 往DynamicSqlSessionTemplate注入多個數據源,通過apollo配置可以動態選擇使用哪個datasource來操作數據庫。
- 原來是配置的SqlSessionTemplate現在改成配置DynamicSqlSessionTemplate,程序最后使用的DynamicSqlSessionTemplate重寫的方法,可以動態調整數據源。
具體的可以參考: https://www.cnblogs.com/xifengxiaoma/p/9888240.html
數據同步-阿里雲DTS
阿里雲數據同步和數據遷移的一個工具,可以做數據的全量與增量同步
數據庫遷移參考文檔https://help.aliyun.com/document_detail/26598.html?spm=a2c4g.11186623.6.550.d6d17695FP1q32