小紅書自研Binlog Server守護MySQL數據0丟失

異常情況下的數據丟失問題將極大地影響業務的可用性,尤其在一些核心場景的數據恢復過程更是耗時耗力。在業務支持上我們亟需一種方案,當數據庫在發生故障既要保證數據一致性也要減少切換時間,盡可能減少甚至徹底免除人工的介入。
小紅書數據庫團隊提出一種基于Binlog Server的數據一致性解決方案,通過提升半同步復制性能,加速日志傳輸,在故障時可無侵入現有數據庫架構地實現自動補數據,保證數據一致性。現推出的自研 Binlog Server 與 ORC 高可用方案,經過實踐已證明可做到:
1)使用極少的資源(1C1G)即可將復制速度提升至300MB/s+,實現了復制性能翻倍;
2)優化了故障切換效率,按照一致性優先原則使用Binlog Server為新主庫補數據,有效降低運維成本和業務風險,實現數據庫快速數據恢復。
目前該方案已經100%部署于小紅書半同步復制集群,在多次切換中為新主庫補數據,守護了核心數據庫的安全。
01、簡介
2017年 GitLab 數據庫工程師誤操作,導致18個小時的服務中斷并且部分數據永久性丟失,丟失數據影響了大約 5000 個客戶和 700 個項目。
2022年某云廠商部分區域 RDS 服務不可用,影響了業務大約 3+小時。
2023年某云數據庫出現了自動清理數據的 Bug,導致部分用戶的最新數據刪除且不可恢復。
2023年 Digital Ocean 托管的部分數據庫異常切換,導致部分用戶永久丟失 2-5 分鐘數據。
核心場景的數據庫一旦出現了數據丟失,會極大的影響了業務的可用性。因此,數據庫的高可用性和一致性始終是核心業務系統的關鍵訴求。比如,DBA 同學也剛剛經歷了這樣驚心動魄的一幕:
?? 某天,數據庫 P0 告警突發,核心集群主庫宕機!XX同學需要立即與上下游業務緊急聯動,定位到數據丟失并完成數據修正。經過一個小時的“救火”操作后,業務才逐漸恢復正常。這一“救火”場景出現,既消耗了大量的人力成本,也影響了系統整體穩定性。因此,亟需一種方案,當數據庫在發生故障切換下也能自動保障數據一致性和完整性,徹底免除人工介入。
在展開方案介紹之前,我們先來了解 2 個知識:
?? 什么是 RPO=0?RPO=0 意味著在任何切換或災難發生后,數據一條都不丟! 如果實現了 RPO=0,當數據庫發生宕機時,新的數據庫能夠100% 自動補齊所有數據,上下游業務不用再擔心數據修復事務,極大降低運維壓力和業務風險,在高可用里面實現了數據恢復的閉環。
?? 業內主流OLTP數據庫如何實現 RPO=0?業內主流方案主要分為以下三種:



MySQL 復制分為異步復制和半同步復制,其中半同步復制要求從庫至少有一臺復制成功響應,這樣保證至少一臺從庫保存了日志數據。所以半同步復制的速度決定了主庫寫入速度的上限。但社區半同步實現復雜,其復制速度較慢,影響了主庫寫入速度。Facebook方案使用 Binlog Server 加快半同步復制速度,從而提升了主庫寫入性能,讓更多的場景可以使用半同步復制。如果復制延遲太大(網絡或者CPU耗盡等場景下),復制會出現自動降級,從半同步復制退化為異步復制,被稱為半同步退化,半同步退化將影響數據一致性(本質是一種異步復制場景)。
基于方案復雜性和穩定性考慮,我們對比后決定采用 Binlog Server 方案,來實現小紅書 MySQL 的 RPO=0,并滿足以下條件:
- 將半同步復制速度翻倍,Binlog復制速度提升到 300MB/s+;
- 對現有 MySQL 架構和復制方案無侵入;
- 無縫支持現有 MySQL 高可用架構的切換方案。
1.1 收益概述
相對于社區MySQL半同步+開源ORC高可用組件,自研Binlog Server+自研ORC高可用在半同步復制速度、輕量化部署、數據一致性優先和運維便捷性等場景進行優化,保證 RPO=0。

得益于Binlog Server性能的提升,當出現寫入大壓力的場景時,Binlog Server可以跟上主庫寫入速度,并且在故障場景下為新主庫提供日志數據。


1.2 性能驗證
當前線上采用了同城異可用區 Binlog Server 部署形式,也就是在 MySQL 集群內部署一個同城、不同機房、半同步連接的 Binlog Server 實例,如下圖所示:

這樣做的目的是為了提升 MySQL 故障恢復的“數據 0 丟失”半徑 ,確保在發生機房級故障時,ORC 的切換機制依然能夠保證數據的一致性。Binlog Server 的性能顯著優于普通從庫,在小事務壓測條件下,其寫入速度可達 300MB/s,且資源消耗極低。憑借高吞吐、低資源消耗的優勢,Binlog Server 完全可以部署于異地機房,大幅提升系統在機房級故障下的數據恢復能力,實現 0 數據丟失的主庫故障切換。

1.3 切換效果驗證
得益于 Binlog Server 的高吞吐能力,以及半同步復制特性,可以確保 Binlog Server 中的數據始終保持最新。即使遇到如機房斷網等嚴重故障場景,結合 ORC 的選主策略,可以實現 MySQL 故障切換過程中數據 0 丟失。

目前 Binlog Server 配合 ORC 的數據一致性方案已經開始灰度,線上已經覆蓋到半同步核心集群,半同步集群覆蓋比例達到100%。
下面的案例的切換效果如下,詳細展示了切換過程中Binlog Server作為臨時主庫給下游補充數據。

02、需求分析
2.1 復制速度分析
首先關注一下影響主從延遲的原因。下圖是MySQL主從復制的完整的數據鏈路圖。綠色框表示執行線程,黃色框表示實例(主庫/從庫)的Binlog,因為Binlog Event中帶有時間戳,所以主從延遲表示為從庫的Binlog時間 - 主庫的Binlog時間。紅色的框為Relaylog,可以理解為從庫來不及處理的數據的臨時在磁盤存儲的文件。紫色為每個worker thread對應的處理隊列(內存結構)。
從圖中可以看到,整個復制鏈路經歷的環節特別多,任何一個環節速度跟不上都會造成主從延遲比較大。其中IO Thread和Dispatch Thread之間的干擾會降低半同步復制速度(包括不限于共享Mutex鎖,IO串行化,共享復制位點信息等),如果IO線程處理速度慢將影響Master節點對業務響應的速度。復制速度慢一直是MySQL社區存在的問題,否則也不會有各種Binlog Server方案。

2.2 行業方案調研
在MySQL不滿足需求的情況下,參考調研市場上已有的Binlog Server,總結各個方案的優缺點。

根據行業的調研和數據庫現狀,從上面的部署來看,Facebook Binlog Server方案是最合適的,其功能豐富,和現有系統能兼容。但其實現未開源,將按照其設計思路設計自研Binlog Server。
2.3 需求定位
- 功能:支持半同步,提供RPO=0的方案;支持級聯架構,在主從切換時為從庫補充Binlog數據;
- 性能:半同步復制時提供更高復制速度,相對于主庫無丟失;
- 運維:支持MySQL管理命令,無需外部系統改造;輕量化部署,1C1G資源即可滿足需求;
- 穩定性:支持crash recovery,保證數據一致性;
- 兼容性:兼容MySQL 生態的各種解析工具,無需單獨開發。
03、方案設計
Binlog Server架構與其基本數據流和控制流基本如下圖所示。下圖所示為級聯架構(對Binlog Server來說最復雜的場景),同時支持Master和Slave分別作為上下游,表現類似一個MySQL實例。其中綠色線表示Binlog Server控制流,主要是從Admin管理員發送的管控SQL,在SQL解析器處理后,在Manage模塊進行處理,可以對MasterSession(和主庫的連接),SlaveSession(和下游從庫的連接),Binlog(本地存儲文件)進行管理。紅色線就是數據流,主要是存放主庫發送來的Binlog數據,存儲在本地并通過SlaveSession向下游發送。具體模塊將一一展開介紹。

下面介紹3.1-3.5節為各個模塊實現細節,3.6節將介紹Binlog Server和ORC配合主從切換。
3.1 MySQL協議支持
為了滿足上面的數據流程,需要支持如下協議的解析&處理:
- BinlogServer->Master,Slave->BinlogServer進行認證、連接和狀態獲取SQL
- Admin->BinlogServer管理線程的認證和連接
- Admin->BinlogServer發送的COM命令
- BinlogServer->Admin發送的ResultSet
- Master->BinlogServer, BinlogServer->Slave發送的Event格式
這里需要按照MySQL協議規定的注冊、握手、COM格式、ResultSet格式以及EVENT格式處理, 對于協議的發送將復用MySQL Client的庫,但是協議解析和數據包封裝需要Binlog Server處理。以Binlog為例,其基本格式如下圖所示,需要分別對Header和Footer處理,提取各個字段。

3.2 SQL語法支持
為了方便ORC進行管理,對現有的運維系統和高可用系統無侵入。需要Binlog Server支持SQL語法,可以減少周圍系統的開發和適配成本。在這里我們制作了一個語法解析器支持特定SQL類型。聯調和部署時遇到新SQL支持,十分方便進行新語法的支持。
這里無法采用MySQL解析器,因為MySQL的詞法解析部分全部自行編寫,而不是采用FLEX(全局變量,不支持多線程并發),以提升SQL解析性能,從而支持每秒幾十萬次的SQL解析速度,缺點就是代碼非常復雜,難以將所需功能進行剝離。但是Binlog Server的SQL語法只是用來做運維管控,沒有對高并發的需求,所以在FLEX詞法解析過程即使串行化,依然有幾千次的解析速度,完全滿足管控SQL需求。可以使用AI寫bison和flex文件語法解析器文件,效果非常好。
如下圖所示,當輸入的字符串經過詞法解析器(取出token)和語法解析器(獲得語法樹),就可以提取需要的語法樹信息。

從整個SQL執行視角來看,SQL執行分為三個階段:
- 語法解析階段
- SQL命令執行階段
- SQL結果輸出階段
支持 start slave 和 stop slave 等運維命令,保持slave的啟停方式和MySQL一致。以start salve為例,下面展示了 SQL 解析和執行過程,首先會建立一個新 session 和 MySQL 客戶端保持聯系,然后用戶發出 start slave 命令,按照COM_QUERY進行解析。在自定義語法解析器中,將start slave 標記為 SQLCOM_START_SLAVE,然后執行 節點注冊過程(詳細過程見下一節),最終返回結果集。

3.3 節點注冊
Binlog Server支持級聯架構,既可以作為Slave節點從上游接收并保存Binlog,也可以作為Master向下游發送Binlog。因此其必須具有雙向注冊能力,需要遵守MySQL節點注冊的規范,模擬作為從庫或者主庫進行注冊。


3.4 半同步支持
和異步復制相比,半同步發送Binlog過程有變化,這將影響BinlogServer處理的過程。如下圖所示,Master節點生成了Binlog文件(由一個個Event構成),在發送Event時,會在每個Event前添加Header。每個Header由2字節構成,第一字節為0xEF(Magic Number)用于校驗,第二字節為0x1/0x0,用于指示從庫是否發送ACK。當數據發送到BinlogServer以后,會先處理Header信息,確定是否需要發送ACK,如果需要發送,就將MasterLog位點信息發送給主庫。主庫收到ACK后確認這些數據已經在下游持久化,即可在主庫InnoDB進行提交(AFTER_SYNC模式)。
這里需要注意一點,如果ACK信息丟了,后面的ACK確認的位點會自動包含前面的位點,這樣保證發送過程不至于中斷。

3.5 文件管理和數據一致性
Binlog文件管理主要分為兩部分,第一是Binlog文件管理;第二是Crash時的數據一致性。
- 文件管理:參考MySQL Binlog設計,使用索引文件記錄Binlog元數據信息。所以采用索引文件+數據文件結合的方式記錄。
- 數據一致性:Crash Safe重點強調宕機場景(非預期場景),但是對于預期內的關機也保持了一致性。

為了保證Binlog索引文件和數據文件的一致性,參考MySQL修改Binlog的方式。變動時先修改Binlog索引文件,創建新的臨時文件,然后再修改Binlog數據文件,最后將臨時的索引文件覆蓋寫為正式的索引文件。這個過程中如果出現了宕機等場景,那么根據臨時文件和Binlog文件是否修改,決定該操作是提交還是回滾,從而保證了數據的一致性。
3.6 高可用支持
當主庫宕機時,希望最終選舉出來一個同機房的新主庫為業務提供服務。但是同機房的從庫不一定是數據最多的從庫。因此需要增加補數據的環節,如下圖所示。

高可用組件ORC在數據切換的時候,會分為兩個階段進行。
1M:根據GTID最大原則選出第一輪備選主庫,開始補數據。這一輪沒有偏好,盡量選擇GTID最長的作為Master來給所有節點補數據。
2M:根據同機房 & GTID最長選擇第二輪主庫,作為新的Master。這一輪存在偏好,例如選擇和老主庫在同一個機房的Slave作為新主庫。

主庫故障和恢復流程簡化過程上圖所示。部署形態上采用Master掛載2個半同步的BinlogServer以保證數據不丟失,Master同時掛載若干個異步復制的Slave節點。
如果主庫宕機(不可恢復),如圖2所示:
- ORC 1M階段,將選擇兩個Binlog Server中GTID最長的一個作為臨時Master,給其他所有節點補數據。這一輪選舉大概率是同機房的Binlog Server。如果同機房Slave和Binlog Server GTID相同(寫入量很小,所有機器數據沒有延遲), ORC選擇沒有偏好,能將GTID補上即可。
- ORC 2M階段,同機房的Slave將作為新的主庫,將其他所有的節點掛載到新主庫上。
- 經過ORC 2M階段,數據庫集群即可對外提供服務。同時在本機房內,異步補充一臺新從庫。
- 新從庫補充完畢后,整體的部署將和故障前完全一致。
在這個過程中,Binlog Server的添加不會對ORC選舉額外造成負擔。因為1M選擇時,仍然按照GTID最長原則。所以Binlog Server提供足夠高的性能后,ORC會自然選擇到Binlog Server。只是在2M選擇的時候,需要排除Binlog Server作為新的備選主庫即可。
04、未來展望
Binlog Server是一個消耗資源極少的輕量化Binlog 存儲節點(1C1G即可)。除了提供一致性解決方案以外,未來也可以在其他使用Binlog的場景中發揮作用。
- 在從庫擴容、庫表拆分的場景中使用Binlog Server補充Binlog數據;
- Binlog Server支持標準MySQL協議,DTS、Canel等可以從Binlog Server拉取數據,降低主庫壓力;
- Binlog Server后端使用S3(配合S3FS)作為存儲,將節省Binlog保存成本,保持更長時間的Binlog數據。
05、作者簡介
張凡凡
小紅書關系型數據庫研發工程師,主要負責小紅書關系型數據庫內核研發。
周旭峰
小紅書關系型數據庫研發工程師,主要負責小紅書關系型數據庫高可用系統研發。

































