環(huán)境
操作系統(tǒng):CentOS-6.5-x86_64-bin-DVD1.iso
MySQL版本:mysql-5.6.29.tar.gz
主節(jié)點(diǎn)IP:192.168.1.205 主機(jī)名:edu-mysql-01
從節(jié)點(diǎn)IP:192.168.1.206 主機(jī)名:edu-mysql-02
主機(jī)配置:4核CPU、4G內(nèi)存
依賴課程
《高可用架構(gòu)篇--第13節(jié)--MySQL源碼編譯安裝(CentOS-6.5+MySQL-5.6)》
MySQL主從復(fù)制官方文檔
http://dev.mysql.com/doc/refman/5.6/en/replication.html
MySQL主從復(fù)制的方式
MySQL5.6開始主從復(fù)制有兩種方式:基于日志(binlog)、基于GTID(全局事務(wù)標(biāo)示符)。
本教程主要講基于日志(binlog)的復(fù)制。
MySQL主從復(fù)制(也稱A/B復(fù)制)的原理
(1) Master將數(shù)據(jù)改變記錄到二進(jìn)制日志(binary log)中,也就是配置文件log-bin指定的文件,這些記錄叫做二進(jìn)制日志事件(binary log events);
(2) Slave通過I/O線程讀取Master中的binary log events并寫入到它的中繼日志(relay log);
(3) Slave重做中繼日志中的事件,把中繼日志中的事件信息一條一條的在本地執(zhí)行一次,完成數(shù)據(jù)在本地的存儲(chǔ),從而實(shí)現(xiàn)將改變反映到它自己的數(shù)據(jù)(數(shù)據(jù)重放)。
主從配置需要注意的點(diǎn)
(1)主從服務(wù)器操作系統(tǒng)版本和位數(shù)一致;
(2) Master和Slave數(shù)據(jù)庫(kù)的版本要一致;
(3) Master和Slave數(shù)據(jù)庫(kù)中的數(shù)據(jù)要一致;
(4) Master開啟二進(jìn)制日志,Master和Slave的server_id在局域網(wǎng)內(nèi)必須唯一;
主從配置的簡(jiǎn)要步驟
1、Master上的配置
(1) 安裝數(shù)據(jù)庫(kù);
(2) 修改數(shù)據(jù)庫(kù)配置文件,指明server_id,開啟二進(jìn)制日志(log-bin);
(3) 啟動(dòng)數(shù)據(jù)庫(kù),查看當(dāng)前是哪個(gè)日志,position號(hào)是多少;
(4) 登錄數(shù)據(jù)庫(kù),授權(quán)數(shù)據(jù)復(fù)制用戶(IP地址為從機(jī)IP地址,如果是雙向主從,這里的還需要授權(quán)本機(jī)的IP地址,此時(shí)自己的IP地址就是從IP地址);
(5) 備份數(shù)據(jù)庫(kù)(記得加鎖和解鎖);
(6) 傳送備份數(shù)據(jù)到Slave上;
(7) 啟動(dòng)數(shù)據(jù)庫(kù);
以下步驟,為單向主從搭建成功,想搭建雙向主從需要的步驟:
(1) 登錄數(shù)據(jù)庫(kù),指定Master的地址、用戶、密碼等信息(此步僅雙向主從時(shí)需要);
(2) 開啟同步,查看狀態(tài);
2、Slave上的配置
(1) 安裝數(shù)據(jù)庫(kù);
(2) 修改數(shù)據(jù)庫(kù)配置文件,指明server_id(如果是搭建雙向主從的話,也要開啟二進(jìn)制日志log-bin);
(3) 啟動(dòng)數(shù)據(jù)庫(kù),還原備份;
(4) 查看當(dāng)前是哪個(gè)日志,position號(hào)是多少(單向主從此步不需要,雙向主從需要);
(5) 指定Master的地址、用戶、密碼等信息;
(6) 開啟同步,查看狀態(tài)。
單向主從環(huán)境(也稱MySQL A/B復(fù)制)的搭建
1、Master(192.168.1.205)和Slave(192.168.1.206)上都安裝了相同版本的數(shù)據(jù)庫(kù)(mysql-5.6.26.tar.gz)。
注意:兩臺(tái)數(shù)據(jù)庫(kù)服務(wù)器的的selinux都要disable(永久關(guān)閉selinux,請(qǐng)修改/etc/selinux/config,將SELINUX改為disabled)
2、修改Master的配置文件/etc/my.cnf
[root@edu-mysql-01 ~]# vi /etc/my.cnf
## 在 [mysqld] 中增加以下配置項(xiàng)
## 設(shè)置server_id,一般設(shè)置為IP
server_id=205
## 復(fù)制過濾:需要備份的數(shù)據(jù)庫(kù),輸出binlog
#binlog-do-db=roncoo
## 復(fù)制過濾:不需要備份的數(shù)據(jù)庫(kù),不輸出(mysql庫(kù)一般不同步)
binlog-ignore-db=mysql
## 開啟二進(jìn)制日志功能,可以隨便取,最好有含義
log-bin=edu-mysql-bin
## 為每個(gè)session 分配的內(nèi)存,在事務(wù)過程中用來(lái)存儲(chǔ)二進(jìn)制日志的緩存
binlog_cache_size=1M
## 主從復(fù)制的格式(mixed,statement,row,默認(rèn)格式是statement)
binlog_format=mixed
## 二進(jìn)制日志自動(dòng)刪除/過期的天數(shù)。默認(rèn)值為0,表示不自動(dòng)刪除。
expire_logs_days=7
## 跳過主從復(fù)制中遇到的所有錯(cuò)誤或指定類型的錯(cuò)誤,避免slave端復(fù)制中斷。
## 如:1062錯(cuò)誤是指一些主鍵重復(fù),1032錯(cuò)誤是因?yàn)橹鲝臄?shù)據(jù)庫(kù)數(shù)據(jù)不一致
slave_skip_errors=1062
(如想了解以上參數(shù)的更多詳細(xì)解析,大家可以直接百度參數(shù)名)
2.1 復(fù)制過濾可以讓你只復(fù)制服務(wù)器中的一部分?jǐn)?shù)據(jù),有兩種復(fù)制過濾:
(1)在Master上過濾二進(jìn)制日志中的事件;
(2)在Slave上過濾中繼日志中的事件。如下:
2.2 MySQL對(duì)于二進(jìn)制日志 (binlog)的復(fù)制類型
(1) 基于語(yǔ)句的復(fù)制:在Master上執(zhí)行的SQL語(yǔ)句,在Slave上執(zhí)行同樣的語(yǔ)句。MySQL默認(rèn)采用基于語(yǔ)句的復(fù)制,效率比較高。一旦發(fā)現(xiàn)沒法精確復(fù)制時(shí),會(huì)自動(dòng)選著基于行的復(fù)制。
(2) 基于行的復(fù)制:把改變的內(nèi)容復(fù)制到Slave,而不是把命令在Slave上執(zhí)行一遍。從MySQL5.0開始支持。
(3) 混合類型的復(fù)制:默認(rèn)采用基于語(yǔ)句的復(fù)制,一旦發(fā)現(xiàn)基于語(yǔ)句的無(wú)法精確的復(fù)制時(shí),就會(huì)采用基于行的復(fù)制。
3、啟動(dòng)/重啟Master數(shù)據(jù)庫(kù)服務(wù),登錄數(shù)據(jù)庫(kù),創(chuàng)建數(shù)據(jù)同步用戶,并授予相應(yīng)的權(quán)限
[root@edu-mysql-01 ~]# service mysql restart
Shutting down MySQL..[ OK ]
Starting MySQL..[ OK ]
[root@edu-mysql-01 ~]# mysql -uroot -p
Enter password:
##創(chuàng)建數(shù)據(jù)同步用戶,并授予相應(yīng)的權(quán)限
mysql> grant replication slave, replication client on *.* to 'repl'@'192.168.1.206' identified by 'roncoo.123';
Query OK, 0 rows affected (0.00 sec)
## 刷新授權(quán)表信息
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
## 查看position號(hào),記下position號(hào)(從機(jī)上需要用到這個(gè)position號(hào)和現(xiàn)在的日志文件)
mysql> show master status;
4、創(chuàng)建roncoo庫(kù)、表,并寫入一定量的數(shù)據(jù),用于模擬現(xiàn)有的業(yè)務(wù)系統(tǒng)數(shù)據(jù)庫(kù)
create database if not exists roncoo default charset utf8 collate utf8_general_ci;
use roncoo;
DROP TABLE IF EXISTS `edu_user`;
CREATE TABLE `edu_user` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`userName` varchar(255) NOT NULL DEFAULT '' COMMENT '用戶名',
`pwd` varchar(255) NOT NULL DEFAULT '' COMMENT '密碼',
PRIMARY KEY (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='用戶信息表';
INSERT INTO `edu_user` VALUES (1,'吳水成','123456'),(2,'清風(fēng)','123456'),(3,'龍果','roncoo.com');
5、為保證Master和Slave的數(shù)據(jù)一致,我們采用主備份,從還原來(lái)實(shí)現(xiàn)初始數(shù)據(jù)一致
## 先臨時(shí)鎖表
mysql> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)
## 這里我們實(shí)行全庫(kù)備份,在實(shí)際中,我們可能只同步某一個(gè)庫(kù),那也可以只備份一個(gè)庫(kù)
[root@edu-mysql-01 ~]# mysqldump -p3306 -uroot -p --add-drop-table roncoo > /tmp/edu-master-roncoo.sql;
Warning: Using a password on the command line interface can be insecure.
Enter password:
[root@edu-mysql-01 ~]# cd /tmp
[root@edu-mysql-01 tmp]# ll
total 644
-rw-r--r-- 1 root root 644266 Dec 20 04:10 edu-master-roncoo.sql
## 注意:實(shí)際生產(chǎn)環(huán)境中大數(shù)據(jù)量(超2G數(shù)據(jù))的備份,建議不要使用mysqldump進(jìn)行比分,因?yàn)闀?huì)非常慢。此時(shí)推薦使用XtraBackup 進(jìn)行備份。
## 解鎖表
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
將Master上備份的數(shù)據(jù)遠(yuǎn)程傳送到Slave上,以用于Slave配置時(shí)恢復(fù)數(shù)據(jù)
[root@edu-mysql-01 ~]# scp /tmp/edu-master-roncoo.sql root@192.168.1.206:/tmp/
root@192.168.1.206's password:
edu-master-roncoo.sql 100% 629KB 629.2KB/s 00:00
[root@edu-mysql-01 ~]#
6、接下來(lái)處理Slave(192.168.1.206),配置文件只需修改一項(xiàng),其余配置用命令來(lái)操作
[root@edu-mysql-02 ~]# vi /etc/my.cnf
## 在 [mysqld] 中增加以下配置項(xiàng)
## 設(shè)置server_id,一般設(shè)置為IP
server_id=206
## 復(fù)制過濾:需要備份的數(shù)據(jù)庫(kù),輸出binlog
#binlog-do-db=roncoo
##復(fù)制過濾:不需要備份的數(shù)據(jù)庫(kù),不輸出(mysql庫(kù)一般不同步)
binlog-ignore-db=mysql
## 開啟二進(jìn)制日志,以備Slave作為其它Slave的Master時(shí)使用
log-bin=edu-mysql-slave1-bin
## 為每個(gè)session 分配的內(nèi)存,在事務(wù)過程中用來(lái)存儲(chǔ)二進(jìn)制日志的緩存
binlog_cache_size = 1M
## 主從復(fù)制的格式(mixed,statement,row,默認(rèn)格式是statement)
binlog_format=mixed
## 二進(jìn)制日志自動(dòng)刪除/過期的天數(shù)。默認(rèn)值為0,表示不自動(dòng)刪除。
expire_logs_days=7
## 跳過主從復(fù)制中遇到的所有錯(cuò)誤或指定類型的錯(cuò)誤,避免slave端復(fù)制中斷。
## 如:1062錯(cuò)誤是指一些主鍵重復(fù),1032錯(cuò)誤是因?yàn)橹鲝臄?shù)據(jù)庫(kù)數(shù)據(jù)不一致
slave_skip_errors=1062
## relay_log配置中繼日志
relay_log=edu-mysql-relay-bin
## log_slave_updates表示slave將復(fù)制事件寫進(jìn)自己的二進(jìn)制日志
log_slave_updates=1
## 防止改變數(shù)據(jù)(除了特殊的線程)
read_only=1
如果Slave為其它Slave的Master時(shí),必須設(shè)置bin_log。在這里,我們開啟了二進(jìn)制日志,而且顯式的命名(默認(rèn)名稱為hostname,但是,如果hostname改變則會(huì)出現(xiàn)問題)。
relay_log配置中繼日志,log_slave_updates表示slave將復(fù)制事件寫進(jìn)自己的二進(jìn)制日志。
當(dāng)設(shè)置log_slave_updates時(shí),你可以讓slave扮演其它slave的master。此時(shí),slave把SQL線程執(zhí)行的事件寫進(jìn)行自己的二進(jìn)制日志(binary
log),然后,它的slave可以獲取這些事件并執(zhí)行它。如下圖所示(發(fā)送復(fù)制事件到其它Slave):
7、保存后重啟MySQL服務(wù),還原備份數(shù)據(jù)
[root@edu-mysql-02 ~]# service mysql restart
Shutting down MySQL..[ OK ]
Starting MySQL..[ OK ]
Slave上創(chuàng)建相同庫(kù):
create database if not exists roncoo default charset utf8 collate utf8_general_ci;
use roncoo;
導(dǎo)入數(shù)據(jù)
[root@edu-mysql-02 ~]# mysql -uroot -p roncoo < /tmp/edu-master-roncoo.sql
Enter password:
[root@edu-mysql-02 ~]#
8、登錄Slave數(shù)據(jù)庫(kù),添加相關(guān)參數(shù)
(Master的IP、端口、同步用戶、密碼、position號(hào)、讀取哪個(gè)日志文件)
[root@edu-mysql-02 ~]# mysql -uroot -p
Enter password:
mysql>
change master to master_host='192.168.1.205', master_user='repl',
master_password='roncoo.123', master_port=3306,
master_log_file='edu-mysql-bin.000001', master_log_pos=1389,
master_connect_retry=30;
Query OK, 0 rows affected, 2 warnings (0.01 sec)
上面執(zhí)行的命令的解釋:
master_host='192.168.1.205' ## Master的IP地址
master_user='repl' ## 用于同步數(shù)據(jù)的用戶(在Master中授權(quán)的用戶)
master_password='roncoo.123'## 同步數(shù)據(jù)用戶的密碼
master_port=3306## Master數(shù)據(jù)庫(kù)服務(wù)的端口
master_log_file='edu-mysql-bin.000001'##指定Slave從哪個(gè)日志文件開始讀復(fù)制數(shù)據(jù)(可在Master上使用show master status查看到日志文件名)
master_log_pos=429## 從哪個(gè)POSITION號(hào)開始讀
master_connect_retry=30##當(dāng)重新建立主從連接時(shí),如果連接建立失敗,間隔多久后重試。單位為秒,默認(rèn)設(shè)置為60秒,同步延遲調(diào)優(yōu)參數(shù)。
## 查看主從同步狀態(tài)
mysql> show slave status\G;
可看到Slave_IO_State為空, Slave_IO_Running和Slave_SQL_Running是No,表明Slave還沒有開始復(fù)制過程。
## 開啟主從同步
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
## 再查看主從同步狀態(tài)
mysql> show slave status\G;
主要看以下兩個(gè)參數(shù),這兩個(gè)參數(shù)如果是Yes就表示主從同步正常
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
由截圖中的主從同步狀態(tài)信息可以看出,我們配置的主從同步是正常的。
可查看master和slave上線程的狀態(tài)。在master上,可以看到slave的I/O線程創(chuàng)建的連接:
Master : mysql> show processlist\G;
1.row 為處理slave的I/O線程的連接。
2.row 為處理MySQL客戶端連接線程。
3.row 為處理本地命令行的線程。
Slave : mysql> show processlist\G;
1.row為I/O線程狀態(tài)。
2.row 為SQL線程狀態(tài)。
3.row 為處理本地命令行的線程。
9、主從數(shù)據(jù)復(fù)制同步測(cè)試
(1) 在Master中的roncoo庫(kù)上變更數(shù)據(jù)的同步測(cè)試;
mysql> INSERT INTO `edu_user` VALUES (4,'同步測(cè)試1','123456'),(5,'同步測(cè)試2','123456');
Master中添加完之后,登錄Slave中查看數(shù)據(jù)是否已同步。
(2) 在Master上新建一個(gè)ron庫(kù)
mysql> create database if not exists ron default charset utf8 collate utf8_general_ci;
在Slave中查看數(shù)據(jù)庫(kù)
mysql> show databases;
最終的測(cè)試結(jié)果是,在Master中的操作,都成功同步到了Slave。
10、測(cè)試過程中,如果遇到同步出錯(cuò),可在Slave上重置主從復(fù)制設(shè)置(選操作):
(1) mysql> reset slave;
(2) mysql> change master to master_host='192.168.1.205',
master_user='repl',
master_password='roncoo.123',
master_port=3306,
master_log_file='edu-mysql-bin.00000x',
master_log_pos=xx,
master_connect_retry=30;
(此時(shí),master_log_file和master_log_pos要在Master中用show master status 命令查看)
注意:如果在Slave沒做只讀控制的情況下,千萬(wàn)不要在Slave中手動(dòng)插入數(shù)據(jù),那樣數(shù)據(jù)就會(huì)不一致,主從就會(huì)斷開,就需要重新配置了。
11、上面所搭建的是單向復(fù)制的主從,也是用的比較多的,而雙向主從其實(shí)就是Master和Slave都開啟日志功能,然后在Master執(zhí)行授權(quán)用戶(這里授權(quán)的是自己作為從服務(wù)器,也就是這里的IP地址是Master的IP地址),然后再在Master上進(jìn)行chang
master操作。
MySQL主從數(shù)據(jù)同步延遲問題的調(diào)優(yōu)
基于局域網(wǎng)的Master/Slave機(jī)制在通常情況下已經(jīng)可以滿足“實(shí)時(shí)”備份的要求了。如果延遲比較大,可以從以下幾個(gè)因素進(jìn)行排查:
(1) 網(wǎng)絡(luò)延遲;
(2) Master負(fù)載過高;
(3) Slave負(fù)載過高;
一般的做法是使用多臺(tái)Slave來(lái)分?jǐn)傋x請(qǐng)求,再單獨(dú)配置一臺(tái)Slave只作為備份用,不進(jìn)行其他任何操作,就能相對(duì)最大限度地達(dá)到“實(shí)時(shí)”的要求了。
兩個(gè)可以減少主從復(fù)制延遲的參數(shù)(按需配置):
MySQL可以指定3個(gè)參數(shù),用于復(fù)制線程重連主庫(kù):--master-retry-count,--master-connect-retry,--slave-net-timeout
。其中master-connect-retry 和 master-retry-count 需要在 Change Master
搭建主備復(fù)制時(shí)指定,而 slave-net-timeout 是一個(gè)全局變量,可以在 MySQL 運(yùn)行時(shí)在線設(shè)置。具體的重試策略為:備庫(kù)過了
slave-net-timeout 秒還沒有收到主庫(kù)來(lái)的數(shù)據(jù),它就會(huì)開始第一次重試。然后每過 master-connect-retry
秒,備庫(kù)會(huì)再次嘗試重連主庫(kù)。直到重試了 master-retry-count
次,它才會(huì)放棄重試。如果重試的過程中,連上了主庫(kù),那么它認(rèn)為當(dāng)前主庫(kù)是好的,又會(huì)開始 slave-net-timeout
秒的等待。slave-net-timeout 的默認(rèn)值是 3600 秒,master-connect-retry 默認(rèn)為 60
秒,master-retry-count 默認(rèn)為 86400
次。也就是說(shuō),如果主庫(kù)一個(gè)小時(shí)都沒有任何數(shù)據(jù)變更發(fā)送過來(lái),備庫(kù)才會(huì)嘗試重連主庫(kù)。這就是為什么在我們模擬的場(chǎng)景下,一個(gè)小時(shí)后,備庫(kù)才會(huì)重連主庫(kù),繼續(xù)同步數(shù)據(jù)變更的原因。
這樣的話,如果你的主庫(kù)上變更比較頻繁,可以考慮將
slave-net-timeout 設(shè)置的小一點(diǎn),避免主庫(kù) Binlog dump 線程終止了,無(wú)法將最新的更新推送過來(lái)。當(dāng)然
slave-net-timeout 設(shè)置的過小也有問題,這樣會(huì)導(dǎo)致如果主庫(kù)的變更確實(shí)比較少的時(shí)候,備庫(kù)頻繁的重新連接主庫(kù),造成資源浪費(fèi)。
slave-net-timeout=seconds
參數(shù)說(shuō)明:當(dāng)Slave從Master數(shù)據(jù)庫(kù)讀取log數(shù)據(jù)失敗后,等待多久重新建立連接并獲取數(shù)據(jù),單位為秒,默認(rèn)設(shè)置為3600秒。
在做MySQL
Slave的時(shí)候經(jīng)常會(huì)遇到很多錯(cuò)誤,需要根據(jù)具體原因跨過錯(cuò)誤繼續(xù)同步,但有時(shí)候是因?yàn)榫W(wǎng)絡(luò)不穩(wěn)定、網(wǎng)絡(luò)閃斷造成同步不正常,如果Slave機(jī)器非常多的情況下,一個(gè)一個(gè)登錄服務(wù)器去stop
slave、start slave變得無(wú)聊而且重復(fù)。從MySQL5.1開始支持的解決方案配置:
master-connect-retry=seconds
參數(shù)說(shuō)明:在主服務(wù)器宕機(jī)或連接丟失的情況下,從服務(wù)器線程重新嘗試連接主服務(wù)器之前睡眠的秒數(shù)。如果主服務(wù)器.info文件中的值可以讀取則優(yōu)先使用。如果未設(shè)置,默認(rèn)值為60。
通常配置以上2個(gè)參數(shù)可以減少網(wǎng)絡(luò)問題導(dǎo)致的主從數(shù)據(jù)同步延遲。
一般網(wǎng)絡(luò)問題的錯(cuò)誤是:
[ERROR] Error reading packet from server: Lost connection to MySQL server during query (server_errno=xxxx)
[ERROR] Slave I/O thread: Failed reading log event, reconnecting to retry, log ‘edu-mysql-bin.000256’ position 23456