1. 程式人生 > 其它 >第十一篇: mysql主從

第十一篇: mysql主從

# 第1章 主從複製介紹

## 1.介紹

```
MySQL資料庫的主從複製技術與使用scp/rsync等命令進行的異機檔案級別複製類似,都是資料的遠端傳輸.
只不過MySQL的主從複製技術是其軟體自身攜帶的功能,無須藉助第三方工具.
MySQL的主從複製並不是直接複製資料庫磁碟上的檔案,而是將邏輯的記錄資料庫更新的binlog日誌傳送到需要同步的資料庫伺服器本地,然後再由本地的資料庫執行緒讀取日誌中的SQL語句並重新應用到MySQL資料庫中,從而即可實現資料庫的主從複製。
```

## 2.應用場景

```
1.從伺服器作為主伺服器的實時資料備份
2.主從伺服器實現讀寫分離,從伺服器實現負載均衡
3.根據業務重要性對多個伺服器進行拆分
```

# 第2章 主從複製搭建部署

## 1.安裝部署mysql例項

```
安裝過程略,此處只給出3臺例項的配置檔案
# db-01配置
cat > /etc/my.cnf<<EOF
[mysqld]
user=mysql
datadir=/data/mysql_3306
basedir=/opt/mysql/
socket=/tmp/mysql.sock
port=3306
log_error=/var/log/mysql/mysql.err
server_id=51
log_bin=/binlog/mysql-bin

[mysql]
socket=/tmp/mysql.sock

[client]
socket=/tmp/mysql.sock
EOF

# db-52配置
cat > /etc/my.cnf<<EOF
[mysqld]
user=mysql
datadir=/data/mysql_3306
basedir=/opt/mysql/
socket=/tmp/mysql.sock
port=3306
log_error=/var/log/mysql/mysql.err
server_id=52

[mysql]
socket=/tmp/mysql.sock

[client]
socket=/tmp/mysql.sock
EOF

# db-53配置
cat > /etc/my.cnf<<EOF
[mysqld]
user=mysql
datadir=/data/mysql_3306
basedir=/opt/mysql/
socket=/tmp/mysql.sock
port=3306
log_error=/var/log/mysql/mysql.err
server_id=53

[mysql]
socket=/tmp/mysql.sock

[client]
socket=/tmp/mysql.sock
EOF

# 初始化
mysqld --initialize-insecure --user=mysql --basedir=/opt/mysql --datadir=/data/mysql_3306/
```

## 2.主庫操作

### 2.1 建立複製使用者

```
mysql -uroot -p123456 -e "grant replication slave on *.* to repl@'10.0.0.%' identified by '123';"
mysql -uroot -p123456 -e "select user,host,plugin from mysql.user;"
```

### 2.2 備份資料併發送到從庫

```
mysqldump -uroot -p123456 -A --master-data=2 --single-transaction -R -E --triggers --max_allowed_packet=64M > /data/full.sql
scp /data/full.sql 10.0.0.52:/tmp/
scp /data/full.sql 10.0.0.53:/tmp/
```

## 3.從庫操作

### 3.1 檢視從庫位置點

```
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=444;
```

### 3.2 匯入主庫資料

```
mysql -uroot -p123456 < /tmp/full.sql
```

### 3.3 配置主從同步資訊

```
CHANGE MASTER TO
MASTER_HOST='10.0.0.51',
MASTER_USER='repl',
MASTER_PASSWORD='123',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=444,
MASTER_CONNECT_RETRY=10;
```

### 3.4 啟動執行緒

```
start slave;
```

## 4.檢視複製狀態

```
mysql -uroot -p123456 -e "show slave status\G"|grep "Running:"
```

# 第3章 主從複製原理

## 1.涉及到的執行緒

### 1.1 主庫

執行緒說明:

```
binlog_dump_thread
負責接收slave請求和傳送主庫binlog給slave
```

檢視命令:

```
mysql> show processlist;
+----+------+-----------------+------+-------------+------+---------------------------------------------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------------+------+-------------+------+---------------------------------------------------------------+------------------+
| 32 | repl | 10.0.0.53:47726 | NULL | Binlog Dump | 284 | Master has sent all binlog to slave; waiting for more updates | NULL |
| 33 | repl | 10.0.0.52:55250 | NULL | Binlog Dump | 280 | Master has sent all binlog to slave; waiting for more updates | NULL |
| 34 | root | localhost | NULL | Query | 0 | starting | show processlist |
+----+------+-----------------+------+-------------+------+---------------------------------------------------------------+------------------+
```

### 1.2 從庫

執行緒說明:

```
IO執行緒 :
連線主庫DUMP執行緒,請求Master日誌、接收Master日誌、儲存日誌(relay-log)。

SQL執行緒
回放relaylog
```

檢視命令:

```
[root@db-52 ~]# mysql -uroot -p123456 -e "show slave status\G"|grep "Running:"
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
```

## 2.涉及到的檔案

### 2.1 主庫

```
binlog日誌檔案
```

### 2.2 從庫
relay-log 中繼日誌

```
命名方式:
datadir/HOSTNAME-relay-bin.00000N

作用:
儲存獲取到的binlog
```
主庫資訊檔案
```
命名方式:
datadir/master.info
作用:
記錄主庫ip port user password binlog位置點等資訊。
```
中繼日誌應用資訊
```
命名方式:
relay-log.info
作用:
記錄SQL 執行緒回放到的位置點資訊。
```

## 3.畫圖說明主從複製原理--必須掌握--面試必問!

文字:

```
S: Change master to IP,Port,USER,PASSWORD,binlog位置資訊寫入到M.info中,執行Start slave(啟動SQL,IO)。
S: 連線主庫。
M: 分配Dump_T,專門和S_IO通訊。show processlist;
S: IO執行緒:IO執行緒請求新日誌
M: DUMP_T 接收請求,擷取日誌,返回給S_IO
S: IO執行緒接收到binlog,日誌放在TCP/IP,此時網路層層面返回ACK給主庫。主庫工作完成。
S: IO將binlog最終寫入到relaylog中,並更新M.info。IO執行緒工作結束。
S: SQL執行緒讀R.info,獲取上次執行到的位置點
S: SQL執行緒向後執行新的relay-log,再次更新R.info。
```

畫圖:

![](https://upload-images.jianshu.io/upload_images/14248468-c767332e0d143e91.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

# 第4章 主從複製監控

## 1.主庫狀態

檢視複製執行緒:

```
[root@db-51 ~]# mysql -uroot -p123456 -e "show processlist" |grep "Dump"
mysql: [Warning] Using a password on the command line interface can be insecure.
32 repl 10.0.0.53:47726 NULL Binlog Dump 568 Master has sent all binlog to slave; waiting for more updates NULL
33 repl 10.0.0.52:55250 NULL Binlog Dump 564 Master has sent all binlog to slave; waiting for more updates NULL
```

檢視複製節點資訊:

```
[root@db-51 ~]# mysql -uroot -p123456 -e "show slave hosts;"
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID |
+-----------+------+------+-----------+--------------------------------------+
| 53 | | 3306 | 51 | 0f61194b-f733-11ea-8ca6-000c29c20a5d |
| 52 | | 3306 | 51 | 2fbe6b47-f731-11ea-9d25-000c29605eb5 |
+-----------+------+------+-----------+--------------------------------------+
```

## 2.從庫狀態

檢視主從狀態:

```
mysql -uroot -p123456 -e "show slave status \G"
```

主庫連線資訊、binlog位置資訊

```
Master_Host: 10.0.0.51
Master_User: repl
Master_Port: 3306
Connect_Retry: 10
Read_Master_Log_Pos: 444
Relay_Master_Log_File: mysql-bin.000001
```

從庫中relay-log的回放資訊

```
Relay_Log_File: db-52-relay-bin.000002
Relay_Log_Pos: 320
Relay_Master_Log_File: mysql-bin.000001
Exec_Master_Log_Pos: 444
```

執行緒監控資訊:主要用來排查主從故障-重點監控

```
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
```

過濾複製相關資訊

```
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
```

落後於主庫的秒數-重點監控

```
Seconds_Behind_Master: 0
```

延時從庫狀態資訊

```
SQL_Delay: 0
SQL_Remaining_Delay: NULL
```

GTID複製資訊

```
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
```

## 3.位置點資訊

IO 已經獲取到的主庫Binlog的位置點

```
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 444
作用: IO下次請求日誌時,起點位置。
```

SQL 回放到的relaylog位置點

```
Relay_Log_File: db01-relay-bin.000006
Relay_Log_Pos: 320
```

SQL回放的realylog位置點,對應的主庫binlog的位置點

```
Relay_Master_Log_File: mysql-bin.000001
Exec_Master_Log_Pos: 600
作用: 計算主從複製延時日誌量。
```

# 第5章 主從複製故障

## 1.如何監控

```
Slave_IO_Running: Yes # IO執行緒工作狀態: YES、NO、Connecting
Slave_SQL_Running: Yes # SQL執行緒工作狀態:YES、NO
Last_IO_Errno: 0 # IO故障程式碼:2003,1045,1040,1593,1236
Last_IO_Error: # IO執行緒報錯詳細資訊
Last_SQL_Errno: 0 # SQL故障程式碼: 1008,1007
Last_SQL_Error: # IO執行緒報錯詳細資訊
```

## 2.IO執行緒故障

### 2.1 正常狀態

```
Slave_IO_Running: Yes
```

### 2.2 不正常狀態

```
NO
Connecting
```

### 2.3 故障原因

```
1.網路,埠,防火牆
2.使用者 ,密碼,授權
replication slave
3.主庫連線數上限
mysql> select @@max_connections;
4.版本不統一 5.7 native , 8.0 sha2
```

### 2.4 模擬故障

主庫操作

```
mysql> start slave; # 啟動所有執行緒
mysql> stop slave; # 關閉所有執行緒
mysql> start slave sql_thread; #單獨啟動SQL執行緒
mysql> start slave io_thread; #單獨啟動IO執行緒
mysql> stop slave sql_thread;
mysql> stop slave io_thread;

解除從庫身份:
mysql> reset slave all;
mysql> show slave status \G
```

從庫操作

```
stop slave;
reset slave all;

CHANGE MASTER TO
MASTER_HOST='10.0.0.51',
MASTER_USER='repl',
MASTER_PASSWORD='123',
MASTER_PORT=3307,
MASTER_LOG_FILE='mysql-bin.000003',
MASTER_LOG_POS=154,
MASTER_CONNECT_RETRY=10;
start slave;
```

### 2.5 解決思路

```
1.網路是否互通
2.確定複製賬號授權是否正確
3.主從的server id是否相同
4.重做從庫
```

## 3.SQL執行緒故障

### 3.1 SQL執行緒主要工作

```
回放relay-log中的日誌。可以理解為執行relay-log SQL
```

### 3.2 故障本質

```
為什麼SQL執行緒執行不了SQL語句
```

### 3.3 故障原因

```
建立的物件已經存在
需要操作的物件不存在
約束衝突。
以上問題: 大機率出現在從庫寫入或者雙主結構中容易出現。
```

### 3.4 故障模擬

```
(1)先在從庫 create database oldguo charset=utf8;
(2)在主庫 create database oldguo charset=utf8mb4;
(3)檢查從庫SQL執行緒狀態
Slave_SQL_Running: No
Last_Error: Error 'Can't create database 'oldguo'; database exists' on query. Default database: 'oldguo'. Query: 'create database oldguo'
```

### 3.5 故障處理

思路1: 一切以主庫為準

```
在從庫上進行反操作一下。重啟執行緒
mysql> drop database oldguo;
mysql> start slave;
```

思路2: 以從庫為準,跳過此次複製錯誤,不建議

```
stop slave;
set global sql_slave_skip_counter = 1;

#將同步指標向下移動一個,如果多次不同步,可以重複操作。
start slave;
```

思路3: 暴力方法,遇到自動跳過。

```
/etc/my.cnf
slave-skip-errors = 1032,1062,1007

常見錯誤程式碼:
1007:物件已存在
1032:無法執行DML
1062:主鍵衝突,或約束衝突
```

思路4: 重新搭建主從

```
備份恢復+ 重新構建
```

# 第7章 過濾複製

## 1.過濾複製介紹

```
從節點僅僅複製指定的資料庫,或指定資料庫的指定資料表
```

## 2.主庫實現

```
binlog_do_db 白名單
binlog_ignore_db 黑名單
通過是否記錄binlog日誌來控制過濾
```

## 3.從庫實現

實現方法:

```
IO執行緒不做限制。
SQL執行緒回放時,選擇性回放。
```

配置引數:

```
replicate_do_db=world
replicate_do_db=oldboy
replicate_ignore_db=

replicate_do_table=world.city
replicate_ignore_table=

replicate_wild_do_table=world.t*
replicate_wild_ignore_table=
```

配置方法1: 修改配置檔案

```
replicate_do_db=world
replicate_do_db=oldboy
```

配置方法2: 線上熱配置

```
STOP SLAVE SQL_THREAD;
CHANGE REPLICATION FILTER REPLICATE_DO_DB = (oldguo, oldboy);
START SLAVE SQL_THREAD;
```

# 第8章 延時從庫的應用

## 1.延時從庫介紹

```
控制從庫的SQL執行緒執行速度,二進位制日誌照常去主庫取,但是存放到中繼日誌之後就延遲執行,如果主庫被誤操作,這時候對中繼日誌進行處理,就不用根據全備二進位制日誌恢復,節省了大部分的時間
```

## 2.配置方法

```
stop slave;
CHANGE MASTER TO MASTER_DELAY = 300;
start slave;
```
## 3.檢視狀態

```
mysql> show slave status \G
SQL_Delay: 300
SQL_Remaining_Delay: NULL
```

## 3.故障處理流程

```
1. 及時監控故障: 主庫 10:05發現故障,從庫此時8:05資料狀態
2. 立即將從庫的SQL執行緒關閉。 需要對A業務掛維護頁。
3. 停止所有執行緒。
4. 在延時從。恢復A庫資料
手工模擬SQL執行緒工作,找到drop之前位置點。
SQL執行緒上次執行到的位置 ----> drop之前
relay.info ----> 分析drop位置點 ----> 擷取relaylog日誌 ----> source
```

## 4.故障模擬及恢復

主庫操作:

```
create database json charset utf8mb4;
use json;
create table t1(id int);
insert into t1 values(1),(2),(3);
commit;

drop database json;
```

從庫操作:

```
stop slave sql_thread;
show slave status \G;
```

擷取日誌:

起點:SQL上次執行到的位置點,

```
Relay_Log_File: db-52-relay-bin.000002
Relay_Log_Pos: 320
```

終點:drop 之前

```
mysql> show relaylog events in 'db-52-relay-bin.000002';
....略
| db-52-relay-bin.000002 | 985 | Query | 51 | 1201 | drop database json
```

擷取日誌:

```
mysqlbinlog --start-position=320 --stop-position=985 /data/mysql_3306/db-52-relay-bin.000002 >/tmp/bin.sql
```

從庫恢復操作:

```
stop slave;
reset slave all;
set sql_log_bin=0;
source /tmp/bin.sql;
set sql_log_bin=1;
```

# 第9章 GTID複製

## 1.GITD複製介紹

```
功能:主從之間自動校驗GTID一致性: 主庫binlog,從庫binlog ,relay-log

沒有備份: 自動從主庫的第一個gtid對應的pos號開始複製
有備份:
SET @@GLOBAL.GTID_PURGED='2386f449-98a0-11ea-993c-000c298e182d:1-10';
從庫會自動從第11個gtid開始複製。
```

## 2.清理環境

```
pkill mysqld
rm -rf /data/mysql_3306/*
rm -rf /binlog/*
mkdir /binlog/
mkdir
```

## 3.準備配置檔案

db01配置

```
cat > /etc/my.cnf <<EOF
[mysqld]
basedir=/opt/mysql
datadir=/data/mysql_3306
socket=/tmp/mysql.sock
server_id=51
port=3306
secure-file-priv=/tmp
autocommit=0
log_bin=/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
[mysql]
prompt=db01 [\\d]>
EOF
```

db02配置

```
cat > /etc/my.cnf <<EOF
[mysqld]
basedir=/opt/mysql
datadir=/data/mysql_3306
socket=/tmp/mysql.sock
server_id=52
port=3306
secure-file-priv=/tmp
autocommit=0
log_bin=/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
[mysql]
prompt=db02 [\\d]>
EOF
```

db03配置

```
cat > /etc/my.cnf <<EOF
[mysqld]
basedir=/opt/mysql
datadir=/data/mysql_3306
socket=/tmp/mysql.sock
server_id=53
port=3306
secure-file-priv=/tmp
autocommit=0
log_bin=/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
[mysql]
prompt=db03 [\\d]>
EOF
```

## 4.初始化資料

```
mysqld --initialize-insecure --user=mysql --basedir=/app/database/mysql --datadir=/data/3306
```

## 5.啟動資料庫

```
/etc/init.d/mysqld start
```

## 6.建立使用者

```
grant replication slave on *.* to repl@'10.0.0.%' identified by '123';
```

## 7.構建主從

52和53操作:

```
change master to
master_host='10.0.0.51',
master_user='repl',
master_password='123' ,
MASTER_AUTO_POSITION=1;
start slave;
```

# 第10章 主從延時問題的原因和處理

## 1.什麼是主從延時

```
主庫發生了操作,從庫'很久'才跟上來,甚至一直追不上
```

## 2.如何監控主從延時

粗略估計:

```
show slave status \G
Seconds_Behind_Master: 0
```
準確計算:
```
日誌量:
主庫binlog位置點
從relay執行的位置點
```

## 3.如何計算延時的日誌量

```
show master status;
cat /data/3308/data/relay-log.info
```

## 4.主從延時的原因

### 4.1 主庫可能的原因

```
外部原因:
網路,硬體配置,主庫業務繁忙,從庫太多

主庫業務繁忙 :
1. 拆分業務(分散式): 元件分離 ,垂直 , 水平
2. 大事務的拆分 。比如,1000w 業務 拆分為 20次執行。

內部 :
1. 二進位制日誌更新問題:
解決方案:
sync_binlog=1

2. 問題: 5.7之前的版本,沒有開GTID之前,主庫可以併發事務,但是dump傳輸時是序列。
所以會導致,事務量,大事務時會出現比較嚴重延時。
解決方案:
5.6+ 版本,手工開啟gtid,事務在主從的全域性範圍內就有了唯一性標誌。
5.7+ 版本,無需手工開啟,系統會自動生成匿名的GTID資訊
有了GTID之後,就可以實現併發傳輸binlog。
但是,即使有這麼多的優秀特性,我們依然需要儘可能的減少大事務,以及鎖影響。
```

### 4.2 從庫可能的原因

```
外部 :
網路,從庫配置低,引數設定。

內部 :
IO執行緒:
寫relay-log --> IO 效能。

SQL執行緒:
回放 SQL 預設在非GTID模式下是序列的
解決方案:
1. 開啟GTID
```