內容
- 復制方式有哪些?
- 復制基本過程是什么?
- binlog
- binlog格式有那幾種?他們分別有什么問題?
- 和binlog文件密切相關的參數(shù)有哪些?
- binlog event有哪些?它們分別代表什么?
- 如果在程序模擬一個slave接管binlog?
- 程序模擬slave,解析binlog要注意哪些問題?
- GTID
- gtid什么?
- gtid復制原理什么?
- gtid復制要著重關注哪些系統(tǒng)參數(shù)?
- mariadb gtid
一 復制的方式有哪些
異步
1master在commit一個事務后,就返回成功信息給客戶端,不關心binlog是否成功發(fā)送給slave節(jié)點;半異步
1 以插件的形式實現(xiàn)的,需要 [加載/開啟semi-sync插件] https://www.orczhou.com/index.php/2011/06/mysql-5-5-semi-sync-replication-setup-config/;
2 開啟半異步方式后,master在提交一個事務后,會等待一個slave成功接收binlog,并寫入自己relay lgo后,返回一個ack確認包給master,master收到這個確認包才會把事務提交成功信息告訴給客戶端;
3 mysql5.7改進了半同步復制,引入了無數(shù)據(jù)丟失的半同步方案:Loss-Less半同步復制,引入了一個參數(shù):rpl_semi_sync_master_wait_point, 這個參數(shù)有兩種取值:1) AFTER_SYNC , 這個是新的半同步方案,主庫在收到slave的ack信號之后,才完成事務binlog和redo 二階段提交的commit操作。2) AFTER_COMMIT, 這個是老的半同步方案,主庫在完成事務binlog和redo 二階段提交的commit操作后,才等待slave的ack信號;mysql半同步復制同步
1 master會等所有slave 都寫入成功事務后,才會返回事務成功的消息給客戶端;group replication
1 mysql group replication解析:Mysql MGR解析
二 異步復制基本過程
2.1主從同步涉及的幾個主要關鍵點:
- binlog: 數(shù)據(jù)變更存儲的二進制文件;
三個線程:
- 主庫dump線程,就要將binlog event發(fā)送給從庫;
- 從庫io線程,接收主庫的binlog event,然后將之寫入到reylog中;
- 從庫sql線程,從reylog中讀取binlog event,解析event,將主庫數(shù)據(jù)變更更新到從庫;
兩種binlog消費點記錄方式:
- 1 binlog文件+pos: 通過binlog文件和消費的位置點記錄從庫讀取了那些event
- 2 gtid:從mysql 5.6之后支持gtid的方式進行同步,gtid是全局事務id,通過gtid可以代替?zhèn)魉蚥inlog name和pos的方法完成同步;
2.2 復制過程:
1.從庫change to master,連接上master,并發(fā)送相關賬號 密碼 binlog 同步位置點等給master;
2.master收到從庫來的binlog接收消息,開啟dump線程,dump線程將binlog event從1中的位置點源源不斷的發(fā)送給從庫;
3.從庫io線程將接收到binlog event寫入到relay-log;
4.從庫sql線程從relay-log消費binlog event,解析event,將變更同步到從數(shù)據(jù)庫,完成同步;
具體實現(xiàn)步驟:
1. 主庫鎖庫: FLUSH TABLES WITH READ LOCK,防止在dumper過程中主庫有數(shù)據(jù)寫入;
2. dump主庫全量數(shù)據(jù)到sql;
3. 查看主庫現(xiàn)在的binlog文件和位置(找出File和Position) ,并記錄好這個信息;
show master status;
4. 主庫解鎖-》UNLOCK TABLES;
5. 從庫全量同步主庫的數(shù)據(jù);
6. 從庫全量同步主庫數(shù)據(jù)完畢,進行檢查,show slave status \G;
7. 如果數(shù)據(jù)一致,開始增量同步,change master,連接上master,并發(fā)3中記錄的binlog位置信息發(fā)送給master;
CHANGE MASTER TO
MASTER_HOST='....',
MASTER_USER='....',
MASTER_PASSWORD='..',
MASTER_LOG_FILE='mysql-bin.0000001',
MASTER_LOG_POS=1;
8.start slave
注:更詳細步驟可以看:[http://m.itdecent.cn/p/7bfacf149d55](http://m.itdecent.cn/p/7bfacf149d55)
三 binlog
3.1 binlog查看基本語句
show master status :查看主當前使用的binlog文件、寫入的位置點、gtid等
show binary logs: 查看binlog 列表;
show binlog events in 'binlog.000003': 查看某個binlog 文件的詳細event;
flush logs: 從新開始寫一個新的binlog;
mysqlbinlog --base64-output=DECODE-ROWS -v binlog.000001 :查看binlog詳細內容
3.2 binlog 有哪些類型?
binlog 有三種格式, 由binlog_format參數(shù)指定,binlog_format=ROW/STATEMENT/MIXED
STATEMENT:
記錄修改數(shù)據(jù)的sql語句到binlog中。
優(yōu)點:并不需要記錄每一條sql語句和每一行的數(shù)據(jù)變化,減少了binlog日志量,節(jié)約IO,提高性能。
缺點:在某些情況下會導致master-slave中的數(shù)據(jù)不一致(如sleep()函數(shù), last_insert_id(),以及user-defined functions(udf)等會出現(xiàn)問題);ROW模式(RBR)
不記錄具體的sql語句,僅記錄哪條數(shù)據(jù)被修改了,修改成什么樣了;
優(yōu)點:不會出現(xiàn)某些特定情況下的存儲過程、或function、或trigger的調用和觸發(fā)無法被正確復制的問題;
缺點:是會產生大量的日志,尤其是alter table的時候會讓日志暴漲。MIXED模式(MBR)
以上兩種模式的混合使用,一般的復制使用STATEMENT模式保存binlog,對于STATEMENT模式無法復制的操作使用ROW模式保存binlog,MySQL會根據(jù)執(zhí)行的SQL語句選擇日志保存方式。
3.3 和binlog相關的主要參數(shù)有哪些?
-
sync_binlog:控制了事務提交時,binlog刷盤策略
sync_binlog=0 的時候,表示每次提交事務,都只寫到文件系統(tǒng)的 page cache,不 fsync,并沒有把數(shù)據(jù)持久化到磁盤
sync_binlog=1 的時候,表示每次提交事務都會執(zhí)行 fsync,都會持久化到磁盤;
sync_binlog=N(N>1) 的時候,表示每次提交事務都 寫到文件系統(tǒng)的 page cache,但累積 N 個事務后才 fsync。 - binlog_format: 控制binlog格式;
-
binlog_row_image: 控制binlog在row格式下,每行數(shù)據(jù)的在binlog中記錄的信息類型;
full:記錄更的行的所有的列值信息,默認值。
minimal:僅僅記錄被更改的以及能夠唯一識別數(shù)據(jù)行的列值;
noblob:記錄所有的列值,但是BLOB 與 TEXT列除外(如未更改)。
3.3 binlog event
FORMAT_DESCRIPTION_EVENT
是binlog version 4中為了取代之前版本中的START_EVENT_V3事件而引入的。它是binlog文件中的第一個事件,而且,該事件只會在binlog中出現(xiàn)一次。MySQL根據(jù)FORMAT_DESCRIPTION_EVENT的定義來解析其它事件。它通常指定了MySQL Server的版本,binlog的版本,該binlog文件的創(chuàng)建時間。PREVIOUS_GTIDS_LOG_EVENT
開啟GTID模式后,每個binlog開頭都會有一個PREVIOUS_GTIDS_LOG_EVENT事件,它的值是上一個binlog的PREVIOUS_GTIDS_LOG_EVENT+GTID_LOG_EVENT,在數(shù)據(jù)庫重啟的時候,需要重新填充gtid_executed的值,該值即是最新一個binlog的PREVIOUS_GTIDS_LOG_EVENT+GTID_LOG_EVENT。
例如:如果上一個binlog文件的PREVIOUS_GTIDS_LOG_EVENT是d4d6b3e6-235c-11eb-b3e4-e8bdd106a08d:1-10,最后一個GTID_LOG_EVENT是d4d6b3e6-235c-11eb-b3e4-e8bdd106a08d:20, 那么下一個binlog 文件的PREVIOUS_GTIDS_LOG_EVENT是:d4d6b3e6-235c-11eb-b3e4-e8bdd106a08d:1-20-
GTID_LOG_EVENT
在啟用GTID模式后,MySQL實際上為每個事務都分配一個GTID,在每個事務開始前會先插入這個event,指定下一個事務的gtid值;
image.png QUERY_EVENT
QUERY_EVENT以文本的形式來記錄事務的操作。QUERY_EVENT類型的事件通常在以下幾種情況下使用:
- 事務開始時,執(zhí)行的BEGIN操作。
- STATEMENT格式中的DML操作(STATEMENT 增刪改)
- ROW格式中的DDL操作
用于row格式,在記錄DML語句的數(shù)據(jù)時,總會先寫入一個table_map_event,這種類型的event用于記錄表結構相關元數(shù)據(jù)信息,比如數(shù)據(jù)庫名稱,表名稱,表的字段類型,表的字段元數(shù)據(jù)等等
-
ROWS_EVENT
對于ROW格式的binlog,所有的DML語句都是記錄在ROWS_EVENT中。
ROWS_EVENT分為三種:WRITE_ROWS_EVENT,UPDATE_ROWS_EVENT,DELETE_ROWS_EVENT,分別對應insert,update和delete操作。
對于insert操作,WRITE_ROWS_EVENT包含了要插入的數(shù)據(jù);
對于update操作,UPDATE_ROWS_EVENT不僅包含了修改后的數(shù)據(jù),還包含了修改前的值。
對于delete操作,僅僅需要指定刪除的主鍵(在沒有主鍵的情況下,會給定所有列)
對于QUERY_EVENT事件,是以文本形式記錄DML操作的。而對于ROWS_EVENT事件,并不是文本形式,所以在通過mysqlbinlog查看基于ROW格式的binlog時,需要指定-vv --base64-output=decode-rows。
通過binlog_row_image參數(shù)控制是否在binlog event中顯示所有的字段值,包括有沒有變動過的;binlog_row_image有兩個取值;
- full: binlog中顯示所有的字段值,如下所示,delete時,第二字段沒有指定限制條件,也顯示出來;
- minimal: 只顯示有變動的列;
image.png XID_EVENT
在事務提交時,不管是STATEMENT還是ROW格式的binlog,都會在末尾添加一個XID_EVENT事件代表事務的結束。該事件記錄了該事務的ID,在MySQL進行崩潰恢復時,根據(jù)事務在binlog中的提交情況來決定是否提交存儲引擎中狀態(tài)為prepared的事務。ROTATE_EVENT
當binlog文件的大小達到max_binlog_size的值或者執(zhí)行flush logs命令時,binlog會發(fā)生切換,這個時候會在當前的binlog日志添加一個ROTATE_EVENT事件,用于指定下一個日志的名稱和位置。STOP_EVENT
當MySQL數(shù)據(jù)庫停止時,會在當前的binlog末尾添加一個STOP_EVENT事件表示數(shù)據(jù)庫停止。
四 gtid
4.1 gtid是什么
gtid全稱是Global Transaction Identifier,mysql5.6之后可以使用gtid代替以前的file_name和file_position的方式進行主從復制;
-
gtid長啥樣?
gtid由server_uuid和transaction_id組成,長這個樣子:dcb84b95-eb6c-11ea-9ab3-6c92bf64c50c:1- dcb84b95-eb6c-11ea-9aa3-6c92bf64c50c: server_uuid,在auto.cnf中配置,可以通過 show variables like '%uuid%'查看;
- 1:事務ID號全局遞增
gtid何時產生?
在一個事務提交時,會產生一個特殊的binlog event, 這個event類型是GTID_LOG_EVENT,這個event指定了下一個事務的gtid, 即:可以這樣理解,每個事務開始前會對應有一個GTID_LOG_EVENT類型的event
4.2 使用gtid進行主從復制
- gtid配置
MySQL 5.6
gtid_mode=ON#(必選) ,開啟gtid模式
log_bin=ON #(必選)
log-slave-updates=ON
enforce-gtid-consistency=ON #強制gtid一致性(必選), 保證gtid安全,因為開啟grid_mode以后,許多MySQL的SQL和GTID是不兼容的。比如開啟ROW 格式時,CREATE TABLE ... SELECT,在binlog中會形成2個不同的事務,GTID無法唯一
MySQL5.7.13 or higher
gtid_mode=ON(必選)
enforce-gtid-consistency=ON(必選)
log_bin=ON(可選)--高可用切換,最好設置ON
log-slave-updates=ON(可選)--高可用切換,最好設置ON
開啟gtid模式后,就可以使用gtid來進行主從復制,在從庫執(zhí)行以下語句就可以自動的進行復制:
mysql> CHANGE MASTER TO \
-> MASTER_HOST = '', \
-> MASTER_PORT = 3306, \
-> MASTER_USER = 'test', \
-> MASTER_PASSWORD = '', \
-> MASTER_AUTO_POSITION = 1;
4.3 gtid原理
- 使用gtid復制,主庫如何找點?
在change master后,從庫會計算Retrieved_Gtid_Set和Executed_Gtid_Set的并集(通過SHOW SLAVE STATUS可以查看),然后把這個GTID并集發(fā)送給主庫。主庫會使用從庫請求的GTID集合和自己的gtid_executed比較,把從庫GTID集合里缺失的事務全都發(fā)送給從庫。如果從庫缺失的GTID,已經被主庫pruge了,從庫報1236錯誤,IO線程中斷。
4.4 mariadb gtid復制
mariadb的gtid有domainId serverId和tranctionId組成,長domainId-serverId-tranctionId這個樣子,如下:0-2967541547-12869203,每個gtid event標識下一個事務event group所使用的全局事務id。mariadb可以通過如下語句一個slave加入某個master的備機中,進行主從復制:
CHANGE MASTER TO master_host="127.0.0.1", master_port=3306, master_user="root", master_use_gtid={ slave_pos | current_pos | no };
- 當master_use_gtid設置為current_pos時, slave加入主備復制時,主會把備機的gtid_current_pos作為開始復制binlog的起始點,一般情況下只有備機沒有自己的binlog時,才考慮這種方式,因為如果備機自己產生了binlog,如實例A一開始是slave,并且是只讀的實例,但是如果對實例A進行寫的操作,并且實例A的產生了自己的gtid,這個時候在用current_pos模式加入復制時,主就找不到實例A自己產生的gtid點了
- 當master_use_gtid設置為slave_pos時,主會把備機的gtid_slave_pos作為開始復制binlog的起止點,gtid_slave_pos記錄是實例A從其他master應用的event的最后一個gtid點,可以通過下面查看gtid各變量信息:
MariaDB [(none)]> show variables like '%gtid%';
+-------------------------+--------------------------------------------+
| Variable_name | Value |
+-------------------------+--------------------------------------------+
| gtid_binlog_pos | 0-2967541547-12869500 |
| gtid_binlog_state | 0-622864171-10710441,0-2967541547-12869500 |
| gtid_cleanup_batch_size | 64 |
| gtid_current_pos | 0-2967541547-12869500 |
| gtid_domain_id | 0 |
| gtid_ignore_duplicates | OFF |
| gtid_pos_auto_engines | |
| gtid_seq_no | 0 |
| gtid_slave_pos | 0-622864171-10710441 |
| gtid_strict_mode | OFF |
| last_gtid | |
| wsrep_gtid_domain_id | 0 |
| wsrep_gtid_mode | OFF |
+-------------------------+--------------------------------------------+
- gtid_binlog_pos: gtid_binlog_pos是一個只讀變量,變量是寫入二進制日志的最后一個事件組的gtid; reset master是會重置gtid_binlog_pos的,但是不會重置gtid_slave_pos;reset master后,因為gtid_current_pos是根據(jù)gtid_binlog_pos和gtid_slave_pos計算得來的,所以gtid_current_pos是有可能高于gtid_binlog_pos的;
- gtid_current_pos: gtid_current_pos是每個復制域應用到本實例的最新一個gtid,gtid_current_pos是根據(jù)gtid_binlog_pos和gtid_slave_pos計算得來的,當gtid_binlog_pos中的gtid的serverid和實例本身serverId相同并且序列號大于gtid_slave_pos時,gtid_current_pos取gtid_binlog_pos的值,反之則取gtid_slave_pos值,總之gtid_current_pos是在本實例執(zhí)行的最新的gtid,不管實例是作為主還是從;
- gtid_slave_pos: gtid_slave_pos記錄是實例A從其他master應用的event的最后一個gtid點;

