7 MySQL 集群Cluster
7.1 主從復(fù)制
主從架構(gòu)屬于負(fù)載均衡集群
可以實(shí)現(xiàn)讀寫(xiě)分離, 將讀操作調(diào)度到多個(gè)節(jié)點(diǎn)
而負(fù)責(zé)寫(xiě)操作的主服務(wù)器是存在單點(diǎn)失敗的
高可用集群是為了解決單點(diǎn)失敗問(wèn)題
7.1.1 主從復(fù)制原理
主從復(fù)制過(guò)程:
- 主節(jié)點(diǎn)收到用戶請(qǐng)求, 進(jìn)行數(shù)據(jù)更新
- 主節(jié)點(diǎn)將更新的操作寫(xiě)入二進(jìn)制日志, bin log
- 主節(jié)點(diǎn)開(kāi)啟專門的dump線程, 負(fù)責(zé)把新生成的二進(jìn)制日志, 發(fā)給從節(jié)點(diǎn)
- 從節(jié)點(diǎn)的io thread負(fù)責(zé)接收主節(jié)點(diǎn)dump線程發(fā)過(guò)來(lái)的數(shù)據(jù)
- 接收過(guò)來(lái)的數(shù)據(jù)寫(xiě)入中繼日志relay log
- SQL thread把中繼日志中的新的內(nèi)容, 寫(xiě)入從節(jié)點(diǎn)數(shù)據(jù)庫(kù), 實(shí)現(xiàn)主從數(shù)據(jù)的同步
主從復(fù)制相關(guān)線程:
主節(jié)點(diǎn):
- dump thread: 為每個(gè)Slave的IO thread啟動(dòng)一個(gè)dump線程, 用于向其發(fā)送二進(jìn)制日志事件
從節(jié)點(diǎn):
- IO thread: 向master請(qǐng)求二進(jìn)制日志事件, 并保存于中繼日志中, relay log
- SQL thread: 從中繼日志中讀取日志事件, 在本地完成重放
- dump線程與io thread通信走的是mysql協(xié)議, 主節(jié)點(diǎn)開(kāi)啟3306, 從節(jié)點(diǎn)會(huì)打開(kāi)隨機(jī)端口接收數(shù)據(jù)
7.1.2 主從復(fù)制相關(guān)配置
主從復(fù)制配置要求:
-
主從節(jié)點(diǎn)分別啟用二進(jìn)制日志
log-bin
主節(jié)點(diǎn)必須啟用二進(jìn)制, 因?yàn)橐涗浫罩? 然后同步給從節(jié)點(diǎn)
從節(jié)點(diǎn)看情況啟用, 不過(guò)一般都是要直接啟用的, 因?yàn)橐坏┲鞴?jié)點(diǎn)故障, 從節(jié)點(diǎn)需要提升為主節(jié)點(diǎn)
此外, 如果需要利用從節(jié)點(diǎn)進(jìn)行備份和還原, 那么從節(jié)點(diǎn)必須啟用二進(jìn)制, 并且添加log-slave-updates選項(xiàng), 把從主節(jié)點(diǎn)接收的二進(jìn)制寫(xiě)到本地二進(jìn)制日志里
-
為當(dāng)前所有節(jié)點(diǎn)設(shè)置一個(gè)全局唯一的server id號(hào), 在二進(jìn)制日志中用來(lái)表示當(dāng)前的日志事件是來(lái)自哪個(gè)主機(jī)的, 以免混淆不同的日志來(lái)源, 因此, 要給每個(gè)節(jié)點(diǎn), 配置一個(gè)與眾不同的server id
server-id=# 默認(rèn)為1, 只需要確保不同節(jié)點(diǎn), id不同即可, 一般用服務(wù)器ip的最后一位即可
-
主節(jié)點(diǎn)給每個(gè)從節(jié)點(diǎn)創(chuàng)建一個(gè)具有復(fù)制權(quán)限的賬號(hào), 專門用于從節(jié)點(diǎn)從主節(jié)點(diǎn)復(fù)制二進(jìn)制日志
grant replication slave on *.* to 'repluser'@'HOST' identified by 'replpass';
-
從節(jié)點(diǎn)啟用中繼日志
[mysqld] server_id=# #為當(dāng)前節(jié)點(diǎn)設(shè)置一個(gè)全局唯一的ID號(hào), 推薦用ip地址最后一位, 可以保證不沖突 log-bin=/data/mysql/mysql-bin #從節(jié)點(diǎn)也要啟用二進(jìn)制日志, 首先, 從節(jié)點(diǎn)以后有提升為主節(jié)點(diǎn)的可能, 同時(shí), 數(shù)據(jù)備份時(shí), 也可以利用從節(jié)點(diǎn)備份, 減少主節(jié)點(diǎn)壓力 read_only=ON #設(shè)置數(shù)據(jù)庫(kù)只讀, 針對(duì)supper user無(wú)效, 非必須選項(xiàng). 用來(lái)防止普通用戶連接到從數(shù)據(jù)庫(kù)進(jìn)行修改拌牲, 但是從節(jié)點(diǎn)的更新是不會(huì)復(fù)制到主節(jié)點(diǎn)的,就會(huì)造成數(shù)據(jù)不一致. 不過(guò)蚁滋, 該選項(xiàng)對(duì)root無(wú)效. relay_log=relay-log #relay log的文件路徑, 默認(rèn)值HOSTNAME-relay-bin, 非必須選項(xiàng) relay_log_index=relay-log.index #默認(rèn)值HOSTNAME-relay-bin.index, 非必須選項(xiàng)
-
從節(jié)點(diǎn)命令
change master to master_host='MASETHOSTIP', #在從節(jié)點(diǎn)指定主節(jié)點(diǎn)的ip master_user='repluser', # 從節(jié)點(diǎn)復(fù)制用戶 master_password='replpass', # 從節(jié)點(diǎn)復(fù)制密碼 master_log_file='mysql-bin.xxxxxx', #指明從主節(jié)點(diǎn)的哪個(gè)二進(jìn)制日志開(kāi)始復(fù)制 masterlog_pos=#; #指明二進(jìn)制日志文件的位置
-
從節(jié)點(diǎn)開(kāi)啟io thread和sql thread線程
start slave; #默認(rèn)是不開(kāi)啟的
-
如何確定從主節(jié)點(diǎn)哪個(gè)日志哪個(gè)位置開(kāi)始復(fù)制
show master logs;
7.1.3 主從復(fù)制案例-1
從0搭建主從, 主從服務(wù)器都是新的服務(wù)器, 之前沒(méi)有任何數(shù)據(jù)
環(huán)境:
CentOS 7
MySQL 5.7.31
master: 10.0.0.237
slave: 10.0.0.227
配置過(guò)程:
- 修改主節(jié)點(diǎn)配置文件
[mysqld]
datadir=/data/mysql
skip_name_resolve=1
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
log-bin=/data/mysql/mysql-bin
server-id=237
[client]
socket=/data/mysql/mysql.sock
- 創(chuàng)建二進(jìn)制日志存放路徑, 和權(quán)限
mkdir /data/mysql -pv
[root@master ~]#chown -R mysql.mysql /data/mysql
service mysqld restart
- 記錄當(dāng)前二進(jìn)制日志的位置, 此步驟要在創(chuàng)建復(fù)制賬號(hào)之前記錄, 因?yàn)閯?chuàng)建賬號(hào)后, 二進(jìn)制會(huì)被修改. 先記錄二進(jìn)制位置, 再創(chuàng)建賬號(hào), 這樣創(chuàng)建的復(fù)制賬號(hào)信息也會(huì)被記錄到二進(jìn)制日志里, 一同復(fù)制給從節(jié)點(diǎn), 以防之后主機(jī)點(diǎn)down了, 將從節(jié)點(diǎn)提升為主節(jié)點(diǎn)時(shí)還要手動(dòng)創(chuàng)建賬號(hào)
[14:07:14 root@master ~]#ll /data/mysql/mysql-bin*
-rw-r----- 1 mysql mysql 154 Nov 25 14:07 /data/mysql/mysql-bin.000001
-rw-r----- 1 mysql mysql 29 Nov 25 14:07 /data/mysql/mysql-bin.index
mysql> show master logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 154 | #從00001文件的154開(kāi)始后, 都是需要復(fù)制的信息
+------------------+-----------+
1 row in set (0.00 sec)
- 主節(jié)點(diǎn)創(chuàng)建復(fù)制授權(quán)賬號(hào)
#授權(quán)賬號(hào)的host信息要寫(xiě)成一個(gè)網(wǎng)段, 因?yàn)? 從節(jié)點(diǎn)有可能有多個(gè), 不能只寫(xiě)單個(gè)ip
mysql> grant replication slave on *.* to 'repluser'@'10.0.0.%' identified by '000000';
Query OK, 0 rows affected, 1 warning (0.01 sec)
- 從節(jié)點(diǎn)配置文件修改
[mysqld]
server-id=227
log-bin=/data/mysql/mysql-bin
read-only=ON
datadir=/data/mysql
skip_name_resolve=1
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
[client]
socket=/data/mysql/mysql.sock
chown -R mysql.mysql /data/mysql
service mysqld restart
- 從節(jié)點(diǎn)配置復(fù)制命令
mysql> CHANGE MASTER TO
-> MASTER_HOST='10.0.0.237',
-> MASTER_USER='repluser',
-> MASTER_PASSWORD='000000',
-> MASTER_PORT=3306,
-> MASTER_LOG_FILE='mysql-bin.000001',
-> MASTER_LOG_POS=154;
Query OK, 0 rows affected, 2 warnings (0.02 sec)
- 從節(jié)點(diǎn)執(zhí)行了change master to后會(huì)在MySQL數(shù)據(jù)目錄生成新的文件
-rw-r----- 1 mysql mysql 154 Nov 25 14:23 slave-relay-bin.000001 #從節(jié)點(diǎn)中繼日志
-rw-r----- 1 mysql mysql 25 Nov 25 14:23 slave-relay-bin.index #從節(jié)點(diǎn)中繼日志文件信息
-rw-r----- 1 mysql mysql 57 Nov 25 14:23 relay-log.info #中繼日志信息, 存放中繼日志和主節(jié)點(diǎn)二進(jìn)制日志的對(duì)應(yīng)關(guān)系
-rw-r----- 1 mysql mysql 90 Nov 25 14:23 master.info #復(fù)制信息, 存放chang master to命令的參數(shù)信息,
[03:38:41 root@slave ~]#cat /data/mysql/master.info
25
mysql-bin.000001
154
10.0.0.237
repluser
000000
3306
60
0
0
30.000
0
86400
0
[03:39:44 root@slave ~]#cat /data/mysql/relay-log.info
7
./slave-relay-bin.000001 # 中繼日志的POS=4對(duì)應(yīng)主節(jié)點(diǎn)二進(jìn)制日志的POS=154
4
mysql-bin.000001
154
0
0
1
- 觀察從節(jié)點(diǎn)的信息
#執(zhí)行change master to命令后, 可以在從節(jié)點(diǎn)觀察狀態(tài), 尤其要注意Slave_IO_Running: No
和Slave_SQL_Running: No, 兩個(gè)值, 如果出現(xiàn)NO, 就說(shuō)明主從復(fù)制出現(xiàn)問(wèn)題, 該值需要做監(jiān)控, 這里為NO, 是因?yàn)闀簳r(shí)還沒(méi)有開(kāi)啟兩個(gè)線程
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 10.0.0.237
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 154
Relay_Log_File: slave-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: No
Slave_SQL_Running: No
...
Seconds_Behind_Master: NULL #這里表示了主從復(fù)制的延遲時(shí)間, 也需要進(jìn)行監(jiān)控
- 從節(jié)點(diǎn)啟動(dòng)SQL和IO線程
mysql> start slave;
Query OK, 0 rows affected (0.02 sec)
- 開(kāi)啟兩個(gè)線程后, 會(huì)在主從節(jié)點(diǎn)生成用來(lái)進(jìn)行復(fù)制同步的tcp連接
#主節(jié)點(diǎn)
[03:38:35 root@master ~]#ss -nt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0 0 [::ffff:10.0.0.237]:3306 [::ffff:10.0.0.227]:50336
#從節(jié)點(diǎn)
[03:40:13 root@slave ~]#ss -nt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0 0 10.0.0.227:50336 10.0.0.237:3306
- 開(kāi)啟后, 主節(jié)點(diǎn)會(huì)生成dump線程, 從節(jié)點(diǎn)生成sql和io線程
mysql> show processlist;
+----+----------+------------------+------+-------------+------+---------------------------------------------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+----------+------------------+------+-------------+------+---------------------------------------------------------------+------------------+
| 4 | repluser | 10.0.0.227:43156 | NULL | Binlog Dump(主節(jié)點(diǎn)dump線程) | 34 | Master has sent all binlog to slave; waiting for more updates | NULL |
| 5 | root | localhost | NULL | Query | 0 | starting | show processlist |
+----+----------+------------------+------+-------------+------+---------------------------------------------------------------+------------------+
2 rows in set (0.00 sec)
mysql> show processlist;
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------+
| 2 | root | localhost | NULL | Query | 0 | starting | show processlist |
| 3 | system user | | NULL | Connect(從節(jié)點(diǎn)io線程) | 58 | Waiting for master to send event | NULL |
| 4 | system user | | NULL | Connect(從節(jié)點(diǎn)sql線程) | 716 | Slave has read all relay log; waiting for more updates | GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'10.0.0.%' IDENTIFIED WITH 'mysql_native_password' AS ' |
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------+
3 rows in set (0.00 sec)
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.0.0.237
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 448
Relay_Log_File: slave-relay-bin.000002
Relay_Log_Pos: 614
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
測(cè)試同步是否成功:
- 檢查從節(jié)點(diǎn)是否有repluser賬號(hào)
mysql> select user,host from mysql.user;
+---------------+-----------+
| user | host |
+---------------+-----------+
| repluser | 10.0.0.% |
- 觀察slave狀態(tài)
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Exec_Master_Log_Pos: 448 #主節(jié)點(diǎn)最新的二進(jìn)制位置, 目前和主節(jié)點(diǎn)的show master logs值是對(duì)應(yīng)的
Seconds_Behind_Master: 0 #主從復(fù)制延遲為0
- 主節(jié)點(diǎn)導(dǎo)入hellodb數(shù)據(jù), 在從節(jié)點(diǎn)測(cè)試
[14:43:27 root@master ~]#mysql < hellodb_innodb.sql
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| hellodb | #數(shù)據(jù)庫(kù)成功復(fù)制
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
7.1.4 主從復(fù)制案例-2
單獨(dú)添加新的從節(jié)點(diǎn)
部署思路:
- 先在主節(jié)點(diǎn)做一次完全備份, 把現(xiàn)有數(shù)據(jù)都導(dǎo)出來(lái)
- 找到主節(jié)點(diǎn)完全備份時(shí)的二進(jìn)制位置
- 從節(jié)點(diǎn)導(dǎo)入完全備份數(shù)據(jù)
- 從節(jié)點(diǎn)開(kāi)啟二進(jìn)制, 位置指向主節(jié)點(diǎn)備份文件中的change master to位置
環(huán)境:
主節(jié)點(diǎn)還是10.0.0.237
新的從節(jié)點(diǎn)10.0.0.217
步驟:
- 主節(jié)點(diǎn)做完全備份
[14:43:38 root@master ~]#mysqldump -A -F --single-transaction --master-data=1 > /data/allbackup_`date +%F_%T`.sql
[03:49:10 root@master ~]#ll /data/allbackup_2021-06-16_03\:49\:05.sql
-rw-r--r-- 1 root root 869712 Jun 16 03:49 /data/allbackup_2021-06-16_03:49:05.sql
- 將完全備份拷貝到從節(jié)點(diǎn)
[13:53:56 root@mysql-master ~]#scp /data/allbackup_2021-06-14_13\:52\:10.sql 10.0.0.217:/root
- 新的從節(jié)點(diǎn)配置MySQL
[mysqld]
server-id=217
log-bin=/data/mysql/mysql-bin
datadir=/data/mysql
skip_name_resolve=1
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
[client]
socket=/data/mysql/mysql.sock
service mysqld restart
- 開(kāi)啟從節(jié)點(diǎn)復(fù)制
#可以直接從完全備份文件中獲取主節(jié)點(diǎn)二進(jìn)制文件和記錄位置, 直接把change master to命令寫(xiě)到完全備份文件里, 統(tǒng)一導(dǎo)入到從節(jié)點(diǎn)
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=154;
# 因?yàn)樵趍aster節(jié)點(diǎn)執(zhí)行了備份浊猾,所以會(huì)刷新一次日志顿痪, 生成新的mysql-bin.000002
CHANGE MASTER TO
MASTER_HOST='10.0.0.237',
MASTER_USER='repluser',
MASTER_PASSWORD='000000',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000002',
MASTER_LOG_POS=154;
mysql> set sql_log_bin=off;
mysql> source /root/allbackup_2020-11-25_14\:52\:27.sql
mysql> set sql_log_bin=on;
- 導(dǎo)入完全備份文件后, 查看從節(jié)點(diǎn)狀態(tài)
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 10.0.0.237
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 154
Relay_Log_File: slave-2-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: No #此時(shí)線程還是關(guān)閉的, 不過(guò)沒(méi)關(guān)系, 此時(shí)即使主節(jié)點(diǎn)還在寫(xiě)數(shù)據(jù), 從節(jié)點(diǎn)也是從change mater to定義好的主節(jié)點(diǎn)二進(jìn)制文件和位置開(kāi)始同步
Slave_SQL_Running: No
- 主節(jié)點(diǎn)修改數(shù)據(jù)
mysql> use hellodb;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> insert teachers (name,age,gender) value('zhao',18,'M');
Query OK, 1 row affected (0.00 sec)
mysql> insert teachers (name,age,gender) value('qian',18,'M');
Query OK, 1 row affected (0.01 sec)
- 驗(yàn)證從節(jié)點(diǎn)開(kāi)始線程后, 修改的數(shù)據(jù)能正常同步
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from hellodb.teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 93 | F |
| 5 | zhao | 18 | M | #主節(jié)點(diǎn)在從節(jié)點(diǎn)開(kāi)始線程前添加的數(shù)據(jù)也能正常復(fù)制
| 6 | qian | 18 | M |
+-----+---------------+-----+--------+
- 觀察主從節(jié)點(diǎn)各種的線程
#由于有兩個(gè)從節(jié)點(diǎn), 因此主節(jié)點(diǎn)會(huì)為每個(gè)從節(jié)點(diǎn)開(kāi)啟單獨(dú)的dump線程
mysql> show processlist;
+----+----------+-----------------+---------+-------------+------+---------------------------------------------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+----------+-----------------+---------+-------------+------+---------------------------------------------------------------+------------------+
| 3 | repluser | 10.0.0.52:33918 | NULL | Binlog Dump | 8026 | Master has sent all binlog to slave; waiting for more updates | NULL |
| 7 | root | localhost | hellodb | Query | 0 | starting | show processlist |
| 8 | repluser | 10.0.0.53:57096 | NULL | Binlog Dump | 147 | Master has sent all binlog to slave; waiting for more updates | NULL |
+----+----------+-----------------+---------+-------------+------+---------------------------------------------------------------+------------------+
3 rows in set (0.00 sec)
#新添加的從節(jié)點(diǎn)也正常開(kāi)啟了復(fù)制線程
mysql> show processlist;
+----+-------------+-----------+--------------------+---------+------+--------------------------------------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-------------+-----------+--------------------+---------+------+--------------------------------------------------------+------------------+
| 2 | root | localhost | #mysql50#mysql-bin | Query | 0 | starting | show processlist |
| 3 | system user | | NULL | Connect | 197 | Waiting for master to send event | NULL |
| 4 | system user | | NULL | Connect | 277 | Slave has read all relay log; waiting for more updates | NULL |
+----+-------------+-----------+--------------------+---------+------+--------------------------------------------------------+------------------+
3 rows in set (0.00 sec)
7.1.5 主從復(fù)制案例-3
主節(jié)點(diǎn)宕機(jī), 如何提升從節(jié)點(diǎn)為主節(jié)點(diǎn)
- 確定哪個(gè)從節(jié)點(diǎn)對(duì)應(yīng)的主節(jié)點(diǎn)二進(jìn)制位置是更新的, 提升數(shù)據(jù)較新的那個(gè)從節(jié)點(diǎn)為主節(jié)點(diǎn). 因?yàn)閺墓?jié)點(diǎn)同步到的主節(jié)點(diǎn)的二進(jìn)制位置, 就決定了數(shù)據(jù)的新舊
方法1. 從節(jié)點(diǎn)使用show slave status;查看
方法2. 從節(jié)點(diǎn)查看relay-log.info
方法1:show slave status, 查看Master_Log_File和Read_Log_Pos
- 10.0.0.227 slave-1
-
10.0.0.217 slave-2
方法2: 從節(jié)點(diǎn)查看relay-log.info文件
10.0.0.227 slave-1
[04:08:25 root@slave ~]#cat /data/mysql/relay-log.info
7
./slave-relay-bin.000004
923
mysql-bin.000002
710
0
0
1
1
10.0.0.217 slave-2
[04:08:47 root@slave-2 ~]#cat /data/mysql/relay-log.info
7
./slave-2-relay-bin.000002
876
mysql-bin.000002
710
0
0
1
- 實(shí)際生產(chǎn)中, 可以借助軟件, 實(shí)現(xiàn)對(duì)從節(jié)點(diǎn)的監(jiān)控溜宽,自動(dòng)監(jiān)控哪個(gè)從節(jié)點(diǎn)的日志更新碰凶, 然后提升為主節(jié)點(diǎn)
案例: 假設(shè)10.0.0.227-slave-1的從節(jié)點(diǎn)的二進(jìn)制是更新的故俐,關(guān)閉主節(jié)點(diǎn)服務(wù)器分瘾, 提升slave-1為主節(jié)點(diǎn)
- 先關(guān)閉主節(jié)點(diǎn)服務(wù)器胎围, 或者停止mysql服務(wù)也可, 之后從節(jié)點(diǎn)會(huì)立即報(bào)錯(cuò)
Last_IO_Error: error reconnecting to master 'repluser@10.0.0.237:3306' - retry-time: 60 retries: 2
- 提升10.0.0.227-slave-1為主節(jié)點(diǎn)德召, 修改配置文件白魂, 關(guān)閉read-only配置
需要先記錄新的主節(jié)點(diǎn)復(fù)制到了舊的主節(jié)點(diǎn)的那個(gè)二進(jìn)制位置, 之后基于這個(gè)位置上岗, 從舊的主節(jié)點(diǎn)利用mysqlbinlog把未導(dǎo)入的數(shù)據(jù)同步給新的主節(jié)點(diǎn)
因?yàn)橹鞴?jié)點(diǎn)宕機(jī)時(shí), 可以還存在一部分未同步給從節(jié)點(diǎn)的數(shù)據(jù)
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Reconnecting after a failed master event read
Master_Host: 10.0.0.237
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 710 # 當(dāng)前復(fù)制到了主節(jié)點(diǎn)的710位置
[04:08:30 root@slave ~]#vim /etc/my.cnf
[mysqld]
server-id=227
log-bin=/data/mysql/mysql-bin
read-only=OFF
[04:11:19 root@slave ~]#service mysqld restart
# 也可以臨時(shí)關(guān)閉read_only
set global read_only=off;
- 清除舊的主節(jié)點(diǎn)信息
10.0.0.227-slave-1
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> reset slave all;
Query OK, 0 rows affected (0.00 sec)
# reset slave all后, 從節(jié)點(diǎn)原本的master.info, relay-log.info和已經(jīng)產(chǎn)生的中繼日志文件都會(huì)被清除, 只留一個(gè)slave-relay-bin.000001, 表示開(kāi)始新的relay-log
- 在新的主節(jié)點(diǎn)進(jìn)行完全備份
[04:14:47 root@slave ~]#mysqldump -A --single-transaction --master-data=1 -F > backup.sql
分析舊的master日志福荸, 根據(jù)新的master此前記錄的同步到的二進(jìn)制位置, 利用mysqlbinlog把未同步的數(shù)據(jù)導(dǎo)出來(lái)
將導(dǎo)出來(lái)的數(shù)據(jù)肴掷, 導(dǎo)入給新的master敬锐, 由于新的master是開(kāi)啟了二進(jìn)制的, 因此呆瞻, 導(dǎo)入過(guò)程會(huì)被記錄到二進(jìn)制
此時(shí)台夺, 新的master理想情況下, 就有了全部的數(shù)據(jù)痴脾, 之后修改新的master的完全備份文件颤介, 添加change master to, 然后導(dǎo)入到其他從節(jié)點(diǎn)赞赖, 這樣其他從節(jié)點(diǎn)就可以有全部的數(shù)據(jù)
首先滚朵, 其余從節(jié)點(diǎn)因?yàn)閺?fù)制的內(nèi)容少于新的master, 因此前域, 需要利用新的master的完全備份辕近, 同步到和新的master一樣的數(shù)據(jù), 然后因?yàn)樾碌膍aster會(huì)導(dǎo)入舊的master未同步的數(shù)據(jù)匿垄, 并且記錄到本地二進(jìn)制移宅,這樣在完全備份中指定二進(jìn)制位置是新的master還未導(dǎo)入舊的master未同步的數(shù)據(jù)的時(shí)刻,因此剩下的slave也會(huì)把未同步的信息同步
修改backup.sql年堆,指定新的master節(jié)點(diǎn)
CHANGE MASTER TO
MASTER_HOST='10.0.0.227',
MASTER_USER='repluser',
MASTER_PASSWORD='000000',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=154;
[04:17:12 root@slave ~]#scp backup.sql 10.0.0.217:/root
- 其余slave重新指定master
mysql> stop slave;
mysql> reset slave all;
mysql> set sql_log_bin=off;
mysql> source backup.sql;
mysql> set sql_log_bin=on;
mysql> start slave;
- 驗(yàn)證主從同步
10.0.0.227-新的master
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 | 154 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
10.0.0.217-slave-2
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.0.0.227
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000003
Read_Master_Log_Pos: 154
Relay_Log_File: slave-2-relay-bin.000002
Relay_Log_Pos: 320
Relay_Master_Log_File: mysql-bin.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
mysql> create database master_slave;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| hellodb |
| master_slave |
| mysql |
| performance_schema |
| sys |
| testdb |
| testdb2 |
+--------------------+
8 rows in set (0.01 sec)
- 之后故障的master需要重新添加到主從,需要新的master做完全備份盏浇, 然后修改change master to. 然后变丧,故障主節(jié)點(diǎn)清除主從信息, 重新添加主從
主從總結(jié):
1. 主從架構(gòu)绢掰, 從節(jié)點(diǎn)即使開(kāi)啟了二進(jìn)制痒蓬,默認(rèn)也是不會(huì)記錄新的童擎, 數(shù)據(jù)從主節(jié)點(diǎn)同步到中繼日志,然后直接寫(xiě)入到數(shù)據(jù)庫(kù)
2. 如果需要利用從節(jié)點(diǎn)做備份的話攻晒, 那么可以在從節(jié)點(diǎn)做完全備份顾复, 至于二進(jìn)制日志,需要在從節(jié)點(diǎn)配置文件指定log-slave-updates, 這樣從節(jié)點(diǎn)也會(huì)記錄二進(jìn)制日志到本地鲁捏, 之后就可以直接在從節(jié)點(diǎn)做備份了
3. 主從故障芯砸, 會(huì)造成主節(jié)點(diǎn)無(wú)法寫(xiě)入數(shù)據(jù),業(yè)務(wù)中斷给梅, 讀業(yè)務(wù)暫時(shí)不受影響
4. 不過(guò)假丧, 如果是手動(dòng)切換,因?yàn)橐馁M(fèi)時(shí)間去判斷故障主節(jié)點(diǎn)還有那些數(shù)據(jù)沒(méi)有同步給提升的主節(jié)點(diǎn)动羽, 之后導(dǎo)入數(shù)據(jù)包帚, 因此會(huì)有業(yè)務(wù)中斷. 并且程序代碼也要切換主從節(jié)點(diǎn)
5. 因此,主從需要配合程序完成自動(dòng)切換运吓,否則手動(dòng)切換不建議使用
7.1.6 主從復(fù)制相關(guān)
7.1.6.1 清除從節(jié)點(diǎn)主從復(fù)制信息
當(dāng)主服務(wù)器宕機(jī), 提升了一個(gè)從節(jié)點(diǎn)為主節(jié)點(diǎn)后, 其他從節(jié)點(diǎn)需要重新指到新的主節(jié)點(diǎn), 此時(shí)需要先停止其他從節(jié)點(diǎn)的slave, 然后清除slave信息.
清除slave信息有兩個(gè)方法, 不過(guò)都要先停止slave
mysql> stop slave;
方法1:
mysql> reset slave all; #清除所有從服務(wù)器上設(shè)置的主服務(wù)器同步信息, 如: HOST, PORT, USER和PASSWORD等, 這種方式清除的更徹底
方法2:
mysql> reset slave; #從服務(wù)器清除master.info, relay-log.info, relay log, 開(kāi)始新的relay log
#執(zhí)行reset slave all后, 所有關(guān)于主從復(fù)制的文件都被刪除, 生成新的relay-log文件slave-relay-bin.000001
[17:17:41 root@slave ~]#ll /data/mysql
total 123008
-rw-r----- 1 mysql mysql 56 Nov 25 00:05 auto.cnf
-rw------- 1 mysql mysql 1680 Nov 25 00:05 ca-key.pem
-rw-r--r-- 1 mysql mysql 1112 Nov 25 00:05 ca.pem
-rw-r--r-- 1 mysql mysql 1112 Nov 25 00:05 client-cert.pem
-rw------- 1 mysql mysql 1676 Nov 25 00:05 client-key.pem
drwxr-x--- 2 mysql mysql 272 Nov 25 14:43 hellodb
-rw-r----- 1 mysql mysql 293 Nov 25 14:18 ib_buffer_pool
-rw-r----- 1 mysql mysql 12582912 Nov 25 16:45 ibdata1
-rw-r----- 1 mysql mysql 50331648 Nov 25 16:45 ib_logfile0
-rw-r----- 1 mysql mysql 50331648 Nov 25 00:05 ib_logfile1
-rw-r----- 1 mysql mysql 12582912 Nov 25 14:18 ibtmp1
drwxr-x--- 2 mysql mysql 4096 Nov 25 00:05 mysql
-rw-r----- 1 mysql mysql 154 Nov 25 14:18 mysql-bin.000001
-rw-r----- 1 mysql mysql 29 Nov 25 14:18 mysql-bin.index
-rw-r----- 1 mysql mysql 36039 Nov 25 17:15 mysql.log
-rw-r----- 1 mysql mysql 5 Nov 25 14:18 mysql.pid
srwxrwxrwx 1 mysql mysql 0 Nov 25 14:18 mysql.sock
-rw------- 1 mysql mysql 5 Nov 25 14:18 mysql.sock.lock
drwxr-x--- 2 mysql mysql 8192 Nov 25 00:05 performance_schema
-rw------- 1 mysql mysql 1676 Nov 25 00:05 private_key.pem
-rw-r--r-- 1 mysql mysql 452 Nov 25 00:05 public_key.pem
-rw-r--r-- 1 mysql mysql 1112 Nov 25 00:05 server-cert.pem
-rw------- 1 mysql mysql 1680 Nov 25 00:05 server-key.pem
-rw-r----- 1 mysql mysql 177 Nov 25 17:15 slave-relay-bin.000001
-rw-r----- 1 mysql mysql 25 Nov 25 17:15 slave-relay-bin.index
drwxr-x--- 2 mysql mysql 8192 Nov 25 00:05 sys
#slave信息也被刪除
mysql> show slave status \G
Empty set (0.00 sec)
7.1.6.2 主從復(fù)制沖突, 造成數(shù)據(jù)無(wú)法同步的問(wèn)題和解決方法
由于從節(jié)點(diǎn)沒(méi)有設(shè)置read_only=on, 只讀, 造成從節(jié)點(diǎn)也可以修改數(shù)據(jù), 此時(shí)比如從節(jié)點(diǎn)增加了一行數(shù)據(jù), 然后如果主節(jié)點(diǎn)也增了一行數(shù)據(jù), 并且存在主鍵沖突時(shí), 那么這時(shí)數(shù)據(jù)同步就會(huì)失敗
案例演示
- 從節(jié)點(diǎn)增加一行數(shù)據(jù), 10.0.0.217
mysql> use hellodb;
mysql> select * from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 93 | F |
| 5 | zhao | 18 | M |
| 6 | qian | 18 | M |
+-----+---------------+-----+--------+
6 rows in set (0.00 sec)
mysql> insert teachers (name,age,gender) value ('haha',19,'M');
Query OK, 1 row affected (0.01 sec)
- 主節(jié)點(diǎn)增加數(shù)據(jù), 10.0.0.227
mysql> use hellodb;
mysql> select * from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 93 | F |
| 5 | zhao | 18 | M |
| 6 | qian | 18 | M |
+-----+---------------+-----+--------+
6 rows in set (0.00 sec)
mysql> insert teachers (name,age,gender) value ('lala',19,'M');
Query OK, 1 row affected (0.00 sec)
此時(shí), 雖然主從節(jié)點(diǎn)增加的數(shù)據(jù)不同, 但是從節(jié)點(diǎn)增加的數(shù)據(jù)主鍵位為7, 主節(jié)點(diǎn)增加的數(shù)據(jù)主鍵位也為7, 那么主節(jié)點(diǎn)向從節(jié)點(diǎn)同步自己增加的主鍵為7的數(shù)據(jù)時(shí)就會(huì)沖突, 因?yàn)橹麈I7在從節(jié)點(diǎn)已經(jīng)有了
#從節(jié)點(diǎn)觀察show slave status;信息
Last_SQL_Error: Could not execute Write_rows event on table hellodb.teachers; Duplicate entry '7' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin.000002, end_log_pos 1513
#這時(shí)產(chǎn)生的錯(cuò)誤是SQL線程錯(cuò)誤, 也就是把數(shù)據(jù)從中繼日志寫(xiě)到從節(jié)點(diǎn)數(shù)據(jù)庫(kù)時(shí)產(chǎn)生的錯(cuò)誤
- 一旦發(fā)生數(shù)據(jù)沖突, 往后的所有數(shù)據(jù)都不會(huì)同步了
解決方法
- 可以在從服務(wù)器忽略主服務(wù)器的復(fù)制事件個(gè)數(shù), 此為global變量, 或指定跳過(guò)事件的ID
#系統(tǒng)變量, 指定跳過(guò)復(fù)制事件的個(gè)數(shù)
#在出現(xiàn)問(wèn)題的從節(jié)點(diǎn)上執(zhí)行
mysql> set global sql_slave_skip_counter=1; # 出現(xiàn)幾個(gè)sql錯(cuò)誤渴邦, 就跳過(guò)幾次
Query OK, 0 rows affected (0.00 sec)
mysql> stop slave; #關(guān)閉slave
mysql> start slave; #再開(kāi)啟slave
#驗(yàn)證SQL錯(cuò)誤消失即可
此時(shí), 觀察從節(jié)點(diǎn)復(fù)制到的位置id
Master_Log_File: mysql-bin.000003
Read_Master_Log_Pos: 615
驗(yàn)證主節(jié)點(diǎn)二進(jìn)制位置, 兩個(gè)id相等, 就說(shuō)明同步正常了, 此時(shí)在出現(xiàn)沖突后主節(jié)點(diǎn)寫(xiě)入的數(shù)據(jù), 都會(huì)同步給從節(jié)點(diǎn)
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 | 615 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
但是, 這種情況下, 那條沖突的數(shù)據(jù), 由于在從節(jié)點(diǎn)已經(jīng)被忽略, 因此主節(jié)點(diǎn)不會(huì)再向從節(jié)點(diǎn)同步那條數(shù)據(jù), 這時(shí)主從節(jié)點(diǎn)是不一樣的, 如果只有一條, 那么只需在從節(jié)點(diǎn)修改, 按照主節(jié)點(diǎn)數(shù)據(jù)修改即可, 如果多的話就要再分析了
對(duì)于錯(cuò)誤沖突數(shù)據(jù)很多的情況下, 可以直接在從節(jié)點(diǎn)配置文件中指定, 略過(guò)所有的沖突, 之后重啟服務(wù)
[mysqld]
slave_skip_errors=ALL #也可以單獨(dú)指定SQL ERROR ID, 該ID就是從show slave status;報(bào)錯(cuò)得來(lái)的, Last_SQL_ERROR值
7.1.6.3 從節(jié)點(diǎn)服務(wù)器如果重啟, 那么從節(jié)點(diǎn)的兩個(gè)復(fù)制線程會(huì)默認(rèn)自動(dòng)開(kāi)啟
從節(jié)點(diǎn)服務(wù)器選項(xiàng)
skip-slave-start=ON #服務(wù)重啟后不自動(dòng)開(kāi)啟兩個(gè)IO和SQL線程
7.1.6.4 保證主從復(fù)制的事務(wù)安全
- 在master節(jié)點(diǎn)啟用參數(shù)
sync_binlog=1 #每次寫(xiě)數(shù)據(jù)拘哨, 立即同步二進(jìn)制日志到磁盤谋梭, 性能差, 但是安全
# InnoDB引擎參數(shù)
innodb_flush_log_at_trx_commit=1 # 每次提交事務(wù)宅静, 立即同步日志寫(xiě)磁盤
sync_master_info=# # 多少次事件后master.info同步到磁盤
- 在slave節(jié)點(diǎn)啟用參數(shù)
sync_relay_log=# 多少次寫(xiě)后同步relay log到磁盤
sync_relay_log_info=# 多少次事務(wù)后章蚣,同步relay-log.info到磁盤
7.2 級(jí)聯(lián)復(fù)制
級(jí)聯(lián)復(fù)制可以用來(lái)減少主服務(wù)器的壓力, 正常的一主多從, 要求主服務(wù)器負(fù)責(zé)寫(xiě)數(shù)據(jù), 還要根據(jù)后端不同數(shù)量的從服務(wù)器開(kāi)啟不同的復(fù)制線程, 每個(gè)線程都會(huì)消耗資源,
有了中間節(jié)點(diǎn), 主節(jié)點(diǎn)只需要開(kāi)啟一個(gè)dump線程把數(shù)據(jù)同步給中間節(jié)點(diǎn), 其余從節(jié)點(diǎn)由中間節(jié)點(diǎn)去負(fù)責(zé)同步
7.2.1 實(shí)現(xiàn)級(jí)聯(lián)復(fù)制要求
- 中間節(jié)點(diǎn)開(kāi)啟二進(jìn)制, 這樣另一個(gè)從節(jié)點(diǎn)才能從中間節(jié)點(diǎn)復(fù)制數(shù)據(jù)
- 中間節(jié)點(diǎn)開(kāi)啟log-slave-updates 中間節(jié)點(diǎn)必配置, 啟用后從節(jié)點(diǎn)會(huì)把從主節(jié)點(diǎn)接收到的數(shù)據(jù)也寫(xiě)入自己的二進(jìn)制日志中, 這樣才能把數(shù)據(jù)再?gòu)?fù)制給其他從節(jié)點(diǎn)
MySQL工作時(shí),每個(gè)二進(jìn)制日志只記錄當(dāng)前自己這臺(tái)服務(wù)器的操作,從節(jié)點(diǎn)從主節(jié)點(diǎn)獲得的二進(jìn)制會(huì)寫(xiě)到數(shù)據(jù)庫(kù)里, 但是不會(huì)寫(xiě)到二進(jìn)制日志, 但是其他從節(jié)點(diǎn)是要從中間節(jié)點(diǎn)的二進(jìn)制日志獲取數(shù)據(jù)的, 這就要求中間節(jié)點(diǎn)從主節(jié)點(diǎn)獲取的二進(jìn)制信息也要寫(xiě)入自己的二進(jìn)制日志里, 同時(shí)自身發(fā)生的操作也寫(xiě)到二進(jìn)制日志里
實(shí)現(xiàn)級(jí)聯(lián)復(fù)制
10.0.0.237-主節(jié)點(diǎn)
10.0.0.227-作為中間節(jié)點(diǎn)
10.0.0.217作為從節(jié)點(diǎn), 建議找一個(gè)干凈的mysql環(huán)境. 因?yàn)閺墓?jié)點(diǎn)一旦有多于中間節(jié)點(diǎn)和主節(jié)點(diǎn)的數(shù)據(jù), 那么會(huì)保留姨夹, 造成數(shù)據(jù)不一致
步驟:
- 三臺(tái)服務(wù)器安裝mysql
- 配置主節(jié)點(diǎn)
server-id=237
log-bin=/data/mysql/mysql-bin
service mysqld restart
mysql> show master logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 154 |
+------------------+-----------+
1 row in set (0.00 sec)
grant replication slave on *.* to 'repluser'@'10.0.0.%' identified by '000000';
3 . 配置中間節(jié)點(diǎn)
[mysqld]
log-slave-updates
log-bin=/data/mysql/mysql-bin
server-id=227
service mysqld restart
mysql> CHANGE MASTER TO
-> MASTER_HOST='10.0.0.237',
-> MASTER_USER='repluser',
-> MASTER_PASSWORD='000000',
-> MASTER_PORT=3306,
-> MASTER_LOG_FILE='mysql-bin.000001',
-> MASTER_LOG_POS=154;
Query OK, 0 rows affected, 2 warnings (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
- 確保中間節(jié)點(diǎn)有復(fù)制賬號(hào)
mysql> select user,host from mysql.user;
+---------------+-----------+
| user | host |
+---------------+-----------+
| repluser | 10.0.0.% |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+---------------+-----------+
4 rows in set (0.00 sec)
- 主節(jié)點(diǎn)導(dǎo)入hellodb數(shù)據(jù)庫(kù)纤垂, 確保能同步給中間節(jié)點(diǎn), 并且中間節(jié)點(diǎn)會(huì)記錄二進(jìn)制日志到本地
[12:02:48 root@master ~]#mysql < hellodb_innodb.sql
- 中間節(jié)點(diǎn)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| hellodb |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
- 查看中間節(jié)點(diǎn)二進(jìn)制
[12:03:51 root@mid ~]#ll /data/mysql/mysql-bin.000001
-rw-r----- 1 mysql mysql 10147 Jun 15 12:02 /data/mysql/mysql-bin.000001 # 已經(jīng)更新
- 在中間節(jié)點(diǎn)做數(shù)據(jù)完全備份, 需要先確保中間節(jié)點(diǎn)和主節(jié)點(diǎn)是同步的, 查看POS ID
mysql> show master logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 10219 |
+------------------+-----------+
1 row in set (0.00 sec)
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 10219
[12:05:01 root@mid ~]#mysqldump -A -F --master-data=1 --single-transaction > /data/new_all.sql
[12:05:13 root@mid ~]#ll /data/
total 8
-rw-r--r-- 1 root root 203 Jun 15 12:05 new_all.sql
- 復(fù)制到從節(jié)點(diǎn)
[12:05:16 root@mid ~]#scp /data/new_all.sql 10.0.0.217:/root
- 從節(jié)點(diǎn)配置文件
[mysqld]
server-id=217 #server-id不能沖突
log-bin=/data/mysql/mysql-bin
datadir=/data/mysql
skip_name_resolve=1
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
[client]
socket=/data/mysql/mysql.sock
- 創(chuàng)建二進(jìn)制路徑
[18:21:56 root@slave ~]#mkdir -pv /data/mysql/
[18:22:01 root@slave ~]#chown -R mysql.mysql /data/mysql
[12:13:15 root@slave ~]#service mysqld restart
- 導(dǎo)入完全備份
CHANGE MASTER TO
MASTER_HOST='10.0.0.227',
MASTER_USER='repluser',
MASTER_PASSWORD='000000',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=154;
[12:18:55 root@slave ~]#mysql < new_all.sql
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
- 確保三臺(tái)服務(wù)器主從復(fù)制位置一致磷账, 數(shù)據(jù)一致
從服務(wù)器的二進(jìn)制位置要和中間節(jié)點(diǎn)一致
中間節(jié)點(diǎn)要和主服務(wù)器一致
mysql> create database db1;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| hellodb |
| mysql |
| performance_schema |
| sys |
+--------------------+
6 rows in set (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| hellodb |
| mysql |
| performance_schema |
| sys |
+--------------------+
6 rows in set (0.00 sec)
- 總結(jié)
單純的主從峭沦, 需要根據(jù)從節(jié)點(diǎn)的個(gè)數(shù)建立對(duì)應(yīng)的dump線程,對(duì)主節(jié)點(diǎn)壓力很大
級(jí)聯(lián)復(fù)制可以減輕主節(jié)點(diǎn)壓力, 但從節(jié)點(diǎn)的復(fù)制效率不如單純的主從
如果是多機(jī)房情況下逃糟,可以考慮級(jí)聯(lián)復(fù)制吼鱼, 每個(gè)機(jī)房找一個(gè)節(jié)點(diǎn),和主服務(wù)器進(jìn)行同步
7.3 雙主復(fù)制
雙主復(fù)制: 兩個(gè)節(jié)點(diǎn), 都可以更新數(shù)據(jù), 并且互為主從
容易產(chǎn)生的問(wèn)題: 數(shù)據(jù)不一致, 因此慎用, 如果兩臺(tái)服務(wù)器同時(shí)寫(xiě)入數(shù)據(jù), 并且數(shù)據(jù)的主鍵相等, 就會(huì)出現(xiàn)沖突
雙主的好處: 配合讀寫(xiě)分離器, 實(shí)現(xiàn)寫(xiě)操作只調(diào)度到一個(gè)主節(jié)點(diǎn), 讀操作調(diào)度到另一節(jié)點(diǎn), 類似主從. 不過(guò), 因?yàn)楸旧砼涞亩际侵鞴?jié)點(diǎn), 因此, 一旦負(fù)責(zé)寫(xiě)操作的主節(jié)點(diǎn)宕機(jī), 可以直接把請(qǐng)求調(diào)度到另一個(gè)主節(jié)點(diǎn), 省去了主從手動(dòng)切換的過(guò)程
考慮要點(diǎn): 自動(dòng)增長(zhǎng)id
解決方法:
搭建雙主, 通過(guò)前端分離器實(shí)現(xiàn)寫(xiě)操作往一個(gè)服務(wù)器調(diào)度, 讀操作往另一個(gè)服務(wù)器調(diào)度, 這樣就不會(huì)出現(xiàn)同時(shí)寫(xiě)操作的情況, 可以避免主鍵id沖突
兩個(gè)節(jié)點(diǎn)分別使用不同的主鍵id增長(zhǎng)策略, 一個(gè)節(jié)點(diǎn)配置奇數(shù)增長(zhǎng), 一個(gè)節(jié)點(diǎn)配置偶數(shù)增長(zhǎng)
節(jié)點(diǎn)1:
auto_increment_offset=1 #開(kāi)始點(diǎn)
auto_increment_increment=2 #增長(zhǎng)幅度, 實(shí)現(xiàn)奇數(shù)增長(zhǎng)
節(jié)點(diǎn)2:
auto_increment_offset=2 #開(kāi)始點(diǎn)
auto_increment_increment2 #增長(zhǎng)幅度, 實(shí)現(xiàn)偶數(shù)增長(zhǎng)
7.3.1 雙主復(fù)制的配置步驟
各節(jié)點(diǎn)使用一個(gè)唯一的server-id
都啟用binary log和relay log
創(chuàng)建擁有復(fù)制權(quán)限的用戶賬號(hào)
定義自動(dòng)增長(zhǎng)id字段的數(shù)字范圍各為奇偶
均把對(duì)方指定為主節(jié)點(diǎn), 并啟動(dòng)復(fù)制線程
7.3.2 配置案例
雙主:
CentOS 7
MySQL 5.7.31
10.0.0.237
10.0.0.227
10.0.0.237配置
[12:44:37 root@master-1 ~]#vim /etc/my.cnf
[mysqld]
server-id=237
log-bin=/data/mysql/mysql-bin
auto_increment_offset=1
auto_increment_increment=2
10.0.0.227配置
[12:40:36 root@master-2 ~]#vim /etc/my.cnf
server-id=227
log-bin=/data/mysql/mysql-bin
auto_increment_offset=2
auto_increment_increment=2
10.0.0.237
配置后重啟服務(wù), 生成二進(jìn)制日志
[12:44:37 root@master-1 ~]#service mysqld restart
[12:48:20 root@master-1 ~]#ll /data/mysql/mysql-bin*
-rw-r----- 1 mysql mysql 154 Jun 15 12:48 /data/mysql/mysql-bin.000001
-rw-r----- 1 mysql mysql 29 Jun 15 12:48 /data/mysql/mysql-bin.index
查看二進(jìn)制日志位置
[12:48:41 root@master-1 ~]#mysql -e 'show master logs;'
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 154 |
+------------------+-----------+
創(chuàng)建復(fù)制賬號(hào)
mysql> grant replication slave on *.* to 'repluser'@'10.0.0.%' identified by '000000';
Query OK, 0 rows affected, 1 warning (0.00 sec)
10.0.0.227
配置后重啟服務(wù), 生成二進(jìn)制日志
[12:49:24 root@master-2 ~]#service mysqld restart
[12:49:31 root@master-2 ~]#ll /data/mysql/mysql-bin*
-rw-r----- 1 mysql mysql 154 Jun 15 12:49 /data/mysql/mysql-bin.000001
-rw-r----- 1 mysql mysql 29 Jun 15 12:49 /data/mysql/mysql-bin.index
查看二進(jìn)制日志位置
[12:49:44 root@master-2 ~]#mysql -e 'show master logs'
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 154 |
+------------------+-----------+
先把10.0.0.227作為10.0.0.237的從節(jié)點(diǎn)
10.0.0.227
mysql> CHANGE MASTER TO
-> MASTER_HOST='10.0.0.237',
-> MASTER_USER='repluser',
-> MASTER_PASSWORD='000000',
-> MASTER_PORT=3306,
-> MASTER_LOG_FILE='mysql-bin.000001',
-> MASTER_LOG_POS=154;
Query OK, 0 rows affected, 2 warnings (0.02 sec)
由于復(fù)制的位置是主節(jié)點(diǎn)創(chuàng)建賬號(hào)之前的位置, 因此從節(jié)點(diǎn)無(wú)需再創(chuàng)建復(fù)制賬號(hào)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
mysql> select user,host from mysql.user;
+---------------+-----------+
| user | host |
+---------------+-----------+
| repluser | 10.0.0.% |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+---------------+-----------+
4 rows in set (0.00 sec)
此時(shí)從節(jié)點(diǎn)同步數(shù)據(jù), 但是不會(huì)生成二進(jìn)制日志. 因?yàn)闆](méi)有開(kāi)啟log-slave-updates
mysql> show master logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 154 |
+------------------+-----------+
1 row in set (0.00 sec)
再把10.0.0.237作為10.0.0.227的從節(jié)點(diǎn)
10.0.0.237
mysql> CHANGE MASTER TO
-> MASTER_HOST='10.0.0.227',
-> MASTER_USER='repluser',
-> MASTER_PASSWORD='000000',
-> MASTER_PORT=3306,
-> MASTER_LOG_FILE='mysql-bin.000001',
-> MASTER_LOG_POS=154;
Query OK, 0 rows affected, 2 warnings (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
測(cè)試雙向同步
10.0.0.237 創(chuàng)建數(shù)據(jù)庫(kù) db1
mysql> create database db1;
Query OK, 1 row affected (0.01 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.01 sec)
查看10.0.0.227同步情況
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
10.0.0.227 創(chuàng)建數(shù)據(jù)庫(kù) db2
mysql> create database db2;
Query OK, 1 row affected (0.00 sec)
查看10.0.0.237同步情況
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| db2 |
| mysql |
| performance_schema |
| sys |
+--------------------+
6 rows in set (0.00 sec)
- 測(cè)試兩個(gè)節(jié)點(diǎn)同時(shí)創(chuàng)建數(shù)據(jù)庫(kù)db3是否沖突
利用Xshell同時(shí)向多個(gè)窗口發(fā)送指令, create database db3;
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| db2 |
| db3 |
| mysql |
| performance_schema |
| sys |
+--------------------+
7 rows in set (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| db2 |
| db3 |
| mysql |
| performance_schema |
| sys |
+--------------------+
7 rows in set (0.00 sec)
可以看到同時(shí)創(chuàng)建同名的數(shù)據(jù)庫(kù)不會(huì)沖突, 不過(guò)會(huì)產(chǎn)生復(fù)制錯(cuò)誤, 導(dǎo)致后續(xù)創(chuàng)建的數(shù)據(jù)不會(huì)同步
master-1
Last_Errno: 1007
Last_Error: Error 'Can't create database 'db3'; database exists' on query. Default database: 'db3'. Query: 'create database db3'
master-2
Last_SQL_Errno: 1007
Last_SQL_Error: Error 'Can't create database 'db3'; database exists' on query. Default database: 'db3'. Query: 'create database db3'
跳過(guò)沖突:
[mysqld]
slave_skip_errors=ALL
[05:32:02 root@master-1 ~]#service mysqld restart
[mysqld]
slave_skip_errors=ALL
[05:32:02 root@master-2 ~]#service mysqld restart
- 測(cè)試同時(shí)在兩個(gè)節(jié)點(diǎn)創(chuàng)建相同的表是否沖突
在db3創(chuàng)建table1表, use db3;
mysql> create table table1(id int auto_increment primary key, name char(10));
Query OK, 0 rows affected (0.02 sec)
mysql> create table table1(id int auto_increment primary key, name char(10));
Query OK, 0 rows affected (0.02 sec)
結(jié)果顯示建表可以創(chuàng)建, 但是還會(huì)出現(xiàn)沖突
Last_SQL_Errno: 1050
Last_SQL_Error: Error 'Table 'table1' already exists' on query. Default database: 'db3'. Query: 'create table table1(id int auto_increment primary key, name char(10))'
Last_SQL_Errno: 1050
Last_SQL_Error: Error 'Table 'table1' already exists' on query. Default database: 'db3'. Query: 'create table table1(id int auto_increment primary key, name char(10))'
按照上面相同步驟, 跳過(guò)沖突
測(cè)試在db3.table1表創(chuàng)建記錄是否沖突
mysql> insert table1(name) value ('b');
Query OK, 1 row affected (0.10 sec)
mysql> insert table1(name) value ('b');
Query OK, 1 row affected (0.11 sec)
mysql> select * from table1;
+----+------+
| id | name |
+----+------+
| 1 | b |
| 2 | b |
+----+------+
2 rows in set (0.00 sec)
mysql> select * from table1;
+----+------+
| id | name |
+----+------+
| 1 | b |
| 2 | b |
+----+------+
2 rows in set (0.00 sec)
結(jié)果顯示創(chuàng)建數(shù)據(jù)不會(huì)沖突, 因?yàn)槲覀冡槍?duì)兩個(gè)節(jié)點(diǎn)設(shè)定了不同的主鍵id自動(dòng)增長(zhǎng)
補(bǔ)充:
即使數(shù)據(jù)庫(kù)沒(méi)配置成不同的自動(dòng)增長(zhǎng)步長(zhǎng), 只要是表開(kāi)啟了自動(dòng)增長(zhǎng), 那么即使同時(shí)插入相同的數(shù)據(jù), 也不會(huì)沖突, MySQL會(huì)自動(dòng)調(diào)整表的自增步長(zhǎng)
如果插入數(shù)據(jù)時(shí), 人為指定了主鍵, 那么同時(shí)插入數(shù)據(jù)就會(huì)沖突
建議:
- 可以搭雙主架構(gòu), 但是按照一主一從使用, 利用分離器實(shí)現(xiàn)寫(xiě)數(shù)據(jù)往一個(gè)主節(jié)點(diǎn)調(diào)度, 讀數(shù)據(jù)往另一個(gè)主節(jié)點(diǎn)調(diào)度, 數(shù)據(jù)由一個(gè)主節(jié)點(diǎn)復(fù)制到另一個(gè)主節(jié)點(diǎn), 這樣就不會(huì)沖突, 同時(shí), 一旦負(fù)責(zé)寫(xiě)輸入的主節(jié)點(diǎn)down了, 把寫(xiě)數(shù)據(jù)往另一個(gè)主節(jié)點(diǎn)調(diào)度即可, 因?yàn)榱硪粋€(gè)主節(jié)點(diǎn)都是配置好了的, 可以直接寫(xiě)數(shù)據(jù)
跳過(guò)復(fù)制錯(cuò)誤方法-指定具體編號(hào)
構(gòu)建錯(cuò)誤
Last_SQL_Errno: 1007
Last_SQL_Error: Error 'Can't create database 'db3'; database exists' on query. Default database: 'db3'. Query: 'create database db3'
分別修改兩個(gè)節(jié)點(diǎn)的配置文件
10.0.0.237
[23:09:43 root@master-1 ~]#vim /etc/my.cnf
[mysqld]
slave_skip_errors=1007 # 該選項(xiàng)無(wú)法動(dòng)態(tài)修改,而slave_skip_counter是可以動(dòng)態(tài)修改的
重啟mysql
[23:11:26 root@master-1 ~]#service mysqld restart
Shutting down MySQL............ [ OK ]
Starting MySQL. [ OK ]
觀察錯(cuò)誤消失即可, 10.0.0.227上也做相同的操作就可以恢復(fù)數(shù)據(jù)同步了
7.4 半同步復(fù)制
默認(rèn)情況下, MySQL的主從復(fù)制是異步復(fù)制, 用戶發(fā)送DML請(qǐng)求到達(dá)MySQL讀寫(xiě)分離器, 讀寫(xiě)分離器會(huì)把請(qǐng)求調(diào)度到主節(jié)點(diǎn)進(jìn)行寫(xiě)操作, 主節(jié)點(diǎn)完成數(shù)據(jù)庫(kù)更新會(huì)立即返回更新成功結(jié)果給分離器, 分離器會(huì)返回用戶更新成功消息, 主節(jié)點(diǎn)同時(shí)將二進(jìn)制更新同步給從節(jié)點(diǎn)
如果主從復(fù)制延遲較大時(shí), 主節(jié)點(diǎn)的二進(jìn)制更新還沒(méi)有復(fù)制給從節(jié)點(diǎn)時(shí), 一旦主節(jié)點(diǎn)故障, 二進(jìn)制日志也無(wú)法恢復(fù), 那么這時(shí)用戶更新的數(shù)據(jù)就會(huì)丟失, 因?yàn)閺墓?jié)點(diǎn)還沒(méi)來(lái)得及更新自己的數(shù)據(jù). 但是分離器已經(jīng)返回給用戶更新成功通知.
同步復(fù)制:
主節(jié)點(diǎn)更新數(shù)據(jù)后, 必須要確保全部從節(jié)點(diǎn)已經(jīng)完全接收了二進(jìn)制的更新, 更新成功后, 才會(huì)返回給分離器更新成功了. 否則用戶看不到更新成功消息. 這就會(huì)造成用戶等待, 因?yàn)樗袕墓?jié)點(diǎn)完成同步會(huì)有延遲
解決方法: 半同步復(fù)制
必須確保任意一個(gè)從節(jié)點(diǎn)同步成功, 返回同步成功結(jié)果給主節(jié)點(diǎn), 主節(jié)點(diǎn)才會(huì)通知分離器更新成功, 否則不會(huì)返回
這樣半同步就確保了即使主節(jié)點(diǎn)宕機(jī), 至少有一個(gè)從節(jié)點(diǎn)是有更新的數(shù)據(jù)的
然而, 如果所有節(jié)點(diǎn)的復(fù)制都很慢, 主節(jié)點(diǎn)需要設(shè)置超時(shí)時(shí)長(zhǎng), 規(guī)定時(shí)間內(nèi)如果無(wú)法同步到任何一個(gè)從節(jié)點(diǎn), 就會(huì)返回更新失敗. 雖然此時(shí)也有風(fēng)險(xiǎn), 比如等待時(shí)間設(shè)置過(guò)長(zhǎng), 如果等待期間內(nèi)主服務(wù)器宕機(jī), 仍然會(huì)丟失數(shù)據(jù). 半同步只是盡肯能照顧了數(shù)據(jù)安全, 也保證了效率.
主從和半同步復(fù)制需要搭配使用
實(shí)驗(yàn)環(huán)境:
10.0.0.237 主節(jié)點(diǎn)
10.0.0.227 從節(jié)點(diǎn)
步驟1: 兩個(gè)節(jié)點(diǎn)部署mysql
步驟2: 主節(jié)點(diǎn)10.0.0.237開(kāi)啟半同步
#MySQL 5.7版本需要在mysql里安裝半同步插件, 不同版本配置不同, 高本版的MySQL和MariaDB是在配置文件里直接加載
#install這一步需要在修改配置文件, 重啟mysqld之前做, 要不然會(huì)報(bào)錯(cuò), 系統(tǒng)未知的變量"rpl_semi_sync_master_enabled"
mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so';
Query OK, 0 rows affected (0.01 sec)
vim /etc/my.cnf
rpl_semi_sync_master_enabled=ON #開(kāi)啟半同步復(fù)制功能
rpl_semi_sync_master_timeout=3000 #設(shè)置超時(shí)時(shí)間, 3s內(nèi)無(wú)法同步, 會(huì)返回更新失敗消息, 默認(rèn)是10s
server-id=237
log-bin=/data/mysql/mysql-bin
[09:54:03 root@master ~]#service mysqld restart
Shutting down MySQL.. [ OK ]
Starting MySQL. [ OK ]
mysql> show master logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 154 |
+------------------+-----------+
1 row in set (0.00 sec)
mysql> grant replication slave on *.* to 'repluser'@'10.0.0.%' identified by '000000';
Query OK, 0 rows affected, 1 warning (3.00 sec)
步驟3: 修改從節(jié)點(diǎn)配置文件
mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
Query OK, 0 rows affected (0.01 sec)
rpl_semi_sync_slave_enabled=ON #從節(jié)點(diǎn)啟用半同步復(fù)制
server-id=227
log-bin=/data/mysql/mysql-bin
[09:54:03 root@slave ~]#service mysqld restart
從節(jié)點(diǎn)指定復(fù)制位置
mysql> CHANGE MASTER TO
-> MASTER_HOST='10.0.0.237',
-> MASTER_USER='repluser',
-> MASTER_PASSWORD='000000',
-> MASTER_PORT=3306,
-> MASTER_LOG_FILE='mysql-bin.000001',
-> MASTER_LOG_POS=154;
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like '%semi%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled | ON |
| rpl_semi_sync_slave_trace_level | 32 |
+---------------------------------+-------+
2 rows in set (0.00 sec)
查看主節(jié)點(diǎn)半同步狀態(tài)
mysql> show global status like '%semi%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 1 | #這里可以看到已經(jīng)有了一個(gè)從節(jié)點(diǎn)
mysql> show variables like '%semi%';
+-------------------------------------------+------------+
| Variable_name | Value |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled | ON |
| rpl_semi_sync_master_timeout | 3000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_for_slave_count | 1 |
| rpl_semi_sync_master_wait_no_slave | ON |
| rpl_semi_sync_master_wait_point | AFTER_SYNC |
+-------------------------------------------+------------+
6 rows in set (0.00 sec)
步驟4: 驗(yàn)證同步情況
主節(jié)點(diǎn)導(dǎo)入測(cè)試存儲(chǔ)過(guò)程和hellodb數(shù)據(jù)庫(kù)
[09:54:03 root@master ~]#cat testlog.sql
create table testlog (id int auto_increment primary key,name char(10),age int default 20);
delimiter $$
create procedure sp_testlog()
begin
declare i int;
set i = 1;
while i <= 100000
do insert into testlog(name,age) values (concat('wang',i),i);
set i = i +1;
end while;
end$$
delimiter ;
[09:56:19 root@master ~]#mysql < hellodb_innodb.sql
[09:56:26 root@master ~]#mysql hellodb < testlog.sql
mysql> use hellodb;
mysql> call sp_testlog;
同時(shí)觀察從節(jié)點(diǎn)同步情況, 確保同步正常
mysql> select count(*) from hellodb.testlog;
+----------+
| count(*) |
+----------+
| 100000 |
+----------+
1 row in set (0.01 sec)
步驟5: 再搭建一個(gè)從節(jié)點(diǎn)10.0.0.217實(shí)現(xiàn)一主兩從架構(gòu)
mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
Query OK, 0 rows affected (0.00 sec)
[14:31:46 root@slave-2 ~]#vim /etc/my.cnf
[mysqld]
server-id=217
log-bin=/data/mysql/mysql-log
rpl_semi_sync_slave_enabled=ON
datadir=/data/mysql
skip_name_resolve=1
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
[client]
socket=/data/mysql/mysql.sock
[10:46:01 root@slave-2 ~]#service mysqld restart
Shutting down MySQL.. [ OK ]
Starting MySQL. [ OK ]
將主節(jié)點(diǎn)數(shù)據(jù)做完全備份
[10:47:29 root@master ~]#mysqldump -A -F --single-transaction --master-data=1 > /data/allbackup.sql
將完全備份拷貝到10.0.0.53第二個(gè)從節(jié)點(diǎn)
[10:47:30 root@master ~]#scp /data/allbackup.sql 10.0.0.217:/root
從節(jié)點(diǎn)設(shè)置change master to
#查看完全備份日志位置, 修改完全備份文件
CHANGE MASTER TO
MASTER_HOST='10.0.0.237',
MASTER_USER='repluser',
MASTER_PASSWORD='000000',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=154;
從節(jié)點(diǎn)導(dǎo)入完全備份
mysql> set sql_log_bin=off;
mysql> source /root/allbackup.sql
mysql> set sql_log_bin=on;
從節(jié)點(diǎn)開(kāi)啟slave
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
驗(yàn)證同步
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
步驟6: 驗(yàn)證主節(jié)點(diǎn)上半同步客戶端為2
mysql> show global status like '%semi%';
+--------------------------------------------+----------+
| Variable_name | Value |
+--------------------------------------------+----------+
| Rpl_semi_sync_master_clients | 2 |
步驟7: 關(guān)閉10.0.0.217上的slave功能, 驗(yàn)證主節(jié)點(diǎn)可以正常寫(xiě)數(shù)據(jù)
10.0.0.217
mysql> stop slave;
Query OK, 0 rows affected (0.01 sec)
主節(jié)點(diǎn)創(chuàng)建數(shù)據(jù)庫(kù)
mysql> create database testdb;
Query OK, 1 row affected (0.01 sec)
可以看到此時(shí)主節(jié)點(diǎn)還是可以正常修改, 因?yàn)閽炝艘粋€(gè)從節(jié)點(diǎn), 另一個(gè)從節(jié)點(diǎn)還是正常工作可以同步的, 而且因?yàn)榄h(huán)境簡(jiǎn)單, 同步時(shí)間沒(méi)有超過(guò)3秒, 所以同步成功
驗(yàn)證10.0.0.227上同步成功
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| hellodb |
| mysql |
| performance_schema |
| sys |
| testdb |
+--------------------+
步驟8: 關(guān)掉10.0.0.227上的從節(jié)點(diǎn)服務(wù), 構(gòu)建無(wú)法同步的環(huán)境, 測(cè)試主節(jié)點(diǎn)能否修改數(shù)據(jù)
10.0.0.52
mysql> stop slave;
Query OK, 0 rows affected (0.01 sec)
此時(shí)主節(jié)點(diǎn)的mysql日志會(huì)提示同步關(guān)閉
2020-11-25T17:03:48.034172Z 0 [ERROR] /usr/local/mysql/bin/mysqld: Got an error reading communication packets
2020-11-25T17:04:30.781849Z 13 [ERROR] Semi-sync master failed on net_flush() before waiting for slave reply
2020-11-25T17:04:30.781888Z 13 [Note] Stop semi-sync binlog_dump to slave (server_id: 53)
2020-11-25T17:04:30.782041Z 13 [Note] Aborted connection 13 to db: 'unconnected' user: 'repluser' host: '10.0.0.53' (Found net error)
2020-11-25T17:08:37.501641Z 0 [ERROR] /usr/local/mysql/bin/mysqld: Got an error reading communication packets
2020-11-25T17:09:30.803252Z 2 [Note] Stop semi-sync binlog_dump to slave (server_id: 52)
2020-11-25T17:09:30.803377Z 2 [Note] Aborted connection 2 to db: 'unconnected' user: 'repluser' host: '10.0.0.52' (failed on flush_net())
2020-11-25T17:10:35.383468Z 14 [Warning] Timeout waiting for reply of binlog (file: mysql-bin.000003, pos: 487), semi-sync up to file mysql-bin.000003, position 319.
2020-11-25T17:10:35.383562Z 14 [Note] Semi-sync replication switched OFF.
確保主節(jié)點(diǎn)和從節(jié)點(diǎn)復(fù)制關(guān)系消失后, 主節(jié)點(diǎn)創(chuàng)建數(shù)據(jù)庫(kù)
mysql> show global status like '%semi%';
+--------------------------------------------+----------+
| Variable_name | Value |
+--------------------------------------------+----------+
| Rpl_semi_sync_master_clients | 0 | #確保client為0
#此時(shí)主節(jié)點(diǎn)會(huì)等待超時(shí)時(shí)間到期后再返回信息, 這里顯示成功是因?yàn)榧词乖谥鞴?jié)點(diǎn)成功了, 但是信息也沒(méi)有復(fù)制到從節(jié)點(diǎn)上. 根據(jù)半同步原理, 此時(shí)會(huì)返回給用戶端更新失敗消息.
mysql> create database testdb2;
Query OK, 1 row affected (3.00 sec)
這時(shí), 需要恢復(fù)主從同步關(guān)系用戶才能正常寫(xiě)數(shù)據(jù)并且得到更新成功的消息
兩個(gè)從節(jié)點(diǎn)啟動(dòng)復(fù)制, 為下個(gè)實(shí)驗(yàn)做準(zhǔn)備, 開(kāi)啟復(fù)制后, 之前創(chuàng)建的testdb2會(huì)繼續(xù)復(fù)制到兩個(gè)從節(jié)點(diǎn)
start slave;
7.5 復(fù)制過(guò)濾器
讓從節(jié)點(diǎn)僅復(fù)制指定的數(shù)據(jù)庫(kù), 或指定數(shù)據(jù)庫(kù)的指定表
復(fù)制過(guò)濾器的兩種實(shí)現(xiàn)方式
(1) 服務(wù)器選項(xiàng): 在主服務(wù)器配置文件中指定哪些數(shù)據(jù)庫(kù)會(huì)復(fù)制, 哪些不會(huì)復(fù)制
此方法問(wèn)題: 基于二進(jìn)制還原將無(wú)法實(shí)現(xiàn), 不建議使用
vim /etc/my.cnf
binlog-do-db=DB_NAME #數(shù)據(jù)庫(kù)白名單, 不支持同時(shí)指定多個(gè)值, 如果想實(shí)現(xiàn)多個(gè)數(shù)據(jù)庫(kù)需要寫(xiě)多行
binlog-ignore-db=DB_NAME #數(shù)據(jù)庫(kù)黑名單, 不支持同時(shí)指定多個(gè)值, 如果想實(shí)現(xiàn)多個(gè)數(shù)據(jù)庫(kù)需要寫(xiě)多行
案例:
- 先查看主服務(wù)器上數(shù)據(jù)庫(kù)信息
+--------------------+
| Database |
+--------------------+
| information_schema |
| hellodb |
| mysql |
| performance_schema |
| sys |
| testdb |
| testdb2 |
+--------------------+
7 rows in set (0.01 sec)
- 修改主節(jié)點(diǎn)配置文件, 添加復(fù)制規(guī)則
[15:08:20 root@master-1 ~]#vim /etc/my.cnf
[mysqld]
binlog-do-db=testdb2
binlog-do-db=hellodb
rpl_semi_sync_master_enabled=ON
rpl_semi_sync_master_timeout=3000
server-id=237
log-bin=/data/mysql/mysql-bin
datadir=/data/mysql
skip_name_resolve=1
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
[client]
socket=/data/mysql/mysql.sock
~
[10:54:37 root@master ~]#service mysqld restart
- 驗(yàn)證配置
# Binlog_Do_DB表示只同步哪個(gè)數(shù)據(jù)庫(kù)給從節(jié)點(diǎn)
mysql> show master status;
+------------------+----------+-----------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+-----------------+------------------+-------------------+
| mysql-bin.000003 | 154 | testdb2,hellodb | | |
+------------------+----------+-----------------+------------------+-------------------+
1 row in set (0.00 sec)
# 主節(jié)點(diǎn)在testdb2創(chuàng)建表, 驗(yàn)證可以同步到從節(jié)點(diǎn)
mysql> use testdb2;
Database changed
mysql> create table test (id int);
Query OK, 0 rows affected (0.01 sec)
# 驗(yàn)證從節(jié)點(diǎn)可以同步
mysql> show tables from testdb2;
+-------------------+
| Tables_in_testdb2 |
+-------------------+
| test |
+-------------------+
1 row in set (0.00 sec)
# 主節(jié)點(diǎn)在testdb創(chuàng)建t1表, 驗(yàn)證不會(huì)同步
mysql> use testdb;
Database changed
mysql> create table t1(id int);
Query OK, 0 rows affected (0.00 sec)
mysql> show tables;
+------------------+
| Tables_in_testdb |
+------------------+
| t1 |
+------------------+
1 row in set (0.00 sec)
從節(jié)點(diǎn)
mysql> show tables from testdb;
Empty set (0.00 sec)
- 使用服務(wù)器選項(xiàng)方法, 在跨越數(shù)據(jù)庫(kù)創(chuàng)建數(shù)據(jù)時(shí), 是不會(huì)同步的. 創(chuàng)建數(shù)據(jù), 必須在會(huì)被同步的庫(kù)里創(chuàng)建
主節(jié)點(diǎn)
mysql> use testdb;
mysql> create table testdb2.db_test(id int);
Query OK, 0 rows affected (0.01 sec)
mysql> show tables from testdb2;
+-------------------+
| Tables_in_testdb2 |
+-------------------+
| db_test |
| test |
+-------------------+
2 rows in set (0.00 sec)
從節(jié)點(diǎn)不會(huì)同步db_test表, 因?yàn)楸硎侵鞴?jié)點(diǎn)在testdb里創(chuàng)建的
mysql> show tables from testdb2;
+-------------------+
| Tables_in_testdb2 |
+-------------------+
| test |
+-------------------+
1 row in set (0.00 sec)
- 此外, 使用服務(wù)器選項(xiàng)方式, 對(duì)于那些不會(huì)同步的數(shù)據(jù)庫(kù), 主節(jié)點(diǎn)即使開(kāi)啟了二進(jìn)制日志, 也不會(huì)記錄數(shù)據(jù), 這樣之后就無(wú)法利用二進(jìn)制對(duì)于那些沒(méi)有同步的數(shù)據(jù)庫(kù)進(jìn)行數(shù)據(jù)恢復(fù)了, 因此該方法不推薦使用
(2) 從服務(wù)器SQL_THREAD在讀取relay log中的事件時(shí), 僅讀取與特定數(shù)據(jù)庫(kù)(特定表)相關(guān)的時(shí)間, 并應(yīng)用與本地
此方法存在的問(wèn)題: 會(huì)造成網(wǎng)絡(luò)及磁盤IO浪費(fèi), 因?yàn)橹鞴?jié)點(diǎn)會(huì)把二進(jìn)制都復(fù)制給從節(jié)點(diǎn), 而從節(jié)點(diǎn)不會(huì)接收全部的數(shù)據(jù), 就會(huì)造成資源浪費(fèi)
從服務(wù)器上的復(fù)制過(guò)濾器相關(guān)變量
replicate_do_db=db1,db2,db3 #指定復(fù)制庫(kù)的白名單绰咽,變量可以指定逗號(hào)分隔的多個(gè)值菇肃,選項(xiàng)不支持多值
replicate_ignore_db= #指定復(fù)制庫(kù)黑名單
replicate_do_table= #指定復(fù)制表的白名單
replicate_ignore_table= #指定復(fù)制表的黑名單
replicate_wild_do_table= foo%.bar% #支持通配符
replicate_wild_ignore_table=
- MySQL中, 只能在命令行或者配置文件定義服務(wù)器選項(xiàng). 這些變量在MySQL中不存在
案例:
- 取消主節(jié)點(diǎn)的復(fù)制過(guò)濾配置
[11:03:01 root@master ~]#vim /etc/my.cnf
[mysqld]
rpl_semi_sync_master_enabled=ON
rpl_semi_sync_master_timeout=3000
server-id=237
log-bin=/data/mysql/mysql-bin
datadir=/data/mysql
skip_name_resolve=1
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
[client]
socket=/data/mysql/mysql.sock
[11:03:28 root@master ~]#service mysqld restart
- 兩個(gè)從節(jié)點(diǎn)配置復(fù)制過(guò)濾
[17:03:43 root@slave-1 ~]#vim /etc/my.cnf
replicate-do-db=testdb2
replicate-do-db=hellodb
[17:04:07 root@slave-1 ~]#service mysqld restart
[17:28:05 root@slave-2 ~]#vim /etc/my.cnf
replicate-do-db=testdb2
replicate-do-db=hellodb
# 這里如果重啟失敗, 需要先把半同步復(fù)制注釋, 重啟mysql, 然后進(jìn)到mysql安裝半同步復(fù)制插件, 之后啟用半同步, 重啟mysql即可
[17:28:05 root@slave-2 ~]#service mysqld restart
- 主節(jié)點(diǎn)在db1和hellodb做修改, 驗(yàn)證可以正常同步給從節(jié)點(diǎn)即可
- 總結(jié): 定義了復(fù)制過(guò)濾后, 主節(jié)點(diǎn)新創(chuàng)建的數(shù)據(jù)庫(kù)是不會(huì)復(fù)制給從節(jié)點(diǎn)的, 需要從節(jié)點(diǎn)把新的數(shù)據(jù)庫(kù)添加到配置文件指定. 這種方法主節(jié)點(diǎn)會(huì)對(duì)所有數(shù)據(jù)庫(kù)記錄二進(jìn)制, 可用來(lái)做還原
7.6 GTID復(fù)制
GTID復(fù)制: (Global Transaction ID全局事務(wù)標(biāo)識(shí)符), MySQL5.6版本開(kāi)始支持, GTID復(fù)制不像傳統(tǒng)的復(fù)制方式(異步復(fù)制, 半同步復(fù)制)需要找到binlog文件名和POS點(diǎn)
GTID復(fù)制只需要知道m(xù)aster節(jié)點(diǎn)的ip, 端口, 賬號(hào), 密碼即可.
開(kāi)始GTID后, 執(zhí)行change master to master_auto_position=1即可, 它會(huì)自動(dòng)尋找到相應(yīng)的位置開(kāi)始同步
GTID = server_uuid:transaction_id, 在一組復(fù)制中, 全局唯一
server_uuid 來(lái)源于 /var/lib/mysql/auto.cnf
GTID服務(wù)器相關(guān)選項(xiàng)
gtid_mode # gitd模式
enforce_gtid_consistency # 保證GTID安全的參數(shù)
配置案例
- 主服務(wù)器 - 10.0.0.237
[02:05:17 root@master-1 ~]#vim /etc/my.cnf
[mysqld]
server-id=237
log-bin=/data/mysql/mysql-bin
gtid_mode=ON
enforce_gtid_consistency
[02:17:04 root@master-1 ~]#service mysqld restart
- 從服務(wù)器 - 10.0.0.227
取消slave
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
mysql> reset slave all;
Query OK, 0 rows affected (0.01 sec)
[02:19:54 root@slave-2 ~]#vim /etc/my.cnf
[mysqld]
server-id=217
log-bin=/data/mysql/mysql-bin
gtid_mode=ON
enforce_gtid_consistency
[02:20:44 root@slave-2 ~]#service mysqld restart
mysql> change master to master_host='10.0.0.237',
-> master_user="repluser",
-> master_password="000000",
-> master_port=3306,
-> master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.03 sec)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
7.7 復(fù)制的監(jiān)控和維護(hù)
(1): 清理日志
purge { binary | master } logs { to 'log_name' | before datetime_expr }
reset slave [all]
(2): 復(fù)制監(jiān)控
show master status
show binary logs
show binglog events
show slave status
show processlist
(3): 從服務(wù)器是否落后于主服務(wù)
Seconds_Behind_Master: 0
(4): 如果確定主從節(jié)點(diǎn)數(shù)據(jù)是否一致
percona-toolkit
pt-table-checksum #檢查主從數(shù)據(jù)是否一致,
pt-table-sync #把主庫(kù)數(shù)據(jù)同步到從庫(kù)
(5): 數(shù)據(jù)不一致如何修復(fù)
刪除從數(shù)據(jù)庫(kù), 重新復(fù)制
7.8 復(fù)制的問(wèn)題和解決方案
7.8.1 數(shù)據(jù)損壞或丟失
1. master損壞: MHA+半同步復(fù)制,
mha會(huì)自動(dòng)提升一個(gè)較新的從節(jié)點(diǎn)為主節(jié)點(diǎn), 無(wú)需手動(dòng)切換
配合半同步復(fù)制, 確保至少有一個(gè)從節(jié)點(diǎn)已經(jīng)同步了數(shù)據(jù), 一旦主節(jié)點(diǎn)宕機(jī), 會(huì)提升該同步了數(shù)據(jù)的從節(jié)點(diǎn)為主節(jié)點(diǎn), 保證數(shù)據(jù)不丟失
2: slave損壞: 刪除數(shù)據(jù), 主節(jié)點(diǎn)做完全備份, 重新復(fù)制
7.8.2 不唯一的server id
重新復(fù)制
7.8.3 復(fù)制延遲
需要額外的監(jiān)控工具的輔助
一從多主: MariaDB10版本后支持
多線程復(fù)制: 對(duì)多個(gè)數(shù)據(jù)庫(kù)并行復(fù)制, MySQL支持客戶端并行訪問(wèn), 但是復(fù)制是串行的. 5.7以后可以根據(jù)數(shù)據(jù)庫(kù)的數(shù)量開(kāi)啟對(duì)應(yīng)線程進(jìn)行復(fù)制.
7.8.4 MySQL主從數(shù)據(jù)不一致
- 造成主從不一致的原因
主庫(kù)binlog格式為Statement取募,同步到從庫(kù)執(zhí)行后可能造成主從不一致琐谤。
主庫(kù)執(zhí)行更改前有執(zhí)行set sql_log_bin=0,會(huì)使主庫(kù)不記錄binlog玩敏,從庫(kù)也無(wú)法變更這部分?jǐn)?shù)據(jù)斗忌。
從節(jié)點(diǎn)未設(shè)置只讀质礼,誤操作寫(xiě)入數(shù)據(jù)
主庫(kù)或從庫(kù)意外宕機(jī),宕機(jī)可能會(huì)造成binlog或者relaylog文件出現(xiàn)損壞织阳,導(dǎo)致主從不一致
主從實(shí)例版本不一致眶蕉,特別是高版本是主,低版本為從的情況下唧躲,主數(shù)據(jù)庫(kù)上面支持的功能造挽,從數(shù)據(jù)庫(kù)上面可能不支持該功能
MySQL自身bug導(dǎo)致
- 主從不一致修復(fù)方法
- 將從庫(kù)重新實(shí)現(xiàn)
雖然這也是一種解決方法,但是這個(gè)方案恢復(fù)時(shí)間比較慢惊窖,而且有時(shí)候從庫(kù)也是承擔(dān)一部分的查詢操作的刽宪,不能貿(mào)然重建。
- 使用percona-toolkit工具輔助
PT工具包中包含pt-table-checksum和pt-table-sync兩個(gè)工具界酒,主要用于檢測(cè)主從是否一致以及修復(fù)數(shù)據(jù)不一致情況圣拄。
這種方案優(yōu)點(diǎn)是修復(fù)速度快,不需要停止主從輔助毁欣,缺點(diǎn)是需要知識(shí)積累庇谆,需要時(shí)間去學(xué)習(xí),去測(cè)試凭疮,特別是在生產(chǎn)環(huán)境饭耳,還是要小心使用
- 手動(dòng)重建不一致的表
在從庫(kù)發(fā)現(xiàn)某幾張表與主庫(kù)數(shù)據(jù)不一致,而這幾張表數(shù)據(jù)量也比較大执解,手工比對(duì)數(shù)據(jù)不現(xiàn)實(shí)寞肖,并且重做整個(gè)庫(kù)也比較慢,這個(gè)時(shí)候可以只重做這幾張表來(lái)修復(fù)主從不一致
這種方案缺點(diǎn)是在執(zhí)行導(dǎo)入期間需要暫時(shí)停止從庫(kù)復(fù)制衰腌,不過(guò)也是可以接受的
范例:A,B,C這三張表主從數(shù)據(jù)不一致
1新蟆、從庫(kù)停止Slave復(fù)制
mysql>stop slave;
2、在主庫(kù)上dump這三張表右蕊,并記錄下同步的binlog和POS點(diǎn)
mysqldump -uroot -pmagedu -q --single-transaction --master-data=2 testdb A B C >/backup/A_B_C.sql
3琼稻、查看A_B_C.sql文件,找出記錄的binlog和POS點(diǎn)
head A_B_C.sql
例如:MASTERLOGFILE='mysql-bin.888888', MASTERLOGPOS=66666666;
4饶囚、把A_B_C.sql拷貝到Slave機(jī)器上帕翻,并做Change master to指向新位置
mysql>start slave until MASTERLOGFILE='mysql-bin.888888', MASTERLOGPOS=66666666;
#以上指令是為了保障其他表的數(shù)據(jù)不丟失,一直同步萝风,直到同步完那個(gè)點(diǎn)結(jié)束嘀掸,A,B,C表的數(shù)據(jù)在之前的備份已經(jīng)生成了一份快照,只需要導(dǎo)入進(jìn)入规惰,然后開(kāi)啟同步即可
5睬塌、在Slave機(jī)器上導(dǎo)入A_B_C.sql
mysql -uroot -pmagedu testdb
mysql>set sql_log_bin=0;
mysql>source /backup/A_B_C.sql
mysql>set sql_log_bin=1;
6、導(dǎo)入完畢后,從庫(kù)開(kāi)啟同步即可衫仑。
mysql>start slave;
- 如何避免主從不一致
主庫(kù)binlog采用ROW格式
主從實(shí)例數(shù)據(jù)庫(kù)版本保持一致
主庫(kù)做好賬號(hào)權(quán)限把控,不可以執(zhí)行set sql_log_bin=0
從庫(kù)開(kāi)啟只讀堕花,不允許人為寫(xiě)入
定期進(jìn)行主從一致性檢驗(yàn)