1、概述
MySQL 的主從復制又叫 Replication、AB 復制。至少需要兩個 MySQL 服務(可以是同一台機器,也可以是不同機器之間進行)。
比如A服務器做主服務器,B服務器做從服務器,在A服務器上進行數據的更新,通過 binlog 日志記錄同步到B服務器上,並重新執行同步過來的 binlog 數據,從而達到兩台服務器數據一致。
MySQL 數據庫的主從復制方案,與使用 scp/rsync 等命令進行的文件級別復制類似,都是數據的遠程傳輸。只不過 MySQL 的主從復制是其自帶的功能,無需借助第三方工具,而且MySQL的主從復制並不是數據庫磁盤上的文件直接拷貝,而是通過邏輯的 binlog 日志復制到要同步的服務器本地,然后由本地的線程讀取日志里面的 SQL 語句,重新應用到 MySQL 數據庫中。
2、為什么需要 Mysql 主從復制
談起為什么在大多數情況下部署 Mysql 常常使用 Mysql 主從模式進行部署這個問題,本來也去網上搜尋了一些答案,其中原因主要有以下幾點:
- 做數據的熱備,主庫宕機后備庫能夠及時替換主庫,保證業務可用性,能一定程度避免數據丟失。
- 實現讀寫分離,主庫寫,從庫讀,減小主庫的讀寫壓力。當主庫執行寫過程加鎖時,不會堵塞從庫讀操作,從而提高了數據的查詢效率。
- 應對業務量越來越大,I/O 訪問頻率過高,單機無法滿足的問題。增加多個從庫做負載,能夠降低整體 I/O 訪問頻率,提高單個機器 I/O 性能。
3、數據庫常用的主從復制方式
- 基於 Binlog 復制模式
MySQL 主從復制默認是異步的模式。MySQL增刪改操作會全部記錄在 Binlog 中,當 slave 節點連接 master 時,會主動從 master 處獲取最新的 Binlog 文件。並把 Binlog 存儲到本地的 relay log 中,然后去執行 relay log 的更新內容。
- GTID 復制模式
在傳統的復制里面,當發生故障,需要主從切換,需要找到 Binlog 和 位點信息,恢復完成數據之后將主節點指向新的主節點。在 MySQL 5.6 里面,提供了新的數據恢復思路,只需要知道主節點的 IP、端口以及賬號密碼就行,因為復制是自動的,MySQL 會通過內部機制 GTID 自動找點同步。接下來我們要部署的主從也是基於這種模式。
4、GTID 概念相關介紹
GTID 是什么
GTID 指的是全局事務 ID,全程是 Global Transaction Identifier ,在整個事務流程中每一個事務 ID 是全局唯一的,且在整個主從復制架構中該 ID 都不會相同。
GTID 主從復制方式
基於 GTID 的主從復制方式的出現,主要是用於替換傳統的日志點 復制方式。通過GTID 可以保證每個主庫提交的事務在集群中都有 唯一 的一個事務 ID。強化了數據庫主從的一致性和故障恢復數據的容錯能力,在主庫 宕機發生主從切換 的情況下,GTID 方式可以讓其他從庫自動找到新主庫復制的位置。而且 GTID 可以忽略已經執行過的事務,減少了數據發生錯誤的概率。
GTID 的組成
GTID 由server_uuid +tid 組成,其中:
- server_uuid:
server_uuid
是在 Mysql 首次啟動過程中自動生成的一個uuid(128位)
隨機值,生成后會將該值存儲到數據目錄的auto.cnf
中。因為是隨機值,所以不同服務器的 Mysql 的server_uuid 都是不相同的。 - tid: 代表了該實例上已經提交的事務數量,是一個整數,初始值是
1
,每次提交事務的時候分配給這個事務並加1
。
其組成樣式如下:
fb90fba5-60cf-11eb-b5fa-000c295fbc5f:21
GTID 復制工作原理
假設從庫開啟了 binlog,那么執行流程如下:
- ① 主節點執行事務提交前會產生一個
GTID
,其會隨着事務一起記錄到binlog
日志中。 - ② 從節點
I/O Thread
會讀取主節點的binlog
日志文件並存儲在從節點的relaylog
日志中。從節點將主節點的GTID
這個值配置到gtid_next
中,即下一個要讀取的 GTID 值。 - ③ 從節點讀取
gtid_next
中的值,然后查找自己的binlog
日志中是否有這個GTID
。 - ④ 如果有這個記錄,說明這個
GTID
的事務已經執行過了,就忽略掉。 - ⑤ 如果沒有這個記錄,從節點就會執行該 GTID 事務,並記錄到自己的
binlog
日志中。在讀取執行事務前會先檢查其他session
中是否持有該GTID
,確保不被重復執行。 - ⑥ 在解析過程中會判斷是否有主鍵,如果沒有就用二級索引,如果沒有就用全部掃描。
GTID 使用中的限制條件
GTID 復制是針對事務來說的,一個事務只對應一個 GTID,好多的限制就在於此。其中主要限制如下:
- 不能使用
create table table_name select * from table_name
。 - 在一個事務中既包含事務表(使用
InnoDB
存儲引擎的表)的操作又包含非事務表(使用MyISAM
存儲引擎的表)。 - 不支持創建或刪除臨時表操作,如
CREATE TEMPORARY TABLE or DROP TEMPORARY TABLE
語句操作。 - 使用 GTID 復制從庫跳過錯誤時,不支持執行該
ql_slave_skip_counter
參數的語法。
如何開啟 GTID 模式
需要在 Mysql 配置文件中添加下面幾條配置:
## 開啟 gtid 模式
gtid_mode=on
## 配置不允許任何事務違反 GTID 一致性,用於保證數據一致性
enforce_gtid_consistency=on
## 開啟 Binlog 並指定名稱(可選)
log_bin=binlog
## 從節點從主節點接收到更新且執行,是否將記錄存到從節點的 binlog 日志中(可選)
log-slave-updates=on
## 當從數據庫啟動的時候,從節點不會啟動復制(可選)
skip-slave-start=1
MySQL8.0 之前 mysql 密碼加密方式為 mysql_native_password,而 MySQL8.0 版本默認新添加的用戶密碼默認使用的 caching_sha2_password,因此進行使用主從復制時可能會遇到錯誤,需要將加密方式改成 mysql_native_password。
5、基於GTID的主從復制原理** **
我個人理解,基於GTID的MySQL復制流程為:
1、Master寫入記錄前生成一個GTID
2、Master將GTID和數據一起寫入二進制日志中
3、Master刷新日志數據到磁盤中
4、Slave讀取Master的二進制日志中的GTID
5、Slave判斷該GTID是否已經寫入中繼日志,如果寫入了則說明該GTID代表的數據已經存在,跳過該條數據不將其重復錄入到中繼日志中
6、Slave繼續往下讀取Master二進制日志,直到讀取到Slave中繼日志中不存在的GTID即開始將其寫入Slave中繼日志,SQL線程啟動,開始刷新數據到Slave磁盤中
7、復制過程結束
這樣就可以避免Slave中漏寫Master的數據或者重復寫入。
6、環境准備
Linux版本:CentOS7
MySQL版本:mysql8.0
Docker版本:19.03.9
DockerCompose版本:1.27.4
有很多種配置主從同步的方法,可以總結為如下的步驟:
- 在主服務器上,必須開啟二進制日志機制和配置一個獨立的ID
- 在每一個從服務器上,配置一個唯一的ID,創建一個用來專門復制主服務器數據的賬號
- 在開始復制進程前,在主服務器上記錄二進制文件的位置信息
- 如果在開始復制之前,數據庫中已經有數據,就必須先創建一個數據快照(可以使用mysqldump導出數據庫,或者直接復制數據文件)
- 配置從服務器要連接的主服務器的IP地址和登陸授權,二進制日志文件名和位置
主從目錄結構
.
├── config
│ ├── master.cnf
├── master-data
├── .env
└── docker-compose.yml
目錄/文件說明
config/master.cnf
: MySQL Master節點的配置文件docker-compose.yml
: 構建主從節點與掛載數據目錄的docker-compose配置文件master-data
: 主節點數據位置,當然生產環境要掛到別的位置.env
: 環境變量文件
主從數據庫配置
主庫配置
1、修改.env
文件
# default environment arguments for docker-compose.yml
# set master volumes dir
MASTER_DATA=./mysql-volumes/data/master
MASTER_LOGS=./mysql-volumes/logs/master
MASTER_CONF=./mysql-volumes/conf/master
# set master root password
MASTER_PASSWD=P@ssw0rd
MASTER_DATA
是 Master節點的數據目錄,需要修改到宿主機對應的位置。MASTER_LOGS
是 Master節點的日志目錄,需要修改到宿主機對應的位置。MASTER_CONF
是 Master節點的配置目錄,需要修改到宿主機對應的位置。MASTER_PASSWD
是主節點的root密碼,bin目錄下的腳本會讀取這個變量的值從而進行訪問數據庫
2、修改配置文件
cd ./mysql-volumes/conf/master
vim master.cnf
配置內容如下:
[mysqld]
max_connections = 2000
default-time_zone='+8:00'
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
#gtid:
server_id = 1 #服務器id
gtid_mode = on #開啟gtid模式
enforce_gtid_consistency = on #強制gtid一致性,開啟后對於特定create table不被支持
#binlog
log_bin = mysql-binlog
log_slave_updates = on
binlog_format = row #強烈建議,其他格式可能造成數據不一致
#relay log
skip_slave_start = 1
default_authentication_plugin = 'mysql_native_password' #更改加密方式
3、配置docker-compose.yml
version: '3.3'
services:
mysql-master:
image: mysql:8.0
container_name: mysql-master
command:
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
ports:
- 3316:3306
environment:
- MYSQL_ROOT_PASSWORD=${MASTER_PASSWD}
volumes:
- ${MASTER_CONF}:/etc/mysql/conf.d
- ${MASTER_LOGS}:/var/log/mysql
- ${MASTER_DATA}:/var/lib/mysql
4、啟動主庫
在docker-compose.yml目錄下執行docker-compose up -d
5、在主庫中創建用於主從復制的賬號
# 連接mysql服務
docker exec -it mysql-master mysql -uroot -pP@ssw0rd
#查看server_id是否生效
show variables like '%server_id%';
# 查看MASTER狀態
SHOW MASTER STATUS\G
# 創建主從復制賬號
CREATE USER 'replicasName'@'%' IDENTIFIED BY 'replicasPasswd';
GRANT REPLICATION SLAVE ON *.* TO 'replicasName'@'%';
flush privileges;
select user,host from mysql.user;
從庫配置
1、修改.env
文件
# default environment arguments for docker-compose.yml
# set slave volumes dir
SLAVE_DATA=./mysql-volumes/data/slave
SLAVE_LOGS=./mysql-volumes/logs/slave
SLAVE_CONF=./mysql-volumes/conf/slave
# set slave root passwor
SLAVE_PASSWD=P@ssw0rd
SLAVE_DATA
是 Salve節點的數據目錄,需要修改到宿主機對應的位置。SLAVE_LOGS
是 Salve節點的日志目錄,需要修改到宿主機對應的位置。SLAVE_CONF
是 Salve節點的配置目錄,需要修改到宿主機對應的位置。SLAVE_PASSWD
是主節點的root密碼,bin目錄下的腳本會讀取這個變量的值從而進行訪問數據庫
2、修改配置文件
cd ./mysql-volumes/conf/slave
vim slave.cnf
配置內容如下:
[mysqld]
max_connections = 2000
default-time_zone = '+8:00'
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
#GTID:
server_id = 2 #服務器id
gtid_mode = on #開啟gtid模式
enforce_gtid_consistency = on #強制gtid一致性,開啟后對於特定create table不被支持
#binlog
log_bin =mysql-binlog
log_slave_updates = on
binlog_format = row #強烈建議,其他格式可能造成數據不一致
#relay log
skip_slave_start = 1
default_authentication_plugin = 'mysql_native_password' #更改加密方式
read_only = on #設置只讀
3、配置docker-compose.yml
version: '3.3'
services:
mysql-slave:
image: mysql:8.0
container_name: mysql-slave
command:
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
ports:
- 3326:3306
environment:
- MYSQL_ROOT_PASSWORD=${SLAVE_PASSWD}
volumes:
- ${SLAVE_CONF}:/etc/mysql/conf.d
- ${SLAVE_LOGS}:/var/log/mysql
- ${SLAVE_DATA}:/var/lib/mysql
4、啟動從庫
在docker-compose.yml目錄下執行docker-compose up -d
5、通過主庫的賬號開啟主從復制
# 連接mysql
docker exec -it mysql-slave mysql -uroot -pP@ssw0rd
#查看server_id是否生效
show variables like '%server_id%';
# 查看MASTER狀態
SHOW SLAVE STATUS\G
# 從節點使用備份賬戶連接主節點,開啟備份
CHANGE MASTER TO
master_host='192.168.147.152',
master_port=3316,
master_user='replicasName',
master_password='replicasPasswd',
master_auto_position=1;
# 啟動同步
RESET SLAVE;
START SLAVE;
查看SLAVE狀態,都為yes表示基於GTID的MySQL主從復制已經成功!
參考:
https://blog.csdn.net/pbrlovejava/article/details/88046025
https://www.freeaihub.com/post/93490.html