Mysql基礎——復制

內容

  • 復制方式有哪些?
  • 復制基本過程是什么?
  • 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類型的事件通常在以下幾種情況下使用:

  1. 事務開始時,執(zhí)行的BEGIN操作。
  2. STATEMENT格式中的DML操作(STATEMENT 增刪改)
  3. 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點;

引用

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容