1. 程式人生 > >MySQL主從復制-GTID原理

MySQL主從復制-GTID原理

auto 其他 主鍵 中繼 next 設有 第一次啟動 相關 glob

一、MySQL 主從復制原理闡述

Mysql主從復制:簡單來說就是Mysql 同步,Ab 復制等,主從復制是單向的,只能從 Master 復制到 Slave 上,延時基本上是毫秒級別的(排除網絡延遲等問題)。一組復制結構中可以有多個Slave,對於 Master一般場景推薦只有一個,【根據您的業務進行調配,主主復制、延遲復制等】

Mysql 傳統復制是基於 Mysql 二進制文件(Mysql-Bin.000001),加上對應日誌文件中每個事件的偏移量位置點(Postion)。

MySQL主從復制 三個線程來實現:

主庫: Binlog Dump
從庫: IoSql 線程

技術分享圖片

Mysql同步原理簡述:

  1. Master 所有數據庫變更寫進 Binary Log, 主庫線程 Binlog Dump 把 Binary Log 內容發送到從庫 Slave 上(Slave 被動接受數據,不是主動去獲取)。
  2. Slave Io 線程讀取 Master 上 Binary Log 日誌信息,把接受到的 Binary Log 日誌寫到本地中繼日誌 Relay Log
  3. Slave Sql 線程讀取 Ralay Log 日誌內容寫入本地數據庫實例

二、MySQL 異步復制架構中 GTID 復制的原理闡述

2.1 GTID 的概述:

1、全局事物標識:global transaction identifieds。

2、GTID 事物是全局唯一性的,且一個事務對應一個 GTID

3、一個 GTID 在一個服務器上只執行一次,避免重復執行導致數據混亂或者主從不一致。

4、GTID 用來代替classic的復制方法,不在使用 binlog+pos 開啟復制。而是使用 master_auto_postion=1 的方式自動匹配 GTID 斷點進行復制

5、MySQL-5.6.5 開始支持的,MySQL-5.6.10 後開始完善。

6、在傳統的 slave 端,binlog 是不用開啟的,但是在 GTID 中,slave 端的 binlog 是必須開啟的,目的是記錄執行過的 GTID(強制);但是從 5.7.5 版本開始無需在 GTID 模式下啟用參數 log_slave_updates

2.2 GTID 的組成部分:

  • GTID = source_id:transaction_id

  • source_id 正常即是 server_uuid,在第一次啟動時生成(函數 generate_server_uuid),並持久化到 DATADIR/auto.cnf 文件裏。

  • transaction_id 是順序化的序列號(sequence number),在每臺 MySQL 服務器上都是從 1 開始自增長的序列,是事務的唯一標識。例如:3E11FA47-71CA-11E1-9E33-C80AA9429562:23

  • GTID 的集合(GTIDs)可以用 source_id+transaction_id 範圍表示,例如:3E11FA47-71CA-11E1-9E33-C80AA9429562:1-18

  • 復雜一點的:如果這組 GTIDs 來自不同的 source_id,各組 source_id 之間用逗號分隔;如果事務序號有多個範圍區間,各組範圍之間用冒號分隔,例如:3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5:11-18,2C256447-3F0D-431B-9A12-575BB20C1507:1-27

2.3 GTID 如何產生

  • GTID 的生成受 gtid_next 控制。

  • 在 Master 上,gtid_next 是默認的 AUTOMATIC,即 GTID 在每次事務提交時自動生成。它從當前已執行的 GTID 集合(即 gtid_executed)中,找一個大於 0 的未使用的最小值作為下個事務 GTID。同時將 GTID 寫入到 binlog(set gtid_next 記錄),在實際的更新事務記錄之前。

  • 在 Slave 上,從 binlog 先讀取到主庫的 GTID(即 set gtid_next 記錄),而後執行的事務采用該 GTID。

2.4 GTID 相關的變量

GTID_EXECUTED

#表示已經在該實例上執行過的事務; 執行 RESET MASTER 會將該變量置空; 我們還可以通過設置 GTID_NEXT 在執行一個空事務,來影響 GTID_EXECUTED

GTID_PURGED

#已經被刪除了 binlog 的事務,它是 GTID_EXECUTED 的子集,只有在 GTID_EXECUTED 為空時才能設置該變量,修改 GTID_PURGED 會同時更新 GTID_EXECUTED 和 GTID_PURGED 的值。

GTID_OWNED

#表示正在執行的事務的 gtid 以及對應的線程 ID。

GTID_NEXT

#SESSION 級別變量,表示下一個將被使用的 GTID。

2.5 GTID 比傳統復制的優勢與限制:

GTID優勢

更簡單的實現 failover,不用以前那樣在需要找 log_file 和 log_Pos。
更簡單的搭建主從復制。
復制集群有一個統一的方式識別復制位置,給集群管理帶來了便利。
正常情況下,GTID 是連續沒有空洞的,因此主從庫出現數據沖突時,可以用添加空事物的方式進行跳過。

GTID的限制:

1、在一個事務裏面混合使用引擎,如 Innodb(支持事務)、MyISAM(不支持事務), 造成多個 GTIDs 和同一個事務相關聯出錯
2、CREATE TABLE…..SELECT 不能使用,該語句產生的兩個 event 在某一情況 會使用同一個 GTID(同一個 GTID 在 slave 只能被使用一次)
       1th event:創建表語句 create table
       2th event:插入數據語句 insert
3、CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE 不能在事務內使用 (啟用了–enforce-gtid-consistency 參數)。

三、GTID 的工作原理:

master 更新數據時,會在事務前產生 GTID,`一同記錄到 binlog 日誌中`。
slave 端的 i/o 線程將變更的 binlog,寫入到本地的 relay log 中,讀取值是根據`gitd_next變量`,告訴我們slave下一個執行哪個GTID。
sql 線程從 relay log 中獲取 GTID,然後對比 slave 端的 binlog 是否有記錄。
如果有記錄,說明該 GTID 的事務已經執行,slave 會忽略。
如果沒有記錄,slave 就會從 relay log 中執行該 GTID 的事務,並記錄到 binlog。
在解析過程中會判斷是否有主鍵,如果沒有就用二級索引,如果沒有二級索引就用全部掃描。

3.1 pos 與 GTID 有什麽區別?

兩者都是日誌文件裏事件的一個標誌,如果將整個 mysql 集群看作一個整體,pos就是局部的,GTID就是全局的.
技術分享圖片
上圖就是一個 mysql 節點的集群,一主兩從,在 master,slave1,slave2 日誌文件裏的 pos,都各不相同,就是一個 event,在 master 的日誌裏,pos 可能是 700,而在 slave1,slave2 裏,pos 可能就是 300,400 了,因為眾多 slave 也可能不是同時加入集群的,不是從同一個位置進行同步.

而 GTID,在 master,slave1,slave2 各自的日誌文件裏,同一個 event 的 GTID 值都是一樣的.

3.2 為什麽要有這個區分呢?

大家都知道,這整個集群架構的節點,通常情況下,是 master 在工作,其他兩個結點做備份,而且,各個節點的機器,性能不可能完全一致,所以,在做備份時,備份的速度就不一樣,當 master 突然宕掉之後,馬上會啟用從節點機器,接管 master 的工作,當有多個從節點時,選擇備份日誌文件最接近 master 的那個節點;

現在就出現情況了,當 salve1 變成主節點,那slave2就應該從 slave1 去獲取日誌文件,進行同步.
技術分享圖片

大家來想想這個問題
如果使用的是pos,三者的pos不一致,slave2 怎麽去獲取它當前要同步的事件在 slave1 裏的 pos 呢?????????

所以就有了GTID全局的,將所有節點對於同一個 event 的標記完全一致,當 master 宕掉之後,slave2 根據同一個 GTID 直接去讀取 slave1 的日誌文件,繼續同步.

四、MySQL經典主從配置實戰

4.1 核心配置 my.cnf

[mysqld]
log-bin
server-id
gtid_mode=off #禁掉 gtid

4.2 添加主從復制用戶

grant replication slave on *.* to ‘repl‘@‘%‘ identified by ‘qiuyuetao‘;
flush privileges;

技術分享圖片

4.3 添加一個新的從庫

獲取主庫上一個帶 binlog 及 pos 偏移量的備份

在從庫上恢復後

>change master to
master_host=‘192.168.199.117‘,
master_user=‘slave‘,
master_port=7000,
master_password=‘slavepass‘,
master_log_file=‘mysql-bin.000008‘,
master_log_pos=896;

>start slave;
>show slave status\G;

跳過復制錯誤

stop slave;
set global sql_slave_skip_counter=1;
start slave;
show slave status\G;

如果出現錯誤代碼,那麽一般錯誤,可以跳過,具體哪些錯誤代碼可以跳,哪些不能調,後續我會在專門寫一篇文章。

五、GTID 配置

所有節點上都要進行設置
vim /etc/my.cnf

[mysqld]
#GTID:
gtid_mode=on    #開啟 GTID
enforce-gtid-consistency=on
#binlog
log-bin=mysql-bin   #開啟二進制文件系統
server-id=1    #必須為 1-231 之間的一個正整數值,各個值節點不能一致
log-slave-updates=1      # 5.7.5 版本開始無需在 GTID 模式下啟用參數 log_slave_updates

在從節點上 mysql 設置:

mysql>change master to master_host=‘xxxxxxx‘,master_user=‘xxxxxx‘,master_password=‘xxxxx‘,MASTER_AUTO_POSITION=1;
mysql> start slave;
mysql> stop slave io_thread; #重啟 io 線程,刷新狀態
mysql> start slave io_thread;

註意事項:

master_host,master_user,master_password與經典的Mysql主從復制一致。
唯一不一致的是使用了 MASTER_AUTO_POSITION 參數
當使用 MASTER_AUTO_POSITION 參數的時候,MASTER_LOG_FILE,MASTER_LOG_POS 參數不能使用
如果想要從 GTID 配置回 pos,再次執行這條語句,不過把 MASTER_AUTO_POSITION 置為 0

GTID添加從庫有兩種方法:

1.如果 master 所有的 binlog 還在,安裝 slave 後,直接 change master 到 master

原理: 直接獲取 master 所有的 gtid 並執行
優點: 簡單
缺點: 如果 binlog 太多,數據完全同步需要的時間較長,並且需要 master 一開始就啟用了 GTID
總結:適用於 master 也是新建不久的情況

2.通過 master 或者其它 slave 的備份搭建新的 slave.

原理:獲取 master 的數據和這些數據對應的 GTID 範圍,然後通過在 slave 設置@@GLOBAL.GTID_PURGED 從而跳過備份包含的 GTID
優點: 可以避免第一種方法中的不足
缺點: 操作相對復雜
總結:適用於擁有較大數據集的情況

GTID 添加從庫:

1、mysqldump

在備份的時候需要指定–master-data

導出的語句中包括:

set @@GLOBAL.GTID_PURGED=’c8d960f1-83ca-11e5-a8eb-000c29ea831c:1-745497′;
#恢復時,需要先在slave上執行一個
reset master;
#再執行
change master to

2、percona xtrabackup

xtrabackup_binlog_info 包含了 GTID 在信息

做從庫恢復後,需要手工設置:

set@@GLOBAL.GTID_PURGED=‘c8d960f1-83ca-11e5-a8eb-000c29ea831c:1-745497‘;

恢復後,執行 change master to

>change master to
master_host=‘192.168.199.117‘,
master_user=‘slave‘,
master_port=7000,
master_password=‘slavepass‘,
master_auto_position=1;

錯誤跳過

stop slave;
set gtid_next=‘xxxxxxxx:N‘;
begin;
commit;
set gtid_next=‘automatic‘;
start slave;

技術分享圖片

GTID的限制總結:
不支持非事務引擎(從庫報錯,stop slave; start slave; 忽略)
不支持 create table … select 語句復制(主庫直接報錯)
不允許在一個 SQL 同時更新一個事務引擎和非事務引擎的表
在一個復制組中,必須要求統一開啟CTID或是關閉GTID
開啟DTID需要重啟(5.7中可能不需要)
開啟DTID後,就不在使用原來的傳統的復制方式
對於create temporary table 和drop temporary table語句不支持
不支持sql_slave_skip_counter

六、MySQL半同步復制

MySQL 復制默認是異步復制,Master 將事件寫入 binlog,但並不知道 Slave 是否或何時已經接收且已處理。在異步復制的機制的情況下,如果 Master 宕機,事務在 Master 上已提交,但很可能這些事務沒有傳到任何的 Slave 上。假設有 Master->Salve 故障轉移的機制,此時 Slave 也可能會丟失事務

官方半同步復制的概念:

1.當 Slave 主機連接到 Master 時,能夠查看其是否處於半同步復制的機制。

2.當 Master 上開啟半同步復制的功能時,至少應該有一個 Slave 開啟其功能。此時,一個線程在 Master 上提交事務將受到阻塞,直到得知一個已開啟半同步復制功能的 Slave 已收到此事務的所有事件,或等待超時。

3.當一個事務的事件都已寫入其 relay-log 中且已刷新到磁盤上,Slave 才會告知已收到。

4.如果等待超時,也就是 Master 沒被告知已收到,此時 Master 會自動轉換為異步復制的機制。當至少一個半同步的 Slave 趕上了,Master 與其 Slave 自動轉換為半同步復制的機制。

5.半同步復制的功能要在 Master,Slave 都開啟,半同步復制才會起作用;否則,只開啟一邊,它依然為異步復制。

同步(社區增強半同步),異步,半同步復制的比較:

同步復制:Master 提交事務,直到事務在所有的 Slave 都已提交,此時才會返回客戶端,事務執行完畢。缺點:完成一個事務可能會有很大的延遲

異步復制:當 Slave 準備好才會向 Master 請求 binlog。
缺點:不能保證一些事件都能夠被所有的 Slave 所接收。

半同步復制:半同步復制工作的機制處於同步和異步之間,Master 的事務提交阻塞,只要一個 Slave 已收到該事務的事件且已記錄。它不會等待所有的 Slave 都告知已收到,且它只是接收,並不用等其完全執行且提交。

解決主庫不關心日誌是否被從庫讀到

半同步,開啟後嚴重影響性能

半同步配置,在master和slave上都配置

master
[mysqld]
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=1000     #1s

slave
[mysqld]
rpl_semi_sync_slave_enabled=1 復制參數

MySQL主從復制-GTID原理