數據遷移案例分析git
文章地址: blog.piaoruiqing.com/blog/2019/1…github
數據遷移時, 爲了保證數據的一致性, 每每伴隨着停服, 此期間沒法給用戶提供服務或只能提供部分服務. 同時, 爲了確保遷移後業務及數據的正確性, 遷移後測試工做也要佔用很多時間. 如此形成的損失是比較大的.算法
接下來, 本文將就如何在不停服的狀況下進行數據遷移進行探討.數據庫
訂單系統中存在這樣一組訂單表:post
數據庫: MySQL性能
表名: order_{0~19}, 其中{0~19}爲後綴, 合共20張表.測試
主鍵: order_id, 訂單ID, 經過雪花算法得到, 可經過ID獲取建立時間.ui
原分表策略: order_id % 20編碼
伴隨着業務量增加, 各分表的數據量已經破千萬, 如此下去會產生嚴重的性能問題, 此時須要將原分表進行遷移.設計
要求:
有過度庫分表經驗的讀者可能已經發現案例中原分表策略十分不合理, 其原因不去追究(畢竟換了幾波人以後已經沒辦法找到當年的人吊起來揍了).
分析一下原數據表: 訂單數據確定會伴隨着時間和業務量直線上升, 固定的分表數量會致使隨數據量增大性能降低. 因此, 數據遷移後, 分表的數量不能再固定, 即便從20改爲100個總有一天也會達到瓶頸.
訂單數據會伴隨時間增加, 並且在超過退款期限後就變成了冷數據, 使用率會下降. 所以, 將訂單按照建立時間來進行分表是一個不錯的選擇. 值得一提的是, order_id是經過雪花算法得到, 能夠從order_id中獲取建立時間, 能夠經過order_id直接獲取分片鍵.
數據遷移的方案從業務層到數據庫層各有不一樣的遷移方案, 咱們先列舉一些進行比對:
業務層: 在業務層進行硬編碼, 數據雙寫, 以某個時間點進行劃分, 新產生的數據同時寫入新表, 運行一段時間後將舊數據遷移至新表. 成本極高, 與業務耦合嚴重, 不考慮.
鏈接層: 是方案1的進階版, 在鏈接層攔截SQL進行雙寫, 與業務解耦, 但與1有着一樣的一個問題: 週期較長, 要確保舊數據不會產生變動才能進行遷移.
觸發器: 經過觸發器將新產生的數據同步到新表, 本質上與2差很少.
數據庫日誌: 從某一時間點T備份數據庫, 將備份庫的數據遷移至新表, 從時間點T讀取日誌, 恢復到新表, 並持續寫入. 待兩份數據保持同步後, 上線新代碼.
假裝從庫: 相對於方案4的優點是不須要直接去讀取日誌, 解決了數據庫在雲上不方便直接讀取日誌的問題.
相比較之下, 方案4和5都是可選的, 因數據庫在雲上, 直接讀取日誌不方便, 且方案5有成熟的開源中間件**canal**可用, 故筆者選擇了方案5.
Canal文檔地址: github.com/alibaba/can…
新代碼上線後, 誰也不能確保百分百沒問題. 若遷移失敗, 必需要進行回滾. 因此, 須要保證原數據和新數據的同步.
因此, 在前一小節方案5的基礎上, 切流量到新集羣后, 咱們中止數據同步, 從切流量時刻開始同步新表數據到舊錶, 方案也是假裝從庫. 如此就能保證新舊錶的數據同步, 若是上線後發生了異常, 將流量切回舊集羣便可.
flush logs
: 生成新的binlog, 恢復數據將從這裏開始.flush logs
生成新的binlog, 新表向舊錶同步數據將從這裏開始.上線後應及時進行測試, 一旦發現嚴重的異常就當即將流量切回舊集羣.
flash logs
要先於備份源數據表, 即便中間有些許時間間隔也不會影響數據的最終一致 (聽binlog的總沒錯).若是這篇文章對您有幫助,請點個贊吧 ( ̄▽ ̄)"
歡迎關注公衆號(代碼如詩):