最近才考慮數據庫遷移,想起了之前做DTS踩過的那些坑。
DTS同步binlog,開始是使用binlog event + position方式,之后追加支持了GTID。
基於數據庫遷移,比如從源A庫遷移到源B庫,包括但不限於數據庫上雲。
數據庫遷移方案有兩種場景:
(1)、停機遷移方案【停服時間比較長】
這種方案是允許停服的場景,通過mysqldump就搞定了,就不說了。
(2)、在線不停機方案【最多只是切庫的時間點,停服重部服務一下,停服時間很短。若不停服,就得想辦法處理切為時間點的新產生的BINLOG】
這種場景方案中,我們采用先在線整庫遷移,然后在通過binlog在線DTS對齊數據。
步驟如下:
1、源數據庫采用ROW模式,開啟binlog權限
2、需要一個源庫的全局schema查詢用戶,獲取源數據庫的schema同步到目標庫
3、選取某個時間點的BINLOG OFFSET做標記,然后通過JDBC同步整個庫表數據到目標庫,直至完畢。
4、通過netty服務單線程讀取源庫BINLOG數據,從上一步標記的offset位置開始讀取,讀入kafka。
5、多線程消費kafka數據到目標庫,直至同步到最新的binlog數據,遷移完成。
第二種方案中遇到的那些坑:
1、最好選取源庫的一個只讀庫做為同步數據的源庫,這樣不影響源庫線上業務。另外開始同步整庫時,需要選取當前Offset位置以備增量同步時使用,並且整庫同步期間禁止寫入或至少禁止修改schema操作(減少后面增量同步binlog時的程序報錯,及異常表手動處理的成本)。
2、多線程消費kafka時,容易出現binlog順序錯亂的問題,目前采用按表寫partition的方式,指定partitions消費,避免順序錯亂,但帶來的新問題就是kafka的各partitions數據傾斜問題。
3、目前解析binlog同步數據時,DDL和DML操作沒有特殊分別處理,如果數據量比較 大時,DDL很容易超時,導致此DDL之后同步的binlog都有問題,需要重新同步
4、同步binlog時,指定時間窗口大小,記錄同步時的binlog位置到zk上,如果需要重新同步數據,可能會導致一部分binlog重復同步。如果窗口過小,zk也扛不住
5、遇到沒有主鍵或唯一性限制的表,重復同步,會導致數據重復
6、若遇到同步blob相關類型時,若二進制數據過大,可能導致同步失敗
7、同步服務的部署問題,源庫和目標庫都需要開公網IP。
8、同步服務的效率和源庫、目標庫的網絡帶寬,數據庫配置息息相關
9、由於業務在正常的運轉的,需要找個時間點校驗數據的完整性,在業務流量低時,手動停止同步,線上服務切到新庫,(這樣需要處理切庫時的binlog,最好短時停服切庫)
10、一旦開始同步,在手動停止同步之前,不能修改DDL,否則會導致同步任務失敗
11、存儲過程及視圖不會同步,需要切庫后,手動處理
備注:
1、 GTID最初由google實現,MySQL 從5.6.5 新增了基於 GTID 的復制方式。通過 GTID 保證了每個在主庫上提交的事務在集群中有一個唯一的ID。這種方式強化了數據庫的主備一致性,故障恢復以及容錯能力。GTID (Global Transaction ID)是全局事務ID,當在主庫上提交事務或者被從庫應用時,可以定位和追蹤每一個事務。
2、查看當前的Binlog最終偏移量方法
## 獲取binlog文件列表,找到最新的binlog文件
mysql> show binary logs;
mysql> show binlog events in 'binlog.0000MAX'; ##查來下面的End_log_pos,就是最新的binlog偏移量了
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info