0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

探討MySQL的復制機制實現(xiàn)的方式

OSC開源社區(qū) ? 來源:vivo互聯(lián)網(wǎng)技術 ? 2023-04-12 09:29 ? 次閱讀

MySQL Replication(主從復制)是指數(shù)據(jù)變化可以從一個MySQL Server被復制到另一個或多個MySQL Server上,通過復制的功能,可以在單點服務的基礎上擴充數(shù)據(jù)庫的高可用性、可擴展性等。

一、背景

MySQL在生產(chǎn)環(huán)境中被廣泛地應用,大量的應用和服務都對MySQL服務存在重要的依賴關系,可以說如果數(shù)據(jù)層的MySQL實例發(fā)生故障,在不具備可靠降級策略的背景下就會直接引發(fā)上層業(yè)務,甚至用戶使用的障礙;同時MySQL中存儲的數(shù)據(jù)也是需要盡可能地減少丟失的風險,以避免故障時出現(xiàn)數(shù)據(jù)丟失引發(fā)的資產(chǎn)損失、客訴等影響。

在這樣對服務可用性和數(shù)據(jù)可靠性需求的背景下,MySQL在Server層提供了一種可靠的基于日志的復制能力(MySQL Replication),在這一機制的作用下,可以輕易構建一個或者多個從庫,提高數(shù)據(jù)庫的高可用性可擴展性,同時實現(xiàn)負載均衡

實時數(shù)據(jù)變化備份

主庫的寫入數(shù)據(jù)會持續(xù)地在冗余的從庫節(jié)點上被執(zhí)行保留,減少數(shù)據(jù)丟失的風險

橫向拓展節(jié)點,支撐讀寫分離

當主庫本身承受壓力較大時,可以將讀流量分散到其它的從庫節(jié)點上,達成讀擴展性和負載均衡

高可用性保障

當主庫發(fā)生故障時,可以快速的切到其某一個從庫,并將該從庫提升為主庫,因為數(shù)據(jù)都一樣,所以不會影響系統(tǒng)的運行

具備包括但不限于以上特性的MySQL集群就可以覆蓋絕大多數(shù)應用和故障場景,具備較高的可用性與數(shù)據(jù)可靠性,當前存儲組提供的生產(chǎn)環(huán)境MySQL就是基于默認的異步主從復制的集群,向業(yè)務保證可用性99.99%,數(shù)據(jù)可靠性99.9999%的在線數(shù)據(jù)庫服務。

本文將深入探討MySQL的復制機制實現(xiàn)的方式, 同時討論如何具體地應用復制的能力來提升數(shù)據(jù)庫的可用性,可靠性等。

二、復制的原理

2.1 Binlog 的引入

從比較寬泛的角度來探討復制的原理,MySQL的Server之間通過二進制日志來實現(xiàn)實時數(shù)據(jù)變化的傳輸復制,這里的二進制日志是屬于MySQL服務器的日志,記錄了所有對MySQL所做的更改。這種復制模式也可以根據(jù)具體數(shù)據(jù)的特性分為三種:

Statement:基于語句格式

Statement模式下,復制過程中向獲取數(shù)據(jù)的從庫發(fā)送的就是在主庫上執(zhí)行的SQL原句,主庫會將執(zhí)行的SQL原有發(fā)送到從庫中。

Row:基于行格式

Row模式下,主庫會將每次DML操作引發(fā)的數(shù)據(jù)具體行變化記錄在Binlog中并復制到從庫上,從庫根據(jù)行的變更記錄來對應地修改數(shù)據(jù),但DDL類型的操作依然是以Statement的格式記錄。

Mixed:基于混合語句和行格式

MySQL 會根據(jù)執(zhí)行的每一條具體的 SQL 語句來區(qū)分對待記錄的日志形式,也就是在 statement 和 row 之間選擇一種。

最早的實現(xiàn)是基于語句格式,在3.23版本被引入MySQL,從最初起就是MySQL Server層的能力,這一點與具體使用的存儲引擎沒有關聯(lián);在5.1版本后開始支持基于行格式的復制;在5.1.8版本后開始支持混合格式的復制。

這三種模式各有優(yōu)劣,相對來說,基于Row的行格式被應用的更廣泛,雖然這種模式下對資源的開銷會偏大,但數(shù)據(jù)變化的準確性以及可靠性是要強于Statement格式的,同時這種模式下的Binlog提供了完整的數(shù)據(jù)變更信息,可以使其應用不被局限在MySQL集群系統(tǒng)內,可以被例如Binlogserver,DTS數(shù)據(jù)傳輸?shù)确諔?,提供靈活的跨系統(tǒng)數(shù)據(jù)傳輸能力, 目前互聯(lián)網(wǎng)業(yè)務的在線MySQL集群全部都是基于Row行格式的Binlog。

2.2 Binlog 的要點

2.2.1 Binlog事件類型

對于Binlog的定義而言,可以認為是一個個單一的Event組成的序列,這些單獨的Event可以主要分為以下幾類:

40334724-d88b-11ed-bfe3-dac502259ad0.jpg

各類Event出現(xiàn)是具有顯著的規(guī)律的:

XID_EVENT標志一個事務的結尾

當發(fā)生了DDL類型的QUERY_EVENT,那么也是一次事務的結束提交點,且不會出現(xiàn)XID_EVENT

GTID_EVENT只有開啟了GTID_MODE(MySQL版本大于5.6)

TABLE_MAP_EVENT必定出現(xiàn)在某個表的變更數(shù)據(jù)前,存在一對多個ROW_EVENT的情況

除了上面和數(shù)據(jù)更貼近的事件類型外,還有ROTATE_EVENT(標識Binlog文件發(fā)生了切分),F(xiàn)ORMAT_DESCRIPTION_EVENT(定義元數(shù)據(jù)格式)等。

2.2.2 Binlog的生命周期

Binlog和Innodb Log(redolog)的存在方式是不同的,它并不會輪轉重復覆寫文件,Server會根據(jù)配置的單個Binlog文件大小配置不斷地切分并產(chǎn)生新的Binlog,在一個.index文件記錄當前硬盤上所有的binlog文件名,同時根據(jù)Binlog過期時間回收刪除掉過期的Binlog文件,這兩個在目前自建數(shù)據(jù)庫的配置為單個大小1G,保留7天。

所以這種機制背景下,只能在短期內追溯歷史數(shù)據(jù)的狀態(tài),而不可能完整追溯數(shù)據(jù)庫的數(shù)據(jù)變化的,除非是還沒有發(fā)生過日志過期回收的Server。

2.2.3Binlog事件示例

Binlog是對Server層生效的,即使沒有從庫正在復制主庫,只要在配置中開啟了log_bin,就會在對應的本地目錄存儲binlog文件,使用mysqlbinlog打開一個Row格式的示例binlog文件:

403d683a-d88b-11ed-bfe3-dac502259ad0.png

如上圖,可以很明顯地注意到三個操作,創(chuàng)建數(shù)據(jù)庫test, 創(chuàng)建數(shù)據(jù)表test, 一次寫入引發(fā)的行變更,可讀語句(create, alter, drop, begin, commit.....)都可以認為是QUERY_EVENT,而Write_rows就屬于ROW_EVENT中的一種。

在復制的過程中,就是這樣的Binlog數(shù)據(jù)通過建立的連接發(fā)送到從庫,等待從庫處理并應用。

2.2.4 復制基準值

Binlog在產(chǎn)生時是嚴格有序的,但它本身只具備秒級的物理時間戳,所以依賴時間進行定位或排序是不可靠的,同一秒可能有成百上千的事件,同時對于復制節(jié)點而言,也需要有效可靠的記錄值來定位Binlog中的水位,MySQL Binlog支持兩種形式的復制基準值,分別是傳統(tǒng)的Binlog File:Binlog Position模式,以及5.6版本后可用的全局事務序號GTID。

FILE Position

只要開啟了log_bin,MySQL就會具有File Position的位點記錄,這一點不受GTID影響。

File: binlog.000001
Position: 381808617

這個概念相對來說更直觀,可以直接理解為當前處在File對應編號的Binlog文件中,同時已經(jīng)產(chǎn)生了合計Position bytes的數(shù)據(jù),如例子中所示即該實例已經(jīng)產(chǎn)生了381808617 bytes的Binlog,這個值在對應機器直接查看文件的大小也是匹配的,所以File Postion就是文件序列與大小的對應值。

基于這種模式開啟復制,需要顯式地在復制關系中指定對應的File和Position:

CHANGE MASTER TO MASTER_LOG_FILE='binlog.000001', MASTER_LOG_POSITION=381808617;

這個值必須要準確,因為這種模式下從庫獲取的數(shù)據(jù)完全取決于有效的開啟點,那么如果存在偏差,就會丟失或執(zhí)行重復數(shù)據(jù)導致復制中斷。

GTID

MySQL 會在開啟GTID_MODE=ON的狀態(tài)下,為每一個事務分配唯一的全局事務ID,格式為:server_uuid:id

Executed_Gtid_Set: e2e0a733-3478-11eb-90fe-b4055d009f6c:1-753

其中e2e0a733-3478-11eb-90fe-b4055d009f6c用于唯一地標識產(chǎn)生該Binlog事件的實例,1-753表示已經(jīng)產(chǎn)生或接收了由e2e0a733-3478-11eb-90fe-b4055d009f6c實例產(chǎn)生的753個事務;

從庫在從主庫獲取Binlog Event時,自身的執(zhí)行記錄會保持和獲取的主庫Binlog GTID記錄一致,還是以e2e0a733-3478-11eb-90fe-b4055d009f6c:1-753,如果有從庫對e2e0a733-3478-11eb-90fe-b4055d009f6c開啟了復制,那么在從庫自身執(zhí)行show master status也是會看到相同的值。

如果說從庫上可以看到和復制的主庫不一致的值,那么可以認為是存在errant GTID,這個一般是由于主從切換或強制在從庫上執(zhí)行了寫操作引發(fā),正常情況下從庫的Binlog GTID應該和主庫的保持一致;

基于這種模式開啟復制,不需要像File Position一樣指定具體的值,只需要設置:

CHANGE MASTER TO MASTER_AUTO_POSITION=1;

從庫在讀取到Binlog后,會自動根據(jù)自身Executed_GTID_Set記錄比對是否存在已執(zhí)行或未執(zhí)行的Binlog事務,并做對應的忽略和執(zhí)行操作。

2.3 復制的具體流程

2.3.1基本復制流程

當主庫已經(jīng)開啟了binlog( log_bin = ON ),并正常地記錄binlog,如何開啟復制?

這里以MySQL默認的異步復制模式進行介紹:

首先從庫啟動I/O線程,跟主庫建立客戶端連接。

主庫啟動binlog dump線程,讀取主庫上的binlog event發(fā)送給從庫的I/O線程,I/O線程獲取到binlog event之后將其寫入到自己的Relay Log中。

從庫啟動SQL線程,將等待Relay中的數(shù)據(jù)進行重放,完成從庫的數(shù)據(jù)更新。

總結來說,主庫上只會有一個線程,而從庫上則會有兩個線程。

404b59cc-d88b-11ed-bfe3-dac502259ad0.jpg

時序關系

當集群進入運行的狀態(tài)時,從庫會持續(xù)地從主庫接收到Binlog事件,并做對應的處理,那么這個過程中將會按照下述的數(shù)據(jù)流轉方式:

Master將數(shù)據(jù)更改記錄在Binlog中,BinlogDump Thread接到寫入請求后,讀取對應的Binlog

Binlog信息推送給Slave的I/O Thread。

Slave的I/O 線程將讀取到的Binlog信息寫入到本地Relay Log中。

Slave的SQL 線程讀取Relay Log中內容在從庫上執(zhí)行。

4060931e-d88b-11ed-bfe3-dac502259ad0.png

上述過程都是異步操作,所以在某些涉及到大的變更,例如DDL改變字段,影響行數(shù)較大的寫入、更新或刪除操作都會導致主從間的延遲激增,針對延遲的場景,高版本的MySQL逐步引入了一些新的特性來幫助提高事務在從庫重放的速度。

Relay Log的意義

Relay log在本質上可以認為和binlog是等同的日志文件,即使是直接在本地打開兩者也只能發(fā)現(xiàn)很少的差異;

Binlog Version 3 (MySQL 4.0.2 - < 5.0.0)

added the relay logs and changed the meaning of the log position

在MySQL 4.0 之前是沒有Relay Log這部分的,整個過程中只有兩個線程。但是這樣也帶來一個問題,那就是復制的過程需要同步的進行,很容易被影響,而且效率不高。例如主庫必須要等待從庫讀取完了才能發(fā)送下一個binlog事件。這就有點類似于一個阻塞的信道和非阻塞的信道。

在流程中新增Relay Log中繼日志后,讓原本同步的獲取事件、重放事件解耦了,兩個步驟可以異步的進行,Relay Log充當了緩沖區(qū)的作用。Relay Log包含一個relay-log.info的文件,用于記錄當前復制的進度,下一個事件從什么Pos開始寫入,該文件由SQL線程負責更新。

對于后續(xù)逐漸引入的特殊復制模式,會存在一些差異,但整體來說,是按照這個流程來完成的。

2.3.2半同步復制

異步復制的場景下,不能確保從庫實時更新到和主庫一致的狀態(tài),那么如果在出現(xiàn)延遲的背景下發(fā)生主庫故障,那么兩者間的差異數(shù)據(jù)還是無法進行保障,同時也無法在這種情況下進行讀寫分離,而如果說由異步改為完全同步,那么性能開銷上又會大幅提高,很難滿足實際使用的需求。

基于這一的背景,MySQL從5.5版本開始引入了半同步復制機制來降低數(shù)據(jù)丟失的概率,在這種復制模式中,MySQL讓Master在某一個時間點等待一個Slave節(jié)點的 ACK(Acknowledge Character)消息,接收到ACK消息后才進行事務提交,這樣既可以減少對性能的影響,還可以相對異步復制獲得更強的數(shù)據(jù)可靠性。

介紹半同步復制之前先快速過一下 MySQL 事務寫入碰到主從復制時的完整過程,主庫事務寫入分為 4個步驟:

InnoDB Redo File Write (Prepare Write)

Binlog File Flush & Sync to Binlog File

InnoDB Redo File Commit(Commit Write)

Send Binlog to Slave

當Master不需要關注Slave是否接受到Binlog Event時,即為異步主從復制

當Master需要在第3步Commit Write回復客戶端前等待Slave的ACK時,為半同步復制(after-commit)

當Master需要在第2步Flush&Sync,即Commit前等待Slave的ACK時,為增強半同步復制(after-sync)

時序關系

從半同步復制的時序圖來看,實際上只是在主庫Commit的環(huán)節(jié)多了等待接收從庫ACK的階段,這里只需要收到一個從節(jié)點的ACK即可繼續(xù)正常的處理流程,這種模式下,即使主庫宕機了,也能至少保證有一個從庫節(jié)點是可以用的,此外還減少了同步時的等待時間。

406c7f08-d88b-11ed-bfe3-dac502259ad0.png

2.3.3 小結

在當前生產(chǎn)環(huán)境的在線數(shù)據(jù)庫版本背景下,由MySQL官方提供的復制方式主要如上文介紹的內容,當然目前有還很多基于MySQL或兼容MySQL的衍生數(shù)據(jù)庫產(chǎn)品,能在可用性和可靠性上做更大的提升,本文就不繼續(xù)展開這部分的描述。

2.4 復制的特性

目前已經(jīng)提及的復制方式,存在一個顯著的特性:無法回避數(shù)據(jù)延遲的場景,異步復制會使得從庫的數(shù)據(jù)落后,而半同步復制則會阻塞主庫的寫入,影響性能。

MySQL早期的復制模式中,從庫的IO線程和SQL線程本質上都是串行獲取事件并讀取重放的,只有一個線程負責執(zhí)行Relaylog,但主庫本身接收請求是可以并發(fā)地,性能上限只取決于機器資源瓶頸和MySQL處理能力的上限,主庫的執(zhí)行和從庫的執(zhí)行(SQL線程應用事件)是很難對齊的,這里引用一組測試數(shù)據(jù):

機器:64核 256G,MySQL 5.7.29

測試場景:常規(guī)的INSERT,UPDATE壓測場景

結果:MySQL Server的IO線程速度以網(wǎng)絡上的數(shù)據(jù)量評估,每秒超過100MB,正常是可以覆蓋業(yè)務使用的,然而SQL線程的預估速度只有21~23MB/s,如果是涉及UPDATE場景,性能還會減少;

需要注意的是,以上結果是在高版本的MySQL具備并行復制能力的前提下取得,如果是不具備該特性的版本,性能會更差。

期望業(yè)務層限制使用是不現(xiàn)實的,MySQL則在5.6版本開始嘗試引入可用的并行復制方案,總的來說,都是通過嘗試加強在從庫層面的應用速度的方式。

2.4.1 基于Schema級別的并行復制

基于庫級別的并行復制是出于一個非常簡易的原則,實例中不同Database/Schema內的數(shù)據(jù)以及數(shù)據(jù)變更是無關的,可以并行去處置。

在這種模式中,MySQL的從節(jié)點會啟動多個WorkThread ,而原來負責回放的SQLThread會轉變成Coordinator角色,負責判斷事務能否并行執(zhí)行并分發(fā)給WorkThread。

如果事務分別屬于不同的Schema,并且不是DDL語句,同時沒有跨Schema操作,那么就可以并行回放,否則需要等所有Worker線程執(zhí)行完成后再執(zhí)行當前日志中的內容。

MySQLServer
 
MySQL [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| aksay_record       |
| mysql              |
| performance_schema |
| proxy_encrypt      |
| sys                |
| test               |
+--------------------+
7 rows in set (0.06 sec)

對于從庫而言,如果接收到了來自主庫的aksay_record以及proxy_encrypt內的數(shù)據(jù)變更,那么它是可以同時去處理這兩部分Schema的數(shù)據(jù)的。

但是這種方式也存在明顯缺陷和不足,首先只有多個Schema流量均衡的情況下才會有較大的性能改善,但如果存在熱點表或實例上只有一個Schema有數(shù)據(jù)變更,那么這種并行模式和早期的串行復制也不存在差異;同樣,雖然不同Schema的數(shù)據(jù)是沒有關聯(lián),這樣并行執(zhí)行也會影響事務的執(zhí)行順序,某種程度來說,整個Server的因果一致性被破壞了。

2.4.2基于組提交的復制(Group Commit)

基于Schema的并行復制在大部分場景是沒有效力的,例如一庫多表的情況下,但改變從庫的單執(zhí)行線程的思路被延續(xù)了下來,在5.7版本新增加了一種基于事務組提交的并行復制方式,在具體介紹應用在復制中的組提交策略前,需要先介紹Server本身Innodb引擎提交事務的邏輯:

Binlog的落盤是基于sync_binlog的配置來的,正常情況都是取sync_binlog=1,即每次事務提交就發(fā)起fsync刷盤。

主庫在大規(guī)模并發(fā)執(zhí)行事務時,因為每個事務都觸發(fā)加鎖落盤,反而使得所有的Binlog串行落盤,成為性能上的瓶頸。針對這個問題,MySQL本身在5.6版本引入了事務的組提交能力(這里并不是指在從庫上應用的邏輯),設計原理很容易理解,只要是能在同一個時間取得資源,開啟Prepare的所有事務,都是可以同時提交的。

在主庫具有這一能力的背景下,可以很容易得發(fā)現(xiàn)從庫也可以應用相似的機制來并行地去執(zhí)行事務,下面介紹MySQL具體實現(xiàn)經(jīng)歷的兩個階段:

基于Commit-Parents-Based

MySQL中寫入是基于鎖的并發(fā)控制,所以所有在Master端同時處于Prepare階段且未提交的事務就不會存在鎖沖突,在Slave端執(zhí)行時都可以并行執(zhí)行。

因此可以在所有的事務進入prepare階段的時候標記上一個logical timestamp(實現(xiàn)中使用上一個提交事務的sequence_number),在Slave端同樣timestamp的事務就可以并發(fā)執(zhí)行。

但這種模式會依賴上一個事務組的提交,如果本身是不受資源限制的并發(fā)事務,卻會因為它的commit-parent沒有提交而無法執(zhí)行;

基于Logic-Based

針對Commit-Parent-Based中存在的限制進行了解除,純粹的理解就是只有當前事務的sequence_number一致就可以并發(fā)執(zhí)行,只根據(jù)是否能取得鎖且無沖突的情況即可以并發(fā)執(zhí)行,而不是依賴上一個已提交事務的sequence_number。

三、應用

當前vivo的在線MySQL數(shù)據(jù)庫服務標準架構是基于一主一從一離線的異步復制集群,其中一從用于業(yè)務讀請求分離,離線節(jié)點不提供讀服務,提供給大數(shù)據(jù)離線和實時抽數(shù)/DB平臺查詢以及備份系統(tǒng)使用;針對這樣的應用背景,存儲研發(fā)組針對MySQL場景提供了兩種額外的擴展服務:

3.1應用高可用系統(tǒng)+中間件

雖然MySQL的主從復制可以提高系統(tǒng)的高可用性,但是MySQL在5.6,5.7版本是不具備類似Redis的自動故障轉移的能力,如果主庫宕機后不進行干預,業(yè)務實際上是無法正常寫入的,故障時間較長的情況下,分離在從庫上的讀也會變得不可靠。

3.1.1 VSQL(原高可用2.0架構)

那么在當前這樣標準一主二從架構的基礎上,為系統(tǒng)增加HA高可用組件以及中間件組件強化MySQL服務的高可用性、讀拓展性、數(shù)據(jù)可靠性:

HA組件管理MySQL的復制拓撲,負責監(jiān)控集群的健康狀態(tài),管理故障場景下的自動故障轉移;

中間件Proxy用于管理流量,應對原有域名場景下變更解析慢或緩存不生效的問題,控制讀寫分離、實現(xiàn)IP、SQL的黑白名單等;

4073e450-d88b-11ed-bfe3-dac502259ad0.png

3.1.2數(shù)據(jù)可靠性強化

數(shù)據(jù)本身還是依賴MySQL原生的主從復制模式在集群中同步,這樣仍然存在異步復制本身的風險,發(fā)生主庫宕機時,如果從庫上存在還未接收到的主庫數(shù)據(jù),這部分就會丟失,針對這個場景,我們提供了三種可行的方案:

日志遠程復制

配置HA的中心節(jié)點和全網(wǎng)MySQL機器的登錄機器后,按照經(jīng)典的MHA日志文件復制補償方案來保障故障時的數(shù)據(jù)不丟失,操作上即HA節(jié)點會訪問故障節(jié)點的本地文件目錄讀取候選主節(jié)點缺失的Binlog數(shù)據(jù)并在候選主上重放。

優(yōu)勢

與1.0的MHA方案保持一致,可以直接使用舊的機制

機制改造后可以混合在高可用的能力內,不需要機器間的免密互信,降低權限需求和安全風險

劣勢

不一定可用,需要故障節(jié)點所在機器可訪達且硬盤正常,無法應對硬件或網(wǎng)絡異常的情況

網(wǎng)絡上鏈路較長,可能無法控制中間重放日志的耗時,導致服務較長時間不可用

407c89f2-d88b-11ed-bfe3-dac502259ad0.png

日志集中存儲

依賴數(shù)據(jù)傳輸服務中的BinlogServer模塊,提供Binlog日志的集中存儲能力,HA組件同時管理MySQL集群以及BinlogServer,強化MySQL架構的健壯性,真實從庫的復制關系全部建立在BinlogServer上,不直接連接主庫。

優(yōu)勢

可以自定義日志的存儲形式:文件系統(tǒng)或其它共享存儲模式

不涉及機器可用和權限的問題

間接提高binlog的保存安全性(備份)

劣勢

額外的資源使用,如果需要保留較長時間的日志,資源使用量較大

如果不開啟半同步,也不能保證所有的binlog日志都能被采集到,即使采集(相當于IO線程)速度遠超relay速度,極限約110MB/s

系統(tǒng)復雜度提升,需要承受引入額外鏈路的風險

改變?yōu)榘胪綇椭?/strong>

MySQL集群開啟半同步復制,通過配置防止退化(風險較大),Agent本身支持半同步集群的相關監(jiān)控,可以減少故障切換時日志丟失的量(相比異步復制)

優(yōu)勢

MySQL原生的機制,不需要引入額外的風險

本質上就是在強化高可用的能力(MySQL集群本身)

HA組件可以無縫接入開啟半同步的集群,不需要任何改造

劣勢

存在不兼容的版本,不一定可以開啟

業(yè)務可能無法接受性能下降的后果

半同步不能保證完全不丟數(shù)據(jù),Agent本身機制實際上是優(yōu)先選擇“執(zhí)行最多”的從節(jié)點而不是“日志最多”的從節(jié)點

orchestrator will promote the replica which has executed more events rather than the replica which has more data in the relay logs.

目前來說,我們采用的是日志遠程復制的方案,同時今年在規(guī)劃集中存儲的BinlogServer方案來強化數(shù)據(jù)安全性;不過值得一提的是,半同步也是一種有效可行的方式,對于讀多寫少的業(yè)務實際上是可以考慮升級集群的能力,這樣本質上也可以保證分離讀流量的準確性。

3.2數(shù)據(jù)傳輸服務

3.2.1 基于Binlog的跨系統(tǒng)數(shù)據(jù)流轉

通過利用Binlog,實時地將MySQL的數(shù)據(jù)流轉到其它系統(tǒng),包括MySQL,ElasticSearch,Kafka等MQ已經(jīng)是一種非常經(jīng)典的應用場景了,MySQL原生提供的這種變化數(shù)據(jù)同步的能力使其可以有效地在各個系統(tǒng)間實時聯(lián)動,DTS(數(shù)據(jù)傳輸服務)針對MySQL的采集也是基于和前文介紹的復制原理一致的方法,這里介紹我們是如何利用和MySQL 從節(jié)點相同的機制去獲取數(shù)據(jù)的,也是對于完整開啟復制的拓展介紹:

(1)如何獲取Binlog

比較常規(guī)的方式有兩種:

監(jiān)聽Binlog文件,類似日志采集系統(tǒng)的操作

MySQL Slave的機制,采集者偽裝成Slave來實現(xiàn)

本文只介紹第二種,F(xiàn)ake Slave的實現(xiàn)方式

40874a90-d88b-11ed-bfe3-dac502259ad0.jpg

(2)注冊Slave身份

這里以GO SDK為例,GO的byte范圍是0~255,其它語言做對應轉換即可。

data := make([]byte, 4+1+4+1+len(hostname)+1+len(b.cfg.User)+1+len(b.cfg.Password)+2+4+4)

第0-3位為0,無意義

第4位是MySQL協(xié)議中的Command_Register_Slave,byte值為21

第5-8位是當前實例預設的server_id(非uuid,是一個數(shù)值)使用小端編碼成的4個字節(jié)

接下來的若干位是把當前實例的hostname,user,password

接下來的2位是小端編碼的port端口

最后8位一般都置為0,其中最后4位指master_id,偽裝slave設置為0即可

(3)發(fā)起復制指令

data := make([]byte, 4+1+4+2+4+len(p.Name))

40968316-d88b-11ed-bfe3-dac502259ad0.png

第0-3位同樣置為0,無特殊意義

第4位是MySQL協(xié)議的Command_Binlog_Dump,byte值為18

第5-8位是Binlog Position值的小端序編碼產(chǎn)生的4位字節(jié)

第9-10位是MySQL Dump的類別,默認是0,指Binlog_Dump_Never_Stop,即編碼成2個0值

第11-14位是實例的server_id(非uuid)基于小端編碼的四個字節(jié)值

最后若干位即直接追加Binlog File名稱

以上兩個命令通過客戶端連接執(zhí)行后,就可以在主庫上觀察到一個有效的復制連接。

40a098ec-d88b-11ed-bfe3-dac502259ad0.png

3.2.2 利用并行復制模式提升性能

以上兩個命令通過客戶端連接執(zhí)行后,就可以在主庫上觀察到一個有效的復制連接。

根據(jù)早期的性能測試結果,不做任何優(yōu)化,直接單連接重放源集群數(shù)據(jù),在網(wǎng)絡上的平均傳輸速度在7.3MB/s左右,即使是和MySQL的SQL Relay速度相比也是相差很遠,在高壓場景下很難滿足需求。

DTS消費單元實現(xiàn)了對消費自kafka的事件的事務重組以及并發(fā)的事務解析工作,但實際最終執(zhí)行還是串行單線程地向MySQL回放,這一過程使得性能瓶頸完全集中在了串行執(zhí)行這一步驟。

MySQL 5.7版本以前,會利用事務的Schema屬性,使不同db下的DML操作可以在備庫并發(fā)回放。在優(yōu)化后,可以做到不同表table下并發(fā)。但是如果業(yè)務在Master端高并發(fā)寫入一個庫(或者優(yōu)化后的表),那么slave端就會出現(xiàn)較大的延遲?;趕chema的并行復制,Slave作為只讀實例提供讀取功能時候可以保證同schema下事務的因果序(Causal Consistency,本文討論Consistency的時候均假設Slave端為只讀),而無法保證不同schema間的。例如當業(yè)務關注事務執(zhí)行先后順序時候,在Master端db1寫入T1,收到T1返回后,才在db2執(zhí)行T2。但在Slave端可能先讀取到T2的數(shù)據(jù),才讀取到T1的數(shù)據(jù)。

MySQL 5.7的LOGICAL CLOCK并行復制,解除了schema的限制,使得在主庫對一個db或一張表并發(fā)執(zhí)行的事務到slave端也可以并行執(zhí)行。Logical Clock并行復制的實現(xiàn),最初是Commit-Parent-Based方式,同一個commit parent的事務可以并發(fā)執(zhí)行。但這種方式會存在可以保證沒有沖突的事務不可以并發(fā),事務一定要等到前一個commit parent group的事務全部回放完才能執(zhí)行。后面優(yōu)化為Lock-Based方式,做到只要事務和當前執(zhí)行事務的Lock Interval都存在重疊,即保證了Master端沒有鎖沖突,就可以在Slave端并發(fā)執(zhí)行。LOGICAL CLOCK可以保證非并發(fā)執(zhí)行事務,即當一個事務T1執(zhí)行完后另一個事務T2再開始執(zhí)行場景下的Causal Consistency。

(1)連接池改造

舊版的DTS的每一個消費任務只有一條維持的MySQL長連接,該消費鏈路的所有的事務都在這條長連接上串行執(zhí)行,產(chǎn)生了極大的性能瓶頸,那么考慮到并發(fā)執(zhí)行事務的需求,不可能對連接進行并發(fā)復用,所以需要改造原本的單連接對象,提升到近似連接池的機制。

go-mysql/client包本身不包含連接池模式,這里基于事務并發(fā)解析的并發(fā)度在啟動時,擴展存活連接的數(shù)量。

// 初始化客戶端連接數(shù)
se.conn = make([]*Connection, meta.MaxConcurrenceTransaction)

(2)并發(fā)選擇連接

利用邏輯時鐘

開啟GTID復制的模式下,binlog中的GTID_EVENT的正文內會包含兩個值:

LastCommitted  int64
SequenceNumber int64

lastCommitted是我們并發(fā)的依據(jù),原則上,LastCommitted相等事務可以并發(fā)執(zhí)行,結合原本事務并發(fā)解析完成后會產(chǎn)生并發(fā)度(配置值)數(shù)量的事務集合,那么對這個列表進行分析判斷,進行事務到連接池的分配,實現(xiàn)一種近似負載均衡的機制。

非并發(fā)項互斥

對于并發(fā)執(zhí)行的場景,可以比較簡單地使用類似負載均衡的機制,從連接池中遍歷mysql connection執(zhí)行對應的事務;但需要注意到的是,源的事務本身是具有順序的,在logical-clock的場景下,存在部分并發(fā)prepare的事務是可以被并發(fā)執(zhí)行的,但仍然有相當一部分的事務是不可并發(fā)執(zhí)行,它們顯然是分散于整個事務隊列中,可以認為并發(fā)事務(最少2個)是被不可并發(fā)事務包圍的:

假定存在一個事務隊列有6個元素,其中只有t1、t2和t5、t6可以并發(fā)執(zhí)行,那么執(zhí)行t3時,需要t1、t2已經(jīng)執(zhí)行完畢,執(zhí)行t5時需要t3,t4都執(zhí)行完畢。

40c03dc8-d88b-11ed-bfe3-dac502259ad0.jpg

(3)校驗點更新

在并發(fā)的事務執(zhí)行場景下,存在水位低的事務后執(zhí)行完,而水位高的事務先執(zhí)行完,那么依照原本的機制,更低的水位會覆蓋掉更高的水位,存在一定的風險:

Write_Event的構造SQL調整為replace into,可以回避沖突重復的寫事件;Update和Delete可以基于邏輯時鐘的并發(fā)保障,不會出現(xiàn)。

水位只會向上提升,不會向下降低。

但不論怎樣進行優(yōu)化,并發(fā)執(zhí)行事務必然會引入更多的風險,例如并發(fā)事務的回滾無法控制,目標實例和源實例的因果一致性被破壞等,業(yè)務可以根據(jù)自身的需要進行權衡,是否開啟并發(fā)的執(zhí)行。

基于邏輯時鐘并發(fā)執(zhí)行事務改造后,消費端的執(zhí)行性能在同等的測試場景下,可以從7.3MB/s提升到13.4MB/s左右。

(4)小結

基于消費任務本身的庫、表過濾,可以實現(xiàn)另一種形式下的并發(fā)執(zhí)行,可以啟動復數(shù)的消費任務分別支持不同的庫、表,這也是利用了kafka的多消費者組支持,可以橫向擴展以提高并發(fā)性能,適用于數(shù)據(jù)遷移場景,這一部分可以專門提供支持。

而基于邏輯時鐘的方式,對于目前現(xiàn)網(wǎng)大規(guī)模存在的未開啟GTID的集群是無效的,所以這一部分我們也一直在尋找更優(yōu)的解決方案,例如更高版本的特性Write Set的合并等,繼續(xù)做性能優(yōu)化。

四、總結

最后,關于MySQL的復制能力不僅對于MySQL數(shù)據(jù)庫服務本身的可用性、可靠性有巨大的提升,也提供了Binlog這一非常靈活的開放式的數(shù)據(jù)接口用于擴展數(shù)據(jù)的應用范圍,通過利用這個“接口”,很容易就可以達成數(shù)據(jù)在多個不同存儲結構、環(huán)境的實時同步,未來存儲組也將會聚焦于BinlogServer這一擴展服務來強化MySQL的架構,包括但不限于數(shù)據(jù)安全性保障以及對下游數(shù)據(jù)鏈路的開放等。






審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • DTS
    DTS
    +關注

    關注

    1

    文章

    50

    瀏覽量

    16037
  • MySQL
    +關注

    關注

    1

    文章

    789

    瀏覽量

    26283
  • DDL
    DDL
    +關注

    關注

    0

    文章

    12

    瀏覽量

    6309
  • MYSQL數(shù)據(jù)庫

    關注

    0

    文章

    95

    瀏覽量

    9347

原文標題:MySQL主從復制原理剖析與應用實踐

文章出處:【微信號:OSC開源社區(qū),微信公眾號:OSC開源社區(qū)】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    一文了解MySQL索引機制

    接觸MySQL數(shù)據(jù)庫的小伙伴一定避不開索引,索引的出現(xiàn)是為了提高數(shù)據(jù)查詢的效率,就像書的目錄一樣。 某一個SQL查詢比較慢,你第一時間想到的就是“給某個字段加個索引吧”,那么索引是什么?是如何工作
    的頭像 發(fā)表于 07-25 14:05 ?154次閱讀
    一文了解<b class='flag-5'>MySQL</b>索引<b class='flag-5'>機制</b>

    如何實現(xiàn)Python復制文件操作

    Python 中有許多“開蓋即食”的模塊(比如 os,subprocess 和 shutil)以支持文件 I/O 操作。在這篇文章中,你將會看到一些用 Python 實現(xiàn)文件復制的特殊方法。下面我們開始學習這九種不同的方法來實現(xiàn)
    的頭像 發(fā)表于 07-18 14:53 ?253次閱讀

    MySQL忘記root密碼解決方案

    mysql登錄密碼為password()算法加密,解密成本太高,以下為通用方案; 原理:mysql提供了特殊啟動方式,即跳過權限表驗證,啟動后,登錄不需要提供密碼; 登錄后,即可修改
    的頭像 發(fā)表于 04-23 16:08 ?542次閱讀

    查詢SQL在mysql內部是如何執(zhí)行?

    我們知道在mySQL客戶端,輸入一條查詢SQL,然后看到返回查詢的結果。這條查詢語句在 MySQL 內部到底是如何執(zhí)行的呢?本文跟大家探討一下哈,我們先來看下MySQL基本架構~
    的頭像 發(fā)表于 01-22 14:53 ?405次閱讀
    查詢SQL在<b class='flag-5'>mysql</b>內部是如何執(zhí)行?

    ad復制元件怎么保持編號不變

    瀏覽器”來創(chuàng)建和管理元件庫。在創(chuàng)建庫時,為每個元件分配一個唯一的編號,該編號將在復制過程中保持不變。 復制元件:選中要復制的元件,并使用“復制”命令或快捷鍵(Ctrl+C)將其
    的頭像 發(fā)表于 12-27 17:07 ?5771次閱讀

    mysql備份還原哪些方法

    MySQL是一個開源的關系型數(shù)據(jù)庫管理系統(tǒng),備份和還原是保證數(shù)據(jù)安全性和可恢復性的重要措施。本文將詳細介紹MySQL備份和還原的方法,包括物理備份和邏輯備份等多種方式,以及每種方式
    的頭像 發(fā)表于 11-23 14:35 ?880次閱讀

    docker部署mysql的壞處

    Docker 是一種虛擬化技術,它允許開發(fā)人員在容器內打包應用程序及其所有依賴項,從而實現(xiàn)在不同環(huán)境中運行相同的應用程序的能力。然而,在使用 Docker 部署 MySQL 時,也存在一些潛在
    的頭像 發(fā)表于 11-23 09:29 ?1169次閱讀

    mysql主從復制數(shù)據(jù)不一致怎么辦

    MySQL主從復制是一種常用的數(shù)據(jù)復制技術,用于實現(xiàn)數(shù)據(jù)的實時同步和分布式部署。然而,在實際應用中,主從復制過程中出現(xiàn)數(shù)據(jù)不一致的情況也是很
    的頭像 發(fā)表于 11-16 14:35 ?1887次閱讀

    mysql主從復制 混合類型的復制

    MySQL主從復制是一種常用的數(shù)據(jù)復制技術,可以實現(xiàn)數(shù)據(jù)從一個MySQL服務器(主服務器)復制
    的頭像 發(fā)表于 11-16 14:20 ?447次閱讀

    mysql主從復制的原理

    MySQL主從復制是一種數(shù)據(jù)庫復制技術,它允許將一個MySQL數(shù)據(jù)庫的更新操作自動復制到其他MySQL
    的頭像 發(fā)表于 11-16 14:18 ?404次閱讀

    mysql主從復制主要有幾種模式

    MySQL主從復制MySQL數(shù)據(jù)庫中常用的一種數(shù)據(jù)復制方式,用于實現(xiàn)數(shù)據(jù)的備份、負載均衡、故障
    的頭像 發(fā)表于 11-16 14:15 ?1035次閱讀

    mysql如何實現(xiàn)主從復制的具體流程

    主從復制MySQL數(shù)據(jù)庫中常用的數(shù)據(jù)復制技術之一,它的主要目的是將一個數(shù)據(jù)庫服務器上的數(shù)據(jù)復制到其他服務器上,以實現(xiàn)數(shù)據(jù)的備份、高可用和分
    的頭像 發(fā)表于 11-16 14:10 ?590次閱讀

    mysql主從復制三種模式

    MySQL主從復制是一種常見的數(shù)據(jù)同步方式,它可以實現(xiàn)將一個數(shù)據(jù)庫的更改同步到其他多個數(shù)據(jù)庫的功能。主從復制可以提高數(shù)據(jù)庫的可用性和性能,以
    的頭像 發(fā)表于 11-16 14:04 ?1160次閱讀

    MYSQL事務的底層原理詳解

    在事務的實現(xiàn)機制上,MySQL 采用的是 WAL:Write-ahead logging,預寫式日志,機制實現(xiàn)的。
    的頭像 發(fā)表于 11-15 10:10 ?475次閱讀
    <b class='flag-5'>MYSQL</b>事務的底層原理詳解

    基于MySQL的鎖機制

    在數(shù)據(jù)庫系統(tǒng)中,為了保證數(shù)據(jù)的一致性和并發(fā)控制,鎖機制發(fā)揮著至關重要的作用。尤其在關系型數(shù)據(jù)庫MySQL中,其獨特的鎖機制設計更是贏得了許多開發(fā)者的喜愛。 本文將詳細探討
    的頭像 發(fā)表于 09-30 11:16 ?737次閱讀