一:MySQL Replication
什么是MySQL Replication
- Replication可以實現將數據從一台數據庫服務器(master)復制到一或多台數據庫服務器(slave)
- 默認情況下屬於異步復制,無需維持長連接
- 通過配置,可以復制所有的庫或者幾個庫,甚至庫中的一些表
- 是MySQL內建的,本身自帶的
Replication的原理
簡單的說就是master將數據庫的改變寫入二進制日志,slave同步這些二進制日志,並根據這些二進制日志進行數據操作
DML:SQL操作語句,update, insert,delete
Relay log :中繼日志
Replication的作用
1、Fail Over 故障切換
2、Backup Server 備份服務,無法對SQL語句執行產生的故障恢復,有限的備份
3、High Performance高性能,可以多台slave,實現讀寫分離
Replication如何工作
整體上來說,復制有3個步驟:
(1) master將改變記錄到二進制日志(binary log)中(這些記錄叫做二進制日志事件,binary log events);
(2) slave將master的binary log events拷貝到它的中繼日志(relay log);
(3) slave重做中繼日志中的事件,修改salve上的數據。
mysql主從復制中:
第一步:master記錄二進制日志。在每個事務更新數據完成之前,master在二進制日志記錄這些改變。MySQL將事務寫入二進制日志,即使事務中的語句都是交叉執行的。在事件寫入二進制日志完成后,master通知存儲引擎提交事務。
第二步:slave將master的binary log拷貝到它自己的中繼日志。首先,slave開始一個工作線程——I/O線程。I/O線程在master上打開一個普通的連接,然后開始binlog dump process。Binlog dump process從master的二進制日志中讀取事件,如果已經執行完master產生的所有文件,它會睡眠並等待master產生新的事件。I/O線程將這些事件寫入中繼日志。
第三步:SQL slave thread(SQL從線程)處理該過程的最后一步。SQL線程從中繼日志讀取事件,並重新執行其中的事件而更新slave的數據,使其與master中的數據一致。
Replication常見方案:
1、One master and Muti salve 一主多備
一般用來做讀寫分離的,master寫,其他slave讀,這種架構最大問題I/O壓力集中
在Master上<多台同步影響IO>
2、M-S-S
使用一台slave作為中繼,分擔Master的壓力,slave中繼需要開啟bin-log,並配置log-slave-updates
Slave中繼可使用Black-hole存儲引擎,不會把數據存儲到磁盤,只記錄二進制日志
3、M-M 雙主互備 (互為主從)
很多人誤以為這樣可以做到MySQL負載均衡,實際沒什么好處,每個服務器需要做同樣的同步更新,破壞了事物的隔離性和數據的一致性
4、M-M-M
監控三台機器互相做對方的master
天生的缺陷:復制延遲,slave上同步要慢於master,如果大並發的情況那延遲更嚴重
Mysql在5.6已經自身可以實現fail over故障切換
5、One slave Muti master 一從對多主
好處:節省成本,將多個master數據自動化整合
缺陷:對庫和表數據的修改較多
二:部署MySQL主從同步 <M-S>
環境准備:
主機名 |
IP |
系統/MySQL版本 |
角色 |
harry63 |
10.10.10.63 |
CentOS7.4/5.7.20 |
Master |
harry64 |
10.10.10.64 |
CentOS7.4/5.7.20 |
slave |
模式:C/S
端口:3306
配置主數據庫服務器HARRY63
創建需要同步的數據庫:
mysql> create database HA;
mysql> use HA;
mysql> create table T1(id int,name varchar(20));
service mysqld stop
配置my.cnf:
vim /etc/my.cnf
log-bin=mysql-bin-master #啟用二進制日志
server-id=1 #本機數據庫ID 標示
binlog-do-db=HA #可以被從服務器復制的庫, 二進制需要同步的數據庫名
binlog-ignore-db=mysql #不可以被從服務器復制的庫
重啟mysql ( 如果重啟卡死現象,kill掉再啟動)
Systemctl restart mysqld
授權:
mysql> grant replication slave on *.* to slave@10.10.10.64 identified by "123456";
查看狀態信息:
mysql> show master status;
+-------------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------------+----------+--------------+------------------+
| mysql-bin-master.000001 | 259 | HA | mysql |
+-------------------------+----------+--------------+------------------+
查看二進制日志:
ls /usr/local/mysql/data/
mysql> show binlog events\G
復制前要保證同步的數據庫一致
mysqldump -uroot -p123456 HA >HA.sql #可以導出數據庫
將導出的數據庫傳給從服務器
方法:scp HA.sql 10.10.10.64:/root
配置從數據庫服務器HARRY64
兩台數據庫服務器mysql版本要一致
mysql> show variables like '%version%';
測試連接到主服務器是否成功
mysql -uslave -p123456 -h 10.10.10.63
只有復制的權限, 是看不到其他庫的。正常
導入數據庫,和主數據庫服務器保持一致
mysql> create database HA;
mysql -uroot -p123456 HA<HA.sql
修改從服務器配置文件:
從服務器沒必要開啟bin-log日志
service mysqld stop
vim /etc/my.cnf
master-host=192.168.1.63 #指定主服務器IP地址 master-user=slave #指定定在主服務器上可以進行同步的用戶名 master-password=123456 #密碼 #master-port=3306 master-connect-retry=60 #斷點重新連接時間
|
server-id = 2 #從服務器ID號,不要和主ID相同 ,如果設置多個從服務器,每個從服務器必須有一個唯一的server-id值,必須與主服務器的以及其它從服務器的不相同。可以認為server-id值類似於IP地址:這些ID值能唯一識別復制服務器群集中的每個服務器實例。
文本框是mysql 5.1的配置
mysql>stop slave; #停止slave
mysql> change master to master_host='10.10.10.63',master_user='slave',master_password='123456';
mysql> start slave; #啟動slave
mysql> show slave status\G 查看狀態
Slave_IO_Running :一個負責與主機的io通信
Slave_SQL_Running:負責自己的slave mysql進程
兩個為YES 就成功了!
再到主服務器上查看狀態:
mysql> show processlist \G
插入數據測試同步:
mysql> insert into T1 values (1,'man');
從數據庫上查看:
排錯:
如果遇到主從不同步,看一下主從bin-log的位置,然后再同步。
在主服務器上看二進制日志事件列表
mysql> show binlog events \G
從服務器執行MySQL命令下:
mysql> stop slave; #先停止slave服務
mysql> change master to master_log_file='mysql-bin-master.000001',master_log_pos=1164;
#根據上面主服務器的show master status的結果,進行從服務器的二進制數據庫記錄回歸,達到同步的效果
mysql>slave start; #啟動從服務器同步服務
mysql> show slave status\G; #用show slave status\G;看一下從服務器的同步情況
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
如果都是yes,那代表已經在同步
重啟從服務器,再查看狀態:
停止從服務器slave stop;
開啟從服務器slave start;
排錯思路:
1、二進制日志沒有開啟
2、IPTABLES 沒有放開端口
3、對應的主機 IP地址寫錯了
SQL線程出錯
1、主從服務器數據庫結構不統一
出錯后,數據少,可以手動解決創建插入,再更新slave狀態。
注:如果主上誤刪除了。那么從上也就誤刪除了。 #因此主上要定期做mysqldump備份。
三:部署MySQL主主雙向主從復制 M-M
通過mysql主主:進行mysql 雙向同步數據庫HA的配置
mysql主:服務端:HARRY63 IP:10.10.10.63
mysql主:服務端:HARRY64 IP:10.10.10.64
要先清空一下二進制日志,mysql> reset master
在上面主從的基礎上進行配置
配置HARRY63
它有兩種身份:
身份1: HARRY64的主。 身份2: HARRY64的從。
vim /etc/my.cnf
server-id = 1
log-bin=mysql-bin-master
binlog-do-db=HA
binlog-ignore-db=mysql #避免同步mysql用戶 相關配置
service mysqld restart
授權:
mysql> grant replication slave on *.* to slave@'10.10.10.%' identified by '123456';
如果不符合密碼要求修改如下(5.7版本)
mysql> set global validate_password_policy=0; #定義復雜度
mysql> set global validate_password_length=1; #定義長度 默認是8
關閉密碼強度審計,在my.cnf添加validate-password=off
grant replication slave on *.* to slave@'10.10.10.%' identified by '123456';
mysql> flush privileges; #記得刷新授權表
配置HARRY64
5.1的配置 master-host=192.168.1.64 #指定主服務器IP地址 master-user=slave64 #指定定在主服務器上可以進行同步的用戶名 master-password=123456 #密碼 #master-port=3306 可以不寫 replicate-do-db=HA #要復制的數據庫 master-connect-retry=60 #斷點重新連接時間 |
vim /etc/my.cnf
server-id = 2
log-bin=mysql-bin-slave
binlog-do-db=HA
binlog-ignore-db=mysql
先測試一下從帳號登陸是否正常?
[root@harry64 ~]# mysql -uslave -p123456 -h 10.10.10.63
然后作主授權給從harry63,
[root@harry64 ~]# grant replication slave on *.* to slave@'10.10.10.63' identified by '123456';
指定哪台是harry64的master
[root@HARRY64 ~]# mysql -uroot -p123456
mysql> stop slave;
mysql> change master to master_host='10.10.10.63' master_user='slave',master_password='123456';
mysql> start slave;
mysql> show slave status\G
再回來配置HARRY63
先測試一下從帳號登陸是否正常?
[root@harry63~]# mysql -uslave -p123456 -h 10.10.10.64 #可以登陸
指定哪台是harry63的master
[root@HARRY63 ~]# mysql -uroot -p123456
mysql> change master to master_host='10.10.10.64',master_user='slave',master_password='123456';
mysql> start slave;
mysql> show slave status\G
檢查:
HARRY63上查看slave狀態
HARRY64上查看slave狀態
插入數據測試:
在HARRY63上插入數據,HARRY64上查看
mysql> insert into T1 values(2,'天清');
在HARRY64上插入數據,HARRY63上查看
mysql> insert into T1 values(3,'黑客');
注意:這種M-M架構沒有什么好處,他往往給我們產生一種實現了負載均衡的錯覺
六:部署M-S-S模型
環境:
HARRY68 master mysql5.7.20 10.10.10.68
HARRY69 slave中繼 mysql5. 7.20 10.10.10.69
HARRY70 slave mysql5. 7.20 10.10.10.70
部署master---->HARRY68:
在主服務上授權用戶:
mysql> grant replication slave on *.* to repl@'10.10.10.%' identified by '123456';
mysql> flush privileges;
[root@harry68 ~]# vim /etc/my.cnf #修改配置 增加以下選項
server-id=1
binlog-do-db=HA
log-bin=mysql-bin-master
binlog-ignore-db=mysql
sync-binlog=1
binlog-format=row
重啟服務
[root@harry68 ~]# systemctl restart mysqld
導出主服務器HA庫完整備份, 拷貝到 中繼服務器 和slave服務器
[root@harry68 ~]# mysqldump -uroot -p123456 -B HA>ha.sql
[root@harry68 ~]# scp ha.sql 10.10.10.69:/root
[root@harry68 ~]# scp ha.sql 10.10.10.70:/root
部署slave中繼------> HARRY69
導入數據庫ha.sql
[root@harry69 ~]# mysql –uroot –p123456 <ha.sql
配置my.cnf
[root@harry69 ~]#vim /etc/my.cnf
server-id= 2
#修改主配置文件也要開啟bin-log:
log-bin=mysql-bin-slave1
log-slave-updates=1 #把它從relay-log當中讀取出來的二進制日志並且這本機上執行的操作也記錄這自己的二進制日志里面,這樣才能使第三台slave通過中繼slave讀取到相應數據變化
binlog-format=row
[root@harry69 ~]# systemctl restart mysqld
授權:
mysql> stop slave;
mysql> change master to master_host='10.10.10.68',master_user='repl',master_password='123456';
mysql> start slave;
查看中繼服務的狀態
mysql> show slave status \G
再授權一個用戶給slave(harry70):
mysql> grant replication slave on *.* to 'repl'@'10.10.10.70' identified by '123456';
mysql> flush privileges;
部署slave------>harry70
導入數據庫ha.sql
[root@harry70 ~]# mysql –uroot –p123456 <ha.sql
配置my.cnf
server-id = 3
log-bin=mysql-bini-slave2
binlog-format=row
[root@harry70 ~]# systemctl restart mysqld 重啟
指定slave中繼服務作為harry70的主:
mysql> stop slave;
mysql> change master to master_host='10.10.10.69',master_user='repl',master_password='123456';
mysql> start slave;
查看從服務的狀態
mysql> show slave status \G
從master上插入數據測試:
mysql> insert into test values (1,'AA');
Query OK, 1 row affected (0.09 sec)
然后分別在slave中繼,與slave上查看
為什么中繼服務器也查到數據呢? 因為是存儲引擎的問題。
修改表的引擎:
mysql> alter table t1 ENGINE=blackhole; (先關閉日志記錄再修改set sql_log_bin=off)
你再測試!
排錯:
錯誤1:
此方法可能失效,自行驗證
mysql> show slave status\G
由結果可以看到:
Read_Master_Log_Pos: 288
Exec_Master_Log_Pos: 107
Last_SQL_Errno: 1146
Last_SQL_Error: Error executing row event: 'Table 'HA.student' doesn't exist'
因為只對HA記錄了binlog,當在mydb庫操作其它數據庫的表,但該表在slave上又不存在時就出錯了。
到master上查看事件記錄
mysql> show binlog events in 'mysql-bin-master.000002' from 107\G
由上面的結果可知,我們需要跳過兩個事務173,288
然后到salve中繼操作:
mysql> slave stop;
mysql> SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 2; 跳過一個事務
mysql> slave start;
這個搞定
或者:
它提供了一個session粒度的選項,通過關閉這個選項可以不讓主庫將打開這個選項或關閉連接前的SQL語句寫入binlog。
set sql_log_bin=off;
mysql>alter table aaa add column xxx int default 1 after yyy;
模擬故障:
由於歷史遺留問題,MySQL主從庫的表結構不一致,主庫的某個表tableA比從庫表tableA少了一個字段
當嘗試在主庫上更改表結構時,這行alter語句會隨着binlog同步到從庫,如果從庫執行這行語句時出錯,主從同步線程就會自動停止,那樣只能人為手動處理錯誤,然后再啟動slave上的主從同步線程。場景大概是下面這個樣子:
先在從庫添加這個字段:
mysql> alter table student add age int default 0 after name;
再在主庫添加這個字段:
mysql> alter table student add age int default 0 after name;修改主庫上的表結構,添加一個字段
從庫會同步主庫的,但是從庫已經存在了這個字段
查看slave狀態
解決方法1:
跳過錯誤的事物
從庫上執行:
mysql> stop slave;
set global sql_slave_skip_counter=1;
mysql> start slave;
很多slave數據庫的時候這樣改太麻煩了
解決方法2:
slave比較少的時候還可以,但是當從庫有幾十台時,逐台去處理既費時又容易出錯,怎樣在主庫這一側一勞永逸地避免呢?
那很簡單,我們不要讓主庫將alter語句記錄到binlog中就行
我們直接這主庫中關閉binlog記錄
mysql> set sql_log_bin=off;
然后我們再執行alter語句
mysql> alter table student add age int default 0 after name;
再開啟bin-log
mysql> set sql_log_bin=on;
錯誤2:
這種要求對齊binlog
先到作為它的主上查看binlog
Slave上不對應
Slave上操作:
mysql> stop slave;
mysql> change master to master_host='10.10.10.65',master_user='repl',master_password='123456',master_log_file='mysql-bin-slave1.000002',master_log_pos=415;
mysql> start slave;
Ok,恢復正常