攜程海外 MySQL 數據複製實踐
作者簡介
Roy,攜程軟件技術專家,負責 MySQL 雙向同步 DRC 和數據庫訪問中間件 DAL 的開發演進,對分佈式系統高可用設計、分佈式存儲,數據一致性領域感興趣。
一、前言
在攜程國際化戰略背景下,海外業務將成爲新的發力點,爲了保證用戶高品質的服務體驗,底層數據勢必需要就近服務業務應用。一套標準且普適的數據複製解決方案能夠提升業務決策效率,助力業務更快地觸達目標用戶。
DRC (Data Replicate Center) 作爲攜程內部數據庫上雲標準解決方案,支撐了包括但不限於即時通訊、用戶賬號、IBU 在內的核心基礎服務和國際業務順利上雲。
二、業務上雲場景
業務上雲前,要先要思考 2 個問題:
-
數據庫是否需要上雲?
-
在數據庫上雲情況下,海外數據庫提供只讀還是讀寫操作?
2.1 應用上雲
針對用戶延遲不敏感或者離線業務,可以採用只應用上雲數據庫不上雲,請求回源國內。該方案下業務需要改造應用中讀寫數據庫操作,根據應用部署地,決定流量是否需要轉發。
不建議海外應用直連國內數據庫,網絡層面專線距離遠,成本太高,不現實;安全層面應禁止跨海訪問,否則可能導致預期就近訪問流量由於非預期錯誤,將海外流量寫入國內數據庫,從而引起國內數據錯誤。
2.2 數據庫上雲
對於在線用戶延遲敏感應用,數據庫必須跟隨應用一同上雲,將請求閉環在海外,從而就近提供服務響應。在確定數據庫上雲的前提下,根據不同業務特點,可再細分爲海外只讀和讀寫兩種場景。
只讀場景
對於海外只讀場景,國內數據只需要單向複製,該方案下業務海外賬號默認無寫權限或者業務改造寫操作,避免出現由於誤寫導致國內海外數據不一致。
讀寫場景
對於海外讀寫場景,國內海外數據需要雙向複製,業務代碼無需改造。該方案下由於有 2 個 Master 可以寫入,業務需要在應用層對流量進行切分,比如用戶歸屬地維度,從而避免在兩側同時修改同一條數據,進而導致複製過程出現數據衝突。
2.3 上雲成本
數據距離用戶越近,應用直接提供的服務功能越豐富,對應業務改造量越小,機器資源消耗量越大。攜程海外應用部署在 AWS 公有云上,AWS 入口流量不計費,只針對出口流量計費。應用上雲數據庫不上雲場景,請求回源國內產生出口流量費用;只讀業務單方向數據複製流入,不收費;讀寫業務數據複製回國內產生出口流量費用。
上雲成本主要集中在流量和數據庫費用。AWS 出口 Internet 流量 0.09$/GB,當流量大時,可通過數據壓縮,損耗複製延遲降低出口流量;RDS 根據核數計費,1004 元 / 核 / 月,業務流量少時採用普通 4C16G 機型即可,流量增加後動態提升配置。核心業務 RDS 配置一主一從,非核心業務單主即可,並且多個 DB 可共用一個集羣,進而降低成本。
2.4 小結
爲了提供高品質的用戶體驗,數據勢必需要上雲。在解決了是否上雲的問題後,如何上雲就成爲新的疑問點。下面就詳細分析攜程內部上雲過程中依賴的數據庫複製組件 DRC 實現細節。
三、數據庫上雲方案
DRC 基於開源模式開發,公司內部生產版本和開源保持一致,開源地址 https://github.com/ctripcorp/drc,歡迎關注。
DRC 孵化於異地多活項目,參見《攜程異地多活 - MySQL 實時雙向(多向)複製實踐》,解決國內異地機房間數據庫同步問題。當其中一個或多個機房位置轉變爲公有云時,伴隨着物理距離的擴大,新的問題應運而生。
就 DRC 自身架構實現而言:
-
公有云和國內機房間互不聯通,同步鏈路被物理阻斷
-
公網傳輸不如國內跨機房之間專線質量,丟包頻發
-
公有云數據庫自主運維靈活性下降,如無法獲取 root 權限,直接導致 set gtid_next 無法正常工作
就業務接入而言:
-
國內海外數據隔離,按需複製成爲剛需
-
公有云數據庫成本壓力導致混部,一對一複製不再滿足業務靈活多變的真實部署場景
基於以上限制,DRC 調整架構,引入代理模塊解決網絡聯通性問題,借用事務表降低複製鏈路對權限的要求;爲了適應業務的多樣性,分別從庫、表和行維度支持按需複製。
3.1 架構改造挑戰
1)架構升級
DRC 中有 2 個核心功能需要跨公網傳輸數據:
-
業務 Binlog 數據複製
-
DRC 內部延遲監控探針
數據複製
以單向複製爲例,在 Binlog 拉取模塊 Replicator 和解析應用模塊 Applier 之間引入 Proxy,負責在 TCP 層將內網 / 公網流量轉發到公網 / 內網。Proxy 綁定公網 IP,採用 TLS 協議加密傳輸內網流量。鑑於公網質量不穩定特性,Proxy 使用 BBR 擁塞控制算法,優化丟包引起的卡頓。
Proxy 作爲公網數據傳輸攜程內部統一的解決方案,參見《攜程 Redis 海外機房數據同步實踐》,開源地址:https://github.com/ctripcorp/x-pipe,歡迎關注。
延遲監控
延遲監控探針從業務流量同側機房的 Console 寫入到業務數據庫延遲監控表 (初始化時新建),經過雙向複製鏈路,從異側機房接收延遲探針,從而計算差值得到複製延遲。爲了提升 Proxy 間隔離性,數據複製和延遲監控可以分別配置不同的 Proxy 實例實現數據傳輸。
Proxy Client
由於 Applier 和 Console 都需要對接 Proxy,如何降低 Proxy 對 DRC 系統的侵入性就成爲一個需要解決的問題。爲此我們藉助 Java Agent 技術,動態修改字節碼,實現了可插拔的接入方式。接入方只需要引入 proxy-client 獨立 Jar 包,業務層按需實現 Proxy 的註冊和註銷。
2)網絡優化
公網網絡丟包和擁塞頻發,爲了在弱網環境下實現平穩複製,就需要快速地異常檢測恢復機制。除了在系統層將 Proxy 擁塞控制算法優化爲 BBR 外,DRC 在應用層額外增加:
-
心跳檢測,實現連接自動切換
-
流量控制,避免突增流量引起資源耗盡進而影響數據複製
-
2 條互備海外出口運營商線路,隨機切換
心跳檢測
Binlog 生產方 Replicator 定時對下游消費方進行心跳檢測,消費方接收到心跳檢測需回覆響應,Replicator 根據最後一次接收時間檢測並自動關閉長期沒有響應的連接。
這裏有一種場景需要特別處理,當下遊消費方比較忙,主動關閉連接 auto_read 屬性時,由於應用層無法讀取暫存在緩衝區的心跳包,從而造成無法響應。這就需要消費方在 auto_read 改變時,主動上報生產方自身的 auto_read 狀態。
流量控制
公網網絡質量下降導致複製延遲變大,數據堆積在發送端 Proxy,進而引起 Replicator 和 Proxy 觸發流控;MySQL 性能抖動,應用 Binlog 速度減緩,數據堆積在 Applier,進而引起 Applier 觸發流控並逐層反饋到 Replicator。
運營商線路
針對 Proxy 出口 IP,分別配置移動和聯通兩條運營商線路,當 Binlog 消費方由於觸發空閒檢測出現超時重連時,Proxy 會隨機選擇一個運營商出口 IP,從而實現運營商線路的互備。
3)事務表複製
國內機房間數據複製時,DBA 可以給予 DRC 擁有 root 權限的賬號,以實現 Applier 模擬原生 Slave 節點 set gtid_next 工作方式應用 Binlog,從而將一個事務變更從源機房複製到目標機房,並且在兩端分配到同一個 gtid 下。但是公有云上 RDS 出於安全原因是無法開放 root 權限,直接從原理上否定了原有的複製方案。
爲了找到合理的替換方案,我們首先從 MySQL 服務端視角分析下 set gtid_next 的效果:
-
事務在提交後會被分配指定的 gtid 值,否則 MySQL 服務端會自動分配一個 gtid 值
-
gtid 值加入 MySQL 服務端全局變量 gtid_executed 中
其根本性作用在於將 DRC 指定的 gtid 值保存到 MySQL 系統變量。既然無法利用 MySQL 系統變量,那麼從業務層增加一個複製變量保存 gtid 信息即可實現同等效果。
其次,轉換到 DRC 複製視角,set gtid_next 起到如下作用:
-
記錄 Applier 複製消費位點,並以此向 Replicator 請求 Binlog
-
解決循環複製,Replicator 根據 gtid_event 中的 uuid 判斷是否是 DRC 複製產生的事件
綜上分析,新的替代方案需要引入持久化變量,記錄複製位點並且能夠提供循環阻斷信息功效,爲此 DRC 引入基於事務表的同步方案解決了海外複製難題。
位點記錄
海外複製業務集羣需要新增複製庫 drcmonitordb,其中新建事務表 gtid_executed。
CREATE TABLE `drcmonitordb`.`gtid_executed` (
`id` int(11) NOT NULL,
`server_uuid` char(36) NOT NULL,
`gno` bigint(20) NOT NULL,
`gtidset` longtext,
PRIMARY KEY (`id`,`server_uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
server_uuid:源端數據庫 UUID 號
-
gno:事務 id。該列值爲 0 的行爲彙總行
-
gtidset:對於 gno=0 的彙總行,該列批量存儲 gno 編號,例如 server_uuid:1-10:20:30
當 Applier 應用 SQL 到目標數據庫前,需要先更新事務表,記錄 gtid,然後再執行事務中變更語句,完整的複製流程如下圖所示。事務表中 gno=0 行中 gtidset 等效 MySQL 系統變量 gtid_executed,Applier 執行過程中定時彙總非 0 行事務 gno,從而達到記錄位點功能。
循環阻斷
針對 Binlog 中第一個寫事件是事務表 gtid_executed 操作的事務,Replicator 將其判斷爲 DRC 複製數據,從而阻斷循環複製,否則一條數據會在雙向複製環內無限死循環。
3.2 業務落地挑戰
至此 DRC 解決了理論上阻礙複製的已知技術問題,在實際業務落地過程中,出於數據安全、費用和改造成本的考慮,業務對數據複製提出了更精細化控制的需求。
1)數據隔離
出於合規的要求,業務上雲後,需要完成國內和海外用戶數據的隔離。業務上雲前,國內和海外用戶數據全部在國內數據庫;上雲時就需要將海外用戶數據單獨複製到公有云而過濾掉國內用戶數據。
庫表映射
上雲前國內和海外數據在同一張母表。爲了上雲,業務通過在國內數據庫新增子表,實現國內數據的分離。海外由於只存在海外數據,所以物理上只需要一張母表即可,即國內子表與海外母表相對應,搭建 DRC 實現雙向複製即可。由於母表和子表表名不同,複製時需要做庫表映射,從而屏蔽應用層對不同表名的感知,降低業務改造量。
行過濾
庫表映射不涉及數據過濾,經過 DRC 的流量都會進行復制,因此映射在 Applier 端處理,直接根據映射規則替換表名即可。爲此業務需要進行 2 處改造:
-
人工分離國內機房國內和海外數據
-
爲了使國內母表保存全量數據,海外用戶數據經過 DRC 複製回國內時,需要通過觸發器自動同步到母表
爲了進一步降低業務改造量,DRC 提供行過濾功能,用戶無需進行業務改造,只需保證表中包含 Uid 字段即可,DRC 根據 Uid 自動判斷數據歸屬地,進行數據過濾。
單向複製鏈路級別添加行過濾配置,其中包括:
- 過濾類型
(1)Uid 過濾,業務層面一般通過 Uid 維度進行拆分,通過 SPI 動態加載 Uid 過濾實現,攜程內部由於 Uid 無特殊標記,無法通過 Uid 名稱判斷出歸屬地,只能通過 SOA 遠程調用實時判斷 Uid 歸屬地獲得過濾結果;如果 Uid 有規則可循,則可以通過正則表達式匹配即可
(2)Java 正則表達式,支持針對單字段的 Java 正則表達式簡單匹配計算,適合單一維度數值有規則的業務場景
(3)Aviator 表達式,支持針對多字段的 Aviator 表達式複雜匹配計算,適合多維度數值相關聯的業務場景
- 過濾參數
包含表到過濾字段的映射關係,以及與過濾類型對應的上下文,比如正則表達式。
Applier Binlog 請求中攜帶行過濾配置,Replicator 根據過濾類型加載對應的過濾規則,從而計算出過濾結果。
行過濾在發送端 Replicator 實現,這樣實現的好處是跨海發送數據量大大降低,但同時也帶來了解析和重構 Rows Event 的複雜性和性能損耗,即先解析 Rows Event 並根據過濾後的行數據生成新的 Rows Event。Rows Event 的解析需要表結構信息,而表結構信息是保存在 Binlog 的頭中,勢必在 Rows Event 前保證能夠獲得對應的表結構;解析後就可以將每行過濾字段值應用到過濾規則上,若匹配出需要過濾的行,則需要根據過濾後的行構造新的 Rows Event 併發送,否則直接發送即可。
2)數據庫混部
核心業務隨着數據量的膨脹,會採用分庫來降低數據庫壓力,在公有云部署時,鑑於雲上初始流量不多,並且可動態提升機器配置,DBA 部署時會將所有分庫部署在同一個 RDS 集羣,此時複製從一對一變成一對多。
表過濾
單向複製鏈路級別添加庫表過濾配置,支持 Aviator 表達式。Replicator 發送前,通過將從 Binlog 中解析的庫表名作用於 Aviator 表達式從而得到過濾結果。
3.3 數據庫上雲流程
完整的業務上雲流程一般分爲四步:
-
數據庫先上雲,搭建國內海外數據庫複製,驗證海外數據可用性和完整性
-
在海外數據可用的前提下,應用上雲,就近訪問海外數據庫,驗證部署海外應用可行性
-
流量路由層灰度業務流量,可根據 Uid 白名單、流量百分比在流量接入層進行灰度,驗證業務邏輯正確性
-
灰度完成,國內和海外流量完成切分,驗證國內和海外業務隔離性,爲此後下線底層數據複製做準備
數據庫上雲在每一步都有所涉及,第一步通過 DRC 解決了數據的可用性問題,第二步通過數據庫訪問中間件解決了數據可達性問題,第三步業務通過流量準確切分保證數據一致性問題,第四步國內海外實現數據隔離後,即可下線 DRC 數據複製。在分析完 DRC 原理後,下面再分析下其他幾步數據庫相關問題。
1)數據訪問層
Dal 包含中心化配置管理服務端 Dal Cluster 和 Dal 客戶端兩部分。上雲前同一個數據庫物理上只有一個集羣,上雲後海外增加相同集羣,服務端 Dal Cluster 就需要根據客戶端環境下發正確的 MySQL 配置文件。
Dal Cluster 原理
Dal Cluster 變更推送功能借由分佈式配置中心完成,配置中心提供子環境功能,國內數據庫配置默認放在父環境,海外數據庫則會在上線流程中生成對應的子環境數據庫配置。這樣在 Dal Client 啓動時,帶有不同環境配置的客戶端會拉取到不同的配置,從而實現數據庫的就近訪問,整個過程對業務透明,代碼無需改造。
2)流量切分
業務上雲一般採用 Uid 歸屬地進行流量切分,當流量開始灰度後,兩端數據庫都開始接收寫流量。如果流量灰度不乾淨,針對同一個 Uid 數據在兩端同時被修改,則會導致底層 DRC 數據複製時出現數據衝突。
當衝突發生時,Applier 默認根據時間戳進行衝突策處理,接入 DRC 的表都有一個精確到毫秒自動更新的時間戳,時間戳最新的數據會被採用,從而實現數據的一致。
3)表結構變更
通過 DRC 複製的集羣,在表結構變更流程中,會自動關聯到公有云集羣,在兩端同時進行變更操作。
由於變更完成時間有先後,假設一個增加字段的變更海外先完成,在國內完成變更前的時間範圍內,針對該表海外到國內的複製將出現複製衝突,默認 DRC 會捕獲該異常,並從異常信息中提取出列名,將多出的列從 SQL 中移除後再執行,從而自動處理掉衝突。
當國內集羣完成表結構變更後,新增列的值在兩端都爲默認值,數據仍然一致。
3.4 業務落地成果
-
海外數據庫複製從 2021 年 11 月上線至今,接入公司 90 + 複製集羣;
-
上海↔新加坡 AWS 複製平均延遲 90ms,上海↔法蘭克福 AWS 複製平均延遲 260ms;
-
賬號集羣通過庫表映射,常旅、收藏等通過行過濾實現用戶數據隔離;
-
通過一對多部署,公有云 / 國內機房 MySQL 集羣比維持在 1/5,DRC 複製成本 / MySQL 集羣成本維持在 2/5;
四、未來規劃
-
爲了支持更多 Binlog 消費方,支持消息投遞;
-
DRC 當前只支持增量數據的實時複製,後續會支持存量數據的複製以及敏感數據的初始化過濾,覆蓋業務上雲過程中更多數據複製場景;
-
Replicator 作爲有狀態實例,使用本地磁盤保存 Binlog,公有云使用的塊存儲本身即是分佈式存儲系統,Replicator 可探究存儲架構改造,實現主備共用同一份存儲,從而降低使用成本。
DRC 開源地址:
https://github.com/ctripcorp/drc
“攜程技術”公衆號
分享,交流,成長
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/Yd3yqkdDCnK1EBIwpacaYw