1. 程式人生 > >MySQL主從複製-GTID原理

MySQL主從複製-GTID原理

一、MySQL 主從複製原理闡述

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

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

MySQL主從複製 三個執行緒來實現:

主庫: Binlog Dump
從庫: IoSql 執行緒

MySQL主從複製-GTID原理

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主從複製-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 去獲取日誌檔案,進行同步.
MySQL主從複製-GTID原理

大家來想想這個問題
如果使用的是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;

MySQL主從複製-GTID原理

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 在資訊

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

[email protected]@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;

MySQL主從複製-GTID原理

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 複製引數