天天看點

MySQL主從複制-GTID原理

一、MySQL 主從複制原理闡述

Mysql主從複制:簡單來說就是Mysql 同步,Ab 複制等,主從複制是

單向

的,隻能從 Master 複制到 Slave 上,延時基本上是毫秒級别的(排除網絡延遲等問題)。一組複制結構中可以有多個Slave,對于 Master一般場景推薦隻有一個,【根據您的業務進行調配,主主複制、延遲複制等】

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

同步更新部落格:www.dgstack.cn

MySQL主從複制 三個線程來實作:

主庫:

Binlog Dump

從庫:

Io

Sql

線程

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

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

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;           
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
[mysqld]
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=1000     #1s

slave
[mysqld]
rpl_semi_sync_slave_enabled=1 複制參數           

繼續閱讀