MySQL 主從復制原理不再難


上篇我們分析過 Binlog 日志的作用以及存儲原理,感興趣的可以翻閱:

一文帶你了解 Binlog 日志

Binlog 日志主要作用是數據恢復和主從復制。本身就是二進制格式的日志文件,網絡傳輸無需進行協議轉換。MySQL 集群的高可用,負載均衡,讀寫分離等功能都是基於Binlog 來實現的。

MySQL 主從復制主流架構模型

我們基於 Binlog 可以復制出一台 MySQL 服務器,也可以復制出多台,取決於我們想實現什么功能。主流的系統架構有如下幾種方式:

1. 一主一從 / 一主多從

1

一主一從和一主多從是最常見的主從架構方式,一般實現主從配置或者讀寫分離都可以采用這種架構。

如果是一主多從的模式,當 Slave 增加到一定數量時,Slave 對 Master 的負載以及網絡帶寬都會成為一個嚴重的問題。

2. 多主一從

1

MySQL 5.7 開始支持多主一從的模式,將多個庫的數據備份到一個庫中存儲。

3. 雙主復制

理論上跟主從一樣,但是兩個MySQL服務器互做對方的從,任何一方有變更,都會復制對方的數據到自己的數據庫。雙主適用於寫壓力比較大的業務場景,或者 DBA 做維護需要主從切換的場景,通過雙主架構避免了重復搭建從庫的麻煩。(主從相互授權連接,讀取對方binlog日志並更新到本地數據庫的過程;只要對方數據改變,自己就跟着改變)

4. 級聯復制

1

級聯模式下因為涉及到的 slave 節點很多,所以如果都連在 master 上對主服務器的壓力肯定是不小的。所以部分 slave 節點連接到它上一級的從節點上。這樣就緩解了主服務器的壓力。

級聯復制解決了一主多從場景下多個從庫復制對主庫的壓力,帶來的弊端就是數據同步延遲比較大。

MySQL 主從復制原理

MySQL 主從復制涉及到三個線程:

一個在主節點的線程:log dump thread

從庫會生成兩個線程:一個 I/O 線程,一個 SQL 線程

如下圖所示:

4

主庫會生成一個 log dump 線程,用來給從庫 I/O 線程傳 Binlog 數據。

從庫的 I/O 線程會去請求主庫的 Binlog,並將得到的 Binlog 寫到本地的 relay log (中繼日志)文件中。

SQL 線程,會讀取 relay log 文件中的日志,並解析成 SQL 語句逐一執行。

主節點 log dump 線程

當從節點連接主節點時,主節點會為其創建一個 log dump 線程,用於發送和讀取 Binlog 的內容。在讀取 Binlog 中的操作時,log dump 線程會對主節點上的 Binlog 加鎖;當讀取完成發送給從節點之前,鎖會被釋放。主節點會為自己的每一個從節點創建一個 log dump 線程

從節點I/O線程

當從節點上執行start slave命令之后,從節點會創建一個 I/O 線程用來連接主節點,請求主庫中更新的Binlog。I/O 線程接收到主節點的 log dump 進程發來的更新之后,保存在本地 relay-log(中繼日志)中。

relay log

這里又引申出一個新的日志概念。MySQL 進行主主復制或主從復制的時候會在要復制的服務器下面產生相應的 relay log。

relay log 是怎么產生的呢?

從服務器 I/O 線程將主服務器的 Binlog 日志讀取過來,解析到各類 Events 之后記錄到從服務器本地文件,這個文件就被稱為 relay log。然后 SQL 線程會讀取 relay log 日志的內容並應用到從服務器,從而使從服務器和主服務器的數據保持一致。中繼日志充當緩沖區,這樣 master 就不必等待 slave 執行完成才發送下一個事件。

relay log 相關參數查詢:

mysql>  show variables like '%relay%';
+---------------------------+------------------------------------------------------------+
| Variable_name             | Value                                                      |
+---------------------------+------------------------------------------------------------+
| max_relay_log_size        | 0                                                          |
| relay_log                 | yangyuedeMacBook-Pro-relay-bin                             |
| relay_log_basename        | /usr/local/mysql/data/yangyuedeMacBook-Pro-relay-bin       |
| relay_log_index           | /usr/local/mysql/data/yangyuedeMacBook-Pro-relay-bin.index |
| relay_log_info_file       | relay-log.info                                             |
| relay_log_info_repository | TABLE                                                      |
| relay_log_purge           | ON                                                         |
| relay_log_recovery        | OFF                                                        |
| relay_log_space_limit     | 0                                                          |
| sync_relay_log            | 10000                                                      |
| sync_relay_log_info       | 10000                                                      |
+---------------------------+------------------------------------------------------------+
11 rows in set (0.03 sec)

max_relay_log_size

標記 relay log 允許的最大值,如果該值為 0,則默認值為 max_binlog_size(1G);如果不為 0,則max_relay_log_size 則為最大的 relay_log 文件大小。

relay_log_purge

是否自動清空不再需要中繼日志時。默認值為1(啟用)。

relay_log_recovery

當 slave 從庫宕機后,假如 relay log 損壞了,導致一部分中繼日志沒有處理,則自動放棄所有未執行的 relay log,並且重新從 master 上獲取日志,這樣就保證了 relay log 的完整性。默認情況下該功能是關閉的,將 relay_log_recovery 的值設置為 1 時,可在 slave 從庫上開啟該功能,建議開啟。

relay_log_space_limit

防止中繼日志寫滿磁盤,這里設置中繼日志最大限額。但此設置存在主庫崩潰,從庫中繼日志不全的情況,不到萬不得已,不推薦使用。

sync_relay_log

這個參數和 Binlog 中的 sync_binlog作用相同。當設置為 1 時,slave 的 I/O 線程每次接收到 master 發送過來的 Binlog 日志都要寫入系統緩沖區,然后刷入 relay log 中繼日志里,這樣是最安全的,因為在崩潰的時候,你最多會丟失一個事務,但會造成磁盤的大量 I/O。

當設置為 0 時,並不是馬上就刷入中繼日志里,而是由操作系統決定何時來寫入,雖然安全性降低了,但減少了大量的磁盤 I/O 操作。這個值默認是 0,可動態修改,建議采用默認值。

sync_relay_log_info

當設置為 1 時,slave 的 I/O 線程每次接收到 master 發送過來的 Binlog 日志都要寫入系統緩沖區,然后刷入 relay-log.info 里,這樣是最安全的,因為在崩潰的時候,你最多會丟失一個事務,但會造成磁盤的大量 I/O。當設置為 0 時,並不是馬上就刷入 relay-log.info 里,而是由操作系統決定何時來寫入,雖然安全性降低了,但減少了大量的磁盤 I/O 操作。這個值默認是0,可動態修改,建議采用默認值。

從節點 SQL 線程

SQL 線程負責讀取 relay log 中的內容,解析成具體的操作並執行,最終保證主從數據的一致性。

對於每一個主從連接,都需要這三個進程來完成。當主節點有多個從節點時,主節點會為每一個當前連接的從節點建一個 log dump 進程,而每個從節點都有自己的 I/O 進程,SQL 進程。

從節點用兩個線程將從主庫拉取更新和執行分成獨立的任務,這樣在執行同步數據任務的時候,不會降低讀操作的性能。比如,如果從節點沒有運行,此時 I/O 進程可以很快從主節點獲取更新,盡管 SQL 進程還沒有執行。如果在 SQL 進程執行之前從節點服務停止,至少 I/O 進程已經從主節點拉取到了最新的變更並且保存在本地 relay log 中,當服務再次起來之后就可以完成數據的同步。

要實施復制,首先必須打開 Master 端的 Binlog 功能,否則無法實現。

因為整個復制過程實際上就是 Slave 從 Master 端獲取該日志然后再在自己身上完全順序的執行日志中所記錄的各種操作。如下圖所示:

5

復制的基本過程
  1. 在從節點上執行 sart slave 命令開啟主從復制開關,開始進行主從復制。從節點上的 I/O 進程連接主節點,並請求從指定日志文件的指定位置(或者從最開始的日志)之后的日志內容。
  2. 主節點接收到來自從節點的 I/O 請求后,通過負責復制的 I/O 進程(log Dump Thread)根據請求信息讀取指定日志指定位置之后的日志信息,返回給從節點。返回信息中除了日志所包含的信息之外,還包括本次返回的信息的 Binlog file 以及 Binlog position(Binlog 下一個數據讀取位置)。
  3. 從節點的 I/O 進程接收到主節點發送過來的日志內容、日志文件及位置點后,將接收到的日志內容更新到本機的 relay log 文件(Mysql-relay-bin.xxx)的最末端,並將讀取到的 Binlog文件名和位置保存到master-info 文件中,以便在下一次讀取的時候能夠清楚的告訴 Master :“ 我需要從哪個 Binlog 的哪個位置開始往后的日志內容,請發給我”。
  4. Slave 的 SQL 線程檢測到relay log 中新增加了內容后,會將 relay log 的內容解析成在能夠執行 SQL 語句,然后在本數據庫中按照解析出來的順序執行,並在 relay log.info 中記錄當前應用中繼日志的文件名和位置點。

MySQL 基於 Binlog 主從復制的模式介紹

MySQL 主從復制默認是 異步的模式。MySQL增刪改操作會全部記錄在 Binlog 中,當 slave 節點連接 master 時,會主動從 master 處獲取最新的 Binlog 文件。並把 Binlog 存儲到本地的 relay log 中,然后去執行 relay log 的更新內容。

異步模式 (async-mode)

異步模式如下圖所示:

6

這種模式下,主節點不會主動推送數據到從節點,主庫在執行完客戶端提交的事務后會立即將結果返給給客戶端,並不關心從庫是否已經接收並處理,這樣就會有一個問題,主節點如果崩潰掉了,此時主節點上已經提交的事務可能並沒有傳到從節點上,如果此時,強行將從提升為主,可能導致新主節點上的數據不完整。

半同步模式(semi-sync)

介於異步復制和全同步復制之間,主庫在執行完客戶端提交的事務后不是立刻返回給客戶端,而是等待至少一個從庫接收到並寫到 relay log 中才返回成功信息給客戶端(只能保證主庫的 Binlog 至少傳輸到了一個從節點上),否則需要等待直到超時時間然后切換成異步模式再提交。

7

相對於異步復制,半同步復制提高了數據的安全性,一定程度的保證了數據能成功備份到從庫,同時它也造成了一定程度的延遲,但是比全同步模式延遲要低,這個延遲最少是一個 TCP/IP 往返的時間。所以,半同步復制最好在低延時的網絡中使用。

半同步模式不是 MySQL 內置的,從 MySQL 5.5 開始集成,需要 master 和 slave 安裝插件開啟半同步模式。

全同步模式

指當主庫執行完一個事務,然后所有的從庫都復制了該事務並成功執行完才返回成功信息給客戶端。因為需要等待所有從庫執行完該事務才能返回成功信息,所以全同步復制的性能必然會收到嚴重的影響。

Binlog 復制實戰

配置 my.cnf

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

添加主從復制用戶:

grant replication slave on *.* to 'repl'@'%' identified by 'gtidUser';
flush privileges;

然后我們新增一個從庫。

接着我們用命令行的方式來加載主庫的 Binlog 到從庫,這里可以設置指定的 binlog 文件和位移值。在從庫執行以下命令:

mysql>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=0;

mysql>start slave;
mysql>show slave status\G;

復制過程中如果出現代碼性錯誤,個人根據錯誤日志來決定是否要跳過錯誤繼續執行:

mysql>stop slave;
mysql>set global sql_slave_skip_counter=1;

主從復制可能會出現的問題

Slave 同步延遲

因為 Slave 端是通過 I/O thread 單線程來實現數據解析入庫;而 Master 端寫 Binlog 由於是順序寫效率很高,當主庫的 TPS 很高的時候,必然 Master 端的寫效率要高過 Slave 端的讀效率,這時候就有同步延遲的問題。

I/O Thread 的同步是基於庫的,即同步幾個庫就會開啟幾個 I/O Thread。

可以通過 show slave status 命令查看 Seconds_Behind_Master 的值來看是否出現同步延遲,這個值代表主從同步延遲的時間,值越大說明延遲越嚴重。值為 0 為正常情況,正值表示已經出現延遲,數字越大從庫落后主庫越多。

基於 Binlog 的復制方式肯定有這種問題,MySQL 官方也意識到,單線程不如多線程強,所以在 MySQL 5.7 版本引入了基於組提交的並行復制(官方稱為Enhanced Multi-threaded Slaves,即MTS),設置參數:

slave_parallel_workers>0 即可,並且 global.slave_parallel_type=‘LOGICAL_CLOCK’

即可支持一個 schema(庫) 下,slave_parallel_workers個 worker 線程並發執行 relay log 中主庫提交的事務。

其核心思想:

一個組提交的事務都是可以並行回放(配合binary log group commit);

slave 機器的 relay log 中 last_committed 相同的事務(sequence_num不同)可以並發執行。其中,變量 slave-parallel-type 可以有兩個值:

  1. DATABASE 默認值,基於庫的並行復制方式
  2. LOGICAL_CLOCK,基於組提交的並行復制方式

MySQL 5.7 開啟 MTS 很簡單,只需要在 Slave 從數據庫的 my.cnf 文件中如下配置即可:

# slave
 slave-parallel-type=LOGICAL_CLOCK
 slave-parallel-workers=8        #一般建議設置4-8,太多的線程會增加線程之間的同步開銷
 master_info_repository=TABLE
 relay_log_info_repository=TABLE
 relay_log_recovery=ON

當然多線程帶來的並行復制方案也有很多實現難點,比如事務都是有序執行的,如果並行回放會不會存在執行數據錯亂的問題。這些問題就不在本節解釋,大家有興趣可以繼續深究。

新一代主從復制模式 - GTID 復制模式

在傳統的復制里面,當發生故障,需要主從切換,需要找到 Binlog 和 位點信息,恢復完成數據之后將主節點指向新的主節點。在 MySQL 5.6 里面,提供了新的數據恢復思路,只需要知道主節點的 IP、端口以及賬號密碼就行,因為復制是自動的,MySQL 會通過內部機制 GTID 自動找點同步。

基於 GTID 的復制是 MySQL 5.6.5 后新增的復制方式。

GTID (global transaction identifier) 即全局事務 ID,一個事務對應一個 GTID,保證了在每個在主庫上提交的事務在集群中有一個唯一的 ID。

GTID復制原理

在原來基於日志的復制中,從庫需要告知主庫要從哪個偏移量進行增量同步, 如果指定錯誤會造成數據的遺漏,從而造成數據的不一致。

而基於 GTID 的復制中,從庫會告知主庫已經執行的事務的 GTID 的值,然后主庫會將所有未執行的事務的 GTID 的列表返回給從庫,並且可以保證同一個事務只在指定的從庫執行一次,通過全局的事務 ID 確定從庫要執行的事務的方式代替了以前需要用 Binlog 和 位點確定從庫要執行的事務的方式

基於 GTID 的復制過程如下:

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

​ GTID = source_id:transaction_id

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

transaction_id順序化的序列號(sequence number),在每台 MySQL 服務器上都是從 1 開始自增長的序列,是事務的唯一標識。

GTID 生成

GTID 的生成受 gtid_next 控制。

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

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

GTID 的好處
  1. GTID 使用 master_auto_position=1 代替了 Binlog 的主從復制方案,相比 Binlog 方式更容易搭建主從復制。
  2. GTID 方便實現主從之間的 failover(主從切換),不用一步一步的去定位 Binlog日志文件和查找 Binlog 的位點信息。
GTID 模式復制局限性
  1. 在一個事務里面混合使用引擎,如 Innodb(支持事務)、MyISAM(不支持事務), 造成多個 GTIDs 和同一個事務相關聯出錯。

  2. CREATE TABLE…..SELECT 不能使用,該語句產生的兩個 Event。 在某一情況會使用同一個 GTID(同一個 GTID 在 slave 只能被使用一次):

    • event one:創建表語句 create table
    • event two :插入數據語句 insert
  3. CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE 不能在事務內使用 (啟用了 –enforce-gtid-consistency 參數)。

  4. 使用 GTID 復制從庫跳過錯誤時,不支持 sql_slave_skip_counter 參數的語法。

GTID 主從復制實戰

1.Master 主數據庫上的操作

在 my.cnf 文件中配置 GTID 主從復制

[root@mysql-master ~]# cp /etc/my.cnf /etc/my.cnf.bak
[root@mysql-master ~]# >/etc/my.cnf
[root@mysql-master ~]# cat /etc/my.cnf
[mysqld]
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock
  
symbolic-links = 0
  
log-error = /var/log/mysqld.log
pid-file = /var/run/mysqld/mysqld.pid
  
#GTID:
server_id = 1
gtid_mode = on
enforce_gtid_consistency = on
    
#binlog
log_bin = mysql-bin
log-slave-updates = 1
binlog_format = row
sync-master-info = 1
sync_binlog = 1
   
#relay log
skip_slave_start = 1

配置后,重啟 MySQL 服務:

[root@mysql-master ~]# systemctl restart mysqld

登錄 MySQL,並查看 Master 狀態, 發現多了一項 Executed_Gtid_Set

mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |      154 |              |                  |                   |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
  
mysql> show global variables like '%uuid%';
+---------------+--------------------------------------+
| Variable_name | Value                                |
+---------------+--------------------------------------+
| server_uuid   | 317e2aad-1565-11e9-9c2e-005056ac6820 |
+---------------+--------------------------------------+
1 row in set (0.00 sec)

查看確認 GTID 功能打開:

mysql> show global variables like '%gtid%';
+----------------------------------+-------+
| Variable_name                    | Value |
+----------------------------------+-------+
| binlog_gtid_simple_recovery      | ON    |
| enforce_gtid_consistency         | ON    |
| gtid_executed                    |       |
| gtid_executed_compression_period | 1000  |
| gtid_mode                        | ON    |
| gtid_owned                       |       |
| gtid_purged                      |       |
| session_track_gtids              | OFF   |
+----------------------------------+-------+
8 rows in set (0.00 sec)	

查看確認 Binlog 日志功能打開:

mysql> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |
+---------------+-------+
1 row in set (0.00 sec)

授權 slave 復制用戶,並刷新權限:


mysql> flush privileges;
Query OK, 0 rows affected (0.04 sec)
  
mysql> show grants for slave@'172.23.3.66';
+-------------------------------------------------------------------------------+
| Grants for slave@172.23.3.66                                                |
+-------------------------------------------------------------------------------+
| GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'172.23.3.66' |
+-------------------------------------------------------------------------------+
1 row in set (0.00 sec)
  

再次查看 master 狀態:

mysql> show master status;
+-------------------+----------+--------------+------------------+------------------------------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                        |
+-------------------+----------+--------------+------------------+------------------------------------------+
| mysql-bin.000001 |      622 |              |                  | 317e2aad-1565-11e9-9c2e-005056ac6820:1-2 |
+-------------------+----------+--------------+------------------+------------------------------------------+
1 row in set (0.00 sec)

這里需要注意一下:
啟動配置之前,同樣需要對從服務器進行初始化。對從服務器初始化的方法基本和基於日志點是相同的,只不過在啟動了 GTID 模式后,在備份中所記錄的就不是備份時的二進制日志文件名和偏移量了,而是記錄的是備份時最后的 GTID 值。
需要先在主數據庫機器上把目標庫備份一下,假設這里目標庫是 slave_test:

mysql> CREATE DATABASE slave_test CHARACTER SET utf8 COLLATE utf8_general_ci;
Query OK, 1 row affected (0.02 sec)
  
mysql> use slave_test;
Database changed
mysql> create table user (id int(10) PRIMARY KEY AUTO_INCREMENT,name varchar(50) NOT NULL);
Query OK, 0 rows affected (0.27 sec)
  
mysql> insert into slave_test.user values(1,"xiaoming"),(2,"xiaohong"),(3,"xiaolv");   
Query OK, 3 rows affected (0.06 sec)
Records: 3  Duplicates: 0  Warnings: 0
  
mysql> select * from slave_test.user;
+----+----------+
| id | name     |
+----+----------+
|  1 | xiaoming |
|  2 | xiaohong |
|  3 | xiaolv   |
+----+----------+
3 rows in set (0.00 sec)

把 slave_test 庫備份出來:

[root@mysql-master ~]# mysqldump --single-transaction --master-data=2 --triggers --routines --databases slave_test -uroot -p123456 > /root/user.sql

這里有個版本上的問題:

MySQL 5.6 使用 mysqldump 備份時,指定備份的具體庫,使用 --database

MySQL 5.7 使用 mysqldump 備份時,指定備份的具體庫,使用--databases。

然后把備份的 /root/user.sql 文件拷貝到 slave 從數據庫服務器上。

[root@mysql-master ~]# rsync -e "ssh -p20" -avpgolr /root/user.sql 

到這里主庫的操作結束,包含 GTID 的備份數據已經 copy 到從庫,下面來進行從庫的操作。

2.從庫操作

在 my.cnf 文件中配置 GTID 主從復制

與主服務器配置大概一致,除了 server_id 不一致外,從服務器還可以在配置文件里面添加read_only=on ,使從服務器只能進行讀取操作,此參數對超級用戶無效,並且不會影響從服務器的復制。

[root@mysql-slave1 ~]# >/etc/my.cnf
[root@mysql-slave1 ~]# vim /etc/my.cnf
[mysqld]
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock
  
symbolic-links = 0
  
log-error = /var/log/mysqld.log
pid-file = /var/run/mysqld/mysqld.pid
  
#GTID:
server_id = 2
gtid_mode = on
enforce_gtid_consistency = on
    
#binlog
log_bin = mysql-bin
log-slave-updates = 1
binlog_format = row
sync-master-info = 1
sync_binlog = 1
   
#relay log
skip_slave_start = 1
read_only = on

配置完成后,重啟mysql服務。

[root@mysql-slave1 ~]# systemctl restart mysql

接着將主數據庫目標庫的備份數據 user.sql導入到從數據庫里。

[root@mysql-slave1 ~]# ls /root/user.sql
/root/user.sql
[root@mysql-slave1 ~]# mysql -p123456
.........
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)
  
mysql> source /root/user.sql;
  
mysql> select * from slave.test;
+----+----------+
| id | name     |
+----+----------+
|  1 | xiaoming |
|  2 | xiaohong |
|  3 | xiaolv   |
+----+----------+
3 rows in set (0.00 sec)

在從數據庫里,使用 change master 配置主從復制:

mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
  
mysql> change master to master_host='172.23.3.66',master_user='slave1',master_password='123456',master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.26 sec)
  
mysql> start slave;
Query OK, 0 rows affected (0.02 sec)
  
mysql> show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.23.3.66
                  Master_User: slave1
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 1357
               Relay_Log_File: mysql-slave1-relay-bin.000002
                Relay_Log_Pos: 417
        Relay_Master_Log_File: mysql-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
................
................
            Executed_Gtid_Set: 317e2aad-1565-11e9-9c2e-005056ac6820:1-5
                Auto_Position: 1
  

由此,Master 和 Slave 節點已經配置了主從同步關系。接下來你可以自行在主庫插入一條數據觀察從庫是否同步過來。

使用 GTID 添加從庫有兩種方式

直接同步主庫所有GTID

如果主庫一開始就開啟了 GTID,那么可以直接獲取主庫的所有GTID來同步至從庫。但是如果主庫 Binlog 日志太多,那么相應同步的時間也會變長。這種方式適用於小數據量的同步。

使用這種方式來同步相應的命令為:

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_AUTO_POSITION 參數的時候,MASTER_LOG_FILEMASTER_LOG_POS 參數不能使用。
如果想要從 GTID 配置回 pos,再次執行這條語句,不過把 MASTER_AUTO_POSITION 置為 0。

通過設定范圍進行同步

通過指定 GTID 的范圍,然后通過在 slave 設置 @@GLOBAL.GTID_PURGED 從而跳過備份包含的 GTID 。

這種方案適用於數據量比較大一次同步需要耗費巨量時間的數據。但同時也有操作復雜的問題,需要你記住每次同步的范圍。

用這種方式來同步相應的命令為:

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

這里注意到我們的參數換了:MASTER_LOG_POS,該參數表示當前需要同步的 GTID 事務的起點值。

總結

本篇介紹主從復制的兩種形式:基於 Binlog 和 位點信息的傳統復制方式;基於 Binlog 和 GTID 的新式復制方式。現在很多公司可能還在使用 MySQL 5.6 的版本,所以 GTID不一定可以使用。

本文篇幅較長,大家可以簡要查看原理。

                                                                                                 

                                                                                                                                                                  關注我不迷路


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM