從 SQL Server 到 MySQL (一):異構資料庫遷移
背景
滬江成立於 2001 年,作為較早期的教育學習網站, 當時技術選型範圍並不大: Java 的版本是 1.2,C# 尚未誕生,MySQL 還沒有被 Sun 收購, 版本號是 3.23。 工程師們選擇了當時最合適的微軟體系,並在日後的歲月裡, 逐步從 ASP 過度到 .net,資料庫也跟隨 SQL Server 進行版本升級。
十幾年過去了,技術社群已經發生了天翻地覆的變化。 滬江部分業務還基本在 .net 體系上,這給業務持續發展帶來了一些限制。 人才招聘、社群生態、架構優化、成本風險方面都面臨挑戰。 集團經過慎重考慮,發起了大規模的去 Windows 化專案。 這其中包含兩個重點子專案:開發語言從 C# 遷移到 Java, 資料庫從 SQL Server 遷移到 MySQL。
本系列文章就是向大家介紹, 從 SQL Server 遷移到 MySQL 所面臨的問題和我們的解決方案。
遷移方案的基本流程
設計遷移方案需要考量以下幾個指標:
- 遷移前後的資料一致性
- 業務停機時間
- 遷移專案是否對業務程式碼有侵入
- 需要提供額外的功能:表結構重構、欄位調整
經過仔細調研,在平衡複雜性和業務方需求後, 遷移方案設計為兩種:停機資料遷移和線上資料遷移。 如果業務場景允許數小時的停機,那麼使用停機遷移方案, 複雜度低,資料損失風險低。 如果業務場景不允許長時間停機,或者遷移資料量過大, 無法在幾個小時內遷移完成,那麼就需要使用線上遷移方案了。
資料庫停機遷移的流程:
停機遷移邏輯比較簡單,使用 ETL(Extract Translate Load) 工具從 Source 寫入 Target,然後進行一致性校驗,最後確認應用執行 OK, 將 Source 表名改掉進行備份。
線上遷移的流程:
遷移的方案稍微複雜一些,流程上有準備全量資料,然後實時同步增量資料, 在資料同步跟上(延遲秒級別)之後,進行短暫停機(Hang 住,確保沒有流量), 就可以使用新的應用配置,並使用新的資料庫。
需要解決的問題
從 SQL Server 遷移到 MySQL,核心是完成異構資料庫的遷移。
基於兩種資料遷移方案,我們需要解決以下問題:
- 兩個資料庫的資料結構是否可以一一對應?出現不一致如何處理?
- MySQL 的使用方式和 SQL Server 使用方式是否一致?有哪些地方需要注意?
- 如何確保遷移前後的資料一致性?
- 在遷移中,如何支援資料結構調整?
- 如何保證業務不停情況下面,實現線上遷移?
- 資料遷移後如果發現業務異常需要回滾,如何處理新產生的資料?
為了解決以上的問題,我們需要引入一整套解決方案,包含以下部分:
- 指導文件 A:SQL Server 轉換 MySQL 的資料型別對應表
- 指導文件 B:MySQL 的使用方式以及注意點
- 支援表結構變更,從 SQL Server 到 MySQL 的 ETL 工具
- 支援 SQL Server 到 MySQL 的線上 ETL 工具
- 一致性校驗工具
- 一個回滾工具
讓我們一一來解決這些問題。
SQL Server 到 MySQL 指導文件
非常幸運的是,MySQL 官方早就準備了一份如何其他資料庫遷移到 MySQL 的白皮書。MySQL :: Guide to Migrating from Microsoft SQL Server to MySQL 裡提供了詳盡的 SQL Server 到 MySQL 的對應方案。 包含了:
- SQL Server to MySQL – Datatypes 資料型別對應表
- SQL Server to MySQL – Predicates 邏輯運算元對應表
- SQL Server to MySQL – Operators and Date Functions 函式對應表
- T-SQL Conversion Suggestions 儲存過程轉換建議
需要額外處理的資料型別:
在實際進行中,還額外遇到了一個用來解決樹形結構儲存的欄位型別 Hierarchyid。這個場景需要額外進行業務調整。
我們在內部做了針對 MySQL 知識的摸底排查工作, 並進行了若干次的 MySQL 使用技巧培訓, 將工程師對 MySQL 的認知拉到一根統一的線。
關於儲存過程使用,我們和業務方也達成了一致:所有 SQL Server 儲存過程使用業務程式碼進行重構,不能在 MySQL 中使用儲存過程。 原因是儲存過程增加了業務和 DB 的耦合,會讓維護成本變得極高。 另外 MySQL 的儲存過程功能和效能都較弱,無法大規模使用。
最後我們提供了一個 MySQL 開發規範文件,借資料庫遷移的機會, 將之前相對混亂的表結構設計做了統一了約束(部分有業務繫結的設計, 在考慮成本之後沒有做調整)。
ETL 工具
ETL 的全稱是 Extract Translate Load(讀取、轉換、載入), 資料庫遷移最核心過程就是 ETL 過程。 如果將 ETL 過程簡化,去掉 Translate 過程, 就退化為一個簡單的資料匯入匯出工具。 我們可以先看一下市面上常見的匯入匯出工具, 瞭解他們的原理和特性,方便我們選型。
MySQL 同構資料庫資料遷移工具:
- mysqldump 和 mysqlimport MySQL 官方提供的 SQL 匯出匯出工具
- pt-table-sync Percona 提供的主從同步工具
- XtraBackup Percona 提供的備份工具
異構資料庫遷移工具:
- Database migration and synchronization tools: :國外一家提供資料庫遷移解決方案的公司
- DataX :阿里巴巴開發的資料庫同步工具
- yugong :阿里巴巴開發的資料庫遷移工具
- MySQL Workbench :MySQL 提供的 GUI 管理工具,包含資料庫遷移功能
- Data Integration – Kettle :國外的一款 GUI ETL 工具
- Ispirer :提供應用程式、資料庫異構遷移方案的公司
- DB2DB 資料庫轉換工具 : :一個國產的商業資料庫遷移軟體
- Navicat Premium :經典的資料庫管理工具,帶資料遷移功能
- DBImport :個人維護的遷移工具,非常簡陋,需要付費
看上去異構資料庫遷移工具和方案很多,但是經過我們調研,其中不少是為老派的傳統行業服務的。 比如 Kettle / Ispirerer,他們關注的特性,不能滿足網際網路公司對效能、遷移耗時的要求。 簡單篩選後,以下幾個工具進入我們候選列表(為了做特性對比,加入幾個同構資料庫遷移工具):
由於異構資料庫遷移,真正能夠進入我們選型的只有 DataX / yugong / DB2DB / MySQL Workbench。 經過綜合考慮,我們最終選用了三種方案, DB2DB 提供小資料量、簡單模式的停機模式支援, 足以應付小資料量的停機遷移,開發工程師可以自助完成。 DataX 為大資料量的停機模式提供服務, 使用 JSON 進行配置,通過修改查詢 SQL,可以完成一部分結構調整工程。 yugong 的強大可定製性也為線上遷移提供了基礎, 我們在官方開源版本的基礎之上,增加了以下額外功能:
- 支援 SQL Server 作為 Source 和 Target
- 支援 MySQL 作為 Source
- 支援 SQL Server 增量更新
- 支援使用 YAML 作為配置格式
- 調整 yugong 為 fat jar 模式執行
- 支援表名、欄位名大小寫格式變化,駝峰和下劃線自由轉換
- 支援表名、欄位名細粒度自定義
- 支援複合主鍵遷移
- 支援遷移過程中完成 Range / Time / Mod / Hash 分表
- 支援新增、刪除欄位
關於 yugong 的二次開發,我們也積累了一些經驗,這個我們下篇文章會來分享。
一致性校驗工具
在 ETL 之後,需要有一個流程來確認資料遷移前後是否一致。 雖然理論上不會有差異,但是如果中間有程式異常, 或者資料庫在遷移過程中發生操作,資料就會不一致。
業界有沒有類似的工具呢? 有,Percona 提供了 pt-table-checksum 這樣的工具, 這個工具設計從 master 使用 checksum
來和 slave 進行資料對比。 這個設計場景是為 MySQL 主從同步設計, 顯然無法完成從 SQL Server 到 MySQL 的一致性校驗。 儘管如此,它的一些技術設計特性也值得參考:
- 一次檢查一張表
- 每次檢查表,將表資料拆分為多個 trunk 進行檢查
- 使用
REPLACE...SELECT
查詢,避免大表查詢的長時間帶來的不一致性 - 每個 trunk 的查詢預期時間是 0.5s
- 動態調整 trunk 大小,使用指數級增長控制大小
- 查詢超時時間 1s / 併發量 25
- 支援故障後斷點恢復
- 在資料庫內部維護 src / diff,meta 資訊
- 通過 Master 提供的資訊自動連線上 slave
- 必須 Schema 結構一致
我們選擇 yugong 作為 ETL 工具的一大原因也是因為它提供了多種模式。 支援 CHECK / FULL / INC / AUTO 四種模式。 其中 CHECK 模式就是將 yugong 作為資料一致性檢查工具使用。 yugong 工作原理是通過 JDBC 根據主鍵範圍變化,將資料取出進行批量對比。
這個模式會遇到一點點小問題,如果資料庫表沒有主鍵,將無法進行順序對比。 其實不同資料庫有自己的邏輯主鍵,Oracle 有 rowid
, SQL Server 有 physloc
。這種方案可以解決無主鍵進行比對的問題。
如何回滾
我們需要考慮一個場景,在資料庫遷移成功之後業務已經運行了幾個小時, 但是遇到了一些 Critical 級別的問題,必須回滾到遷移之前狀態。 這時候如何保證這段時間內的資料更新到老的資料庫裡面去?
最樸素的做法是,在業務層面植入 DAO 層的打點, 將 SQL 操作記錄下來到老資料庫進行重放。 這種方式雖然直觀,但是要侵入業務系統,直接被我們否決了。 其實這種方式是 binlog statement based 模式, 理論上我們可以直接從 MySQL 的 binlog 裡面獲取資料變更記錄。 以 row based 方式重放到 SQL Server。
這時候又涉及到逆向 ETL 過程, 因為很可能 Translate 過程中,做了表結構重構。 我們的解決方法是,使用 Canal 對 MySQL binlog 進行解析, 然後將解析之後的資料作為資料來源, 將其中的變更重放到 SQL Server。
由於回滾的過程也是 ETL,基於 yugong, 我們繼續定製了 SQL Server 的寫入功能, 這個模式類似於線上遷移,只不過方向是從 MySQL 到 SQL Server。
其他實踐
我們在遷移之前做了大量壓測工作, 並針對每個遷移的 DB 進行線上環境一致的全真演練。 我們構建了和生產環境機器配置一樣, 資料量一樣的測試環境,並要求每個系統在上線之前都進行若干次演練。 演練之前準備詳盡的操作手冊和事故處理方案。 演練準出的標準是:能夠在單次演練中不出任何意外,時間在估計範圍內。 通過演練我們保證了整個操作時間可控,減少操作時候的風險。
為了讓資料庫的狀態更為直觀的展現出來, 我們對 MySQL / SQL Server 添加了細緻的 Metrics 監控。 在測試和遷移過程中,可以便利地看到資料庫的響應情況。
為了方便 DBA 快速 Review SQL。 我們提供了一些工具,直接將程式碼庫中的 SQL 拎出來, 可以方便地進行 SQL Review。 再配合其他 SQL Review 工具, 比如 Meituan-Dianping/SQLAdvisor, 可以實現一部分自動化,提高 DBA 效率,避免線上出現明顯的 Slow SQL。
最後
基於這幾種方案我們打了一套組合拳。經過將近一年的使用, 進行了 28 個通宵,遷移了 42 個系統, 完成了包括使用者、訂單、支付、電商、學習、社群、內容和工具的遷移。 遷移的資料總規模接近百億,所有遷移專案均一次成功。 遷移過程中積累了豐富的實戰經驗,保障了業務快速向前發展。