Mysql復(fù)制概念說明
Mysql內(nèi)建的復(fù)制功能是構(gòu)建大型,高性能應(yīng)用程序的基礎(chǔ)思灌。將Mysql的數(shù)據(jù)分布到多個系統(tǒng)上去,這種分布的機(jī)制晨继,是通過將Mysql的某一臺主機(jī)的數(shù)據(jù)復(fù)制到其它主機(jī)(slaves)上,并重新執(zhí)行一遍來實現(xiàn)的藏鹊。復(fù)制過程中一個服務(wù)器充當(dāng)主服務(wù)器菇曲,而一個或多個其它服務(wù)器充當(dāng)從服務(wù)器。主服務(wù)器將更新寫入二進(jìn)制日志文件献联,并維護(hù)文件的一個索引以跟蹤日志循環(huán)。這些日志可以記錄發(fā)送到從服務(wù)器的更新就缆。當(dāng)一個從服務(wù)器連接主服務(wù)器時,它通知主服務(wù)器從服務(wù)器在日志中讀取的最后一次成功更新的位置嗤谚。從服務(wù)器接收從那時起發(fā)生的任何更新,然后封鎖并等待主服務(wù)器通知新的更新妖爷。
需要注意的是:
在進(jìn)行mysql復(fù)制時,所有對復(fù)制中的表的更新必須在主服務(wù)器上進(jìn)行国拇。否則必須要小心崎岂,以避免用戶對主服務(wù)器上的表進(jìn)行的更新與對從服務(wù)器上的表所進(jìn)行的更新之間的沖突何暇。
1)Mysql支持那些復(fù)制
1--基于語句的復(fù)制: 在主服務(wù)器上執(zhí)行的SQL語句胳嘲,在從服務(wù)器上執(zhí)行同樣的語句。MySQL默認(rèn)采用基于語句的復(fù)制浇衬,效率比較高铃绒。一旦發(fā)現(xiàn)沒法精確復(fù)制時届榄,會自動選著基于行的復(fù)制埠忘。
2--基于行的復(fù)制:把改變的內(nèi)容復(fù)制過去,而不是把命令在從服務(wù)器上執(zhí)行一遍. 從mysql5.0開始支持
3--混合類型的復(fù)制: 默認(rèn)采用基于語句的復(fù)制,一旦發(fā)現(xiàn)基于語句的無法精確的復(fù)制時癣亚,就會采用基于行的復(fù)制。
2)Mysql復(fù)制能解決的問題
1--數(shù)據(jù)分布 (Data distribution )
2--負(fù)載平衡(load balancing)
3--數(shù)據(jù)備份(Backups) ,保證數(shù)據(jù)安全
4--高可用性和容錯行(High availability and failover)
5--實現(xiàn)讀寫分離弄痹,緩解數(shù)據(jù)庫壓力
3)Mysql主從復(fù)制原理
master服務(wù)器將數(shù)據(jù)的改變記錄二進(jìn)制binlog日志,當(dāng)master上的數(shù)據(jù)發(fā)生改變時锄列,則將其改變寫入二進(jìn)制日志中;salve服務(wù)器會在一定時間間隔內(nèi)對master二進(jìn)制日志進(jìn)行探測其是否發(fā)生改變,如果發(fā)生改變劫映,則開始一個I/OThread請求master二進(jìn)制事件膏斤,同時主節(jié)點為每個I/O線程啟動一個dump線程较曼,用于向其發(fā)送二進(jìn)制事件冕末,并保存至從節(jié)點本地的中繼日志中,從節(jié)點將啟動SQL線程從中繼日志中讀取二進(jìn)制日志,在本地重放州弟,使得其數(shù)據(jù)和主節(jié)點的保持一致,最后I/OThread和SQLThread將進(jìn)入睡眠狀態(tài)拜隧,等待下一次被喚醒忿峻。
注意幾點:
1--master將操作語句記錄到binlog日志中,然后授予slave遠(yuǎn)程連接的權(quán)限(master一定要開啟binlog二進(jìn)制日志功能辕羽;通常為了數(shù)據(jù)安全考慮逛尚,slave也開啟binlog功能)。
2--slave開啟兩個線程:IO線程和SQL線程刁愿。其中:IO線程負(fù)責(zé)讀取master的binlog內(nèi)容到中繼日志relay log里绰寞;SQL線程負(fù)責(zé)從relay log日志里讀出binlog內(nèi)容,并更新到slave的數(shù)據(jù)庫里铣口,這樣就能保證slave數(shù)據(jù)和master數(shù)據(jù)保持一致了滤钱。
3--Mysql復(fù)制至少需要兩個Mysql的服務(wù),當(dāng)然Mysql服務(wù)可以分布在不同的服務(wù)器上脑题,也可以在一臺服務(wù)器上啟動多個服務(wù)件缸。
4--Mysql復(fù)制最好確保master和slave服務(wù)器上的Mysql版本相同(如果不能滿足版本一致,那么要保證master主節(jié)點的版本低于slave從節(jié)點的版本)
5--master和slave兩節(jié)點間時間需同步
Mysql復(fù)制的流程圖如下:
如上圖所示:
Mysql復(fù)制過程的第一部分就是master記錄二進(jìn)制日志旭蠕。在每個事務(wù)更新數(shù)據(jù)完成之前停团,master在二日志記錄這些改變旷坦。MySQL將事務(wù)串行的寫入二進(jìn)制日志,即使事務(wù)中的語句都是交叉執(zhí)行的佑稠。在事件寫入二進(jìn)制日志完成后秒梅,master通知存儲引擎提交事務(wù)。
第二部分就是slave將master的binary log拷貝到它自己的中繼日志舌胶。首先捆蜀,slave開始一個工作線程——I/O線程。I/O線程在master上打開一個普通的連接幔嫂,然后開始binlog dump process辆它。Binlog dump process從master的二進(jìn)制日志中讀取事件,如果已經(jīng)跟上master履恩,它會睡眠并等待master產(chǎn)生新的事件锰茉。I/O線程將這些事件寫入中繼日志。
SQL slave thread(SQL從線程)處理該過程的最后一步切心。SQL線程從中繼日志讀取事件飒筑,并重放其中的事件而更新slave的數(shù)據(jù),使其與master中的數(shù)據(jù)一致绽昏。只要該線程與I/O線程保持一致协屡,中繼日志通常會位于OS的緩存中,所以中繼日志的開銷很小全谤。
此外肤晓,在master中也有一個工作線程:和其它MySQL的連接一樣,slave在master中打開一個連接也會使得master開始一個線程认然。復(fù)制過程有一個很重要的限制——復(fù)制在slave上是串行化的补憾,也就是說master上的并行更新操作不能在slave上并行操作。
4)Mysql復(fù)制的模式
1--主從復(fù)制:主庫授權(quán)從庫遠(yuǎn)程連接季眷,讀取binlog日志并更新到本地數(shù)據(jù)庫的過程余蟹;主庫寫數(shù)據(jù)后卷胯,從庫會自動同步過來(從庫跟著主庫變)子刮;
2--主主復(fù)制:主從相互授權(quán)連接,讀取對方binlog日志并更新到本地數(shù)據(jù)庫的過程窑睁;只要對方數(shù)據(jù)改變挺峡,自己就跟著改變;
5)Mysql主從復(fù)制的優(yōu)點
1--在從服務(wù)器可以執(zhí)行查詢工作(即我們常說的讀功能)担钮,降低主服務(wù)器壓力;(主庫寫橱赠,從庫讀,降壓)
2--在從主服務(wù)器進(jìn)行備份箫津,避免備份期間影響主服務(wù)器服務(wù);(確保數(shù)據(jù)安全)
3--當(dāng)主服務(wù)器出現(xiàn)問題時狭姨,可以切換到從服務(wù)器宰啦。(提升性能)
6)Mysql主從復(fù)制工作流程細(xì)節(jié)
1)MySQL支持單向、異步復(fù)制饼拍,復(fù)制過程中一個服務(wù)器充當(dāng)主服務(wù)器赡模,而一個或多個其它服務(wù)器充當(dāng)從服務(wù)器。MySQL復(fù)制基于主服務(wù)器在二進(jìn)制日志中跟蹤所有對數(shù)據(jù)庫的更改(更新师抄、刪除等等)漓柑。因此,要進(jìn)行復(fù)制叨吮,必須在主服務(wù)器上啟用二進(jìn)制日志辆布。每個從服務(wù)器從主服務(wù)器接收主服務(wù)器上已經(jīng)記錄到其二進(jìn)制日志的保存的更新。當(dāng)一個從服務(wù)器連接主服務(wù)器時茶鉴,它通知主服務(wù)器定位到從服務(wù)器在日志中讀取的最后一次成功更新的位置锋玲。從服務(wù)器接收從那時起發(fā)生的任何更新,并在本機(jī)上執(zhí)行相同的更新涵叮。然后封鎖并等待主服務(wù)器通知新的更新嫩絮。從服務(wù)器執(zhí)行備份不會干擾主服務(wù)器,在備份過程中主服務(wù)器可以繼續(xù)處理更新围肥。
2)MySQL使用3個線程來執(zhí)行復(fù)制功能剿干,其中兩個線程(Sql線程和IO線程)在從服務(wù)器,另外一個線程(IO線程)在主服務(wù)器穆刻。
當(dāng)發(fā)出START SLAVE時置尔,從服務(wù)器創(chuàng)建一個I/O線程,以連接主服務(wù)器并讓它發(fā)送記錄在其二進(jìn)制日志中的語句氢伟。主服務(wù)器創(chuàng)建一個線程將二進(jìn)制日志中的內(nèi)容發(fā)送到從服務(wù)器榜轿。該線程可以即為主服務(wù)器上SHOW PROCESSLIST的輸出中的Binlog Dump線程。從服務(wù)器I/O線程讀取主服務(wù)器Binlog Dump線程發(fā)送的內(nèi)容并將該數(shù)據(jù)拷貝到從服務(wù)器數(shù)據(jù)目錄中的本地文件中朵锣,即中繼日志谬盐。第3個線程是SQL線程,由從服務(wù)器創(chuàng)建诚些,用于讀取中繼日志并執(zhí)行日志中包含的更新飞傀。在從服務(wù)器上,讀取和執(zhí)行更新語句被分成兩個獨立的任務(wù)诬烹。當(dāng)從服務(wù)器啟動時砸烦,其I/O線程可以很快地從主服務(wù)器索取所有二進(jìn)制日志內(nèi)容,即使SQL線程執(zhí)行更新的遠(yuǎn)遠(yuǎn)滯后绞吁。
--------------------------下面記錄下mysql主從/主主同步環(huán)境的實施過程-------------------------
1)環(huán)境描述
mysql的安裝可以參考:http://www.cnblogs.com/kevingrace/p/6109679.html
Centos6.8版本
master:182.148.15.238
slave: 182.148.15.237
注意下面幾點:
1)要保證同步服務(wù)期間之間的網(wǎng)絡(luò)聯(lián)通幢痘。即能相互ping通,能使用對方授權(quán)信息連接到對方數(shù)據(jù)庫(防火墻開放3306端口)家破。
2)關(guān)閉selinux颜说。
3)同步前购岗,雙方數(shù)據(jù)庫中需要同步的數(shù)據(jù)要保持一致。這樣门粪,同步環(huán)境實現(xiàn)后藕畔,再次更新的數(shù)據(jù)就會如期同步了。
2)主從復(fù)制實現(xiàn)過程記錄
為了測試效果庄拇,先在master機(jī)器上創(chuàng)建測試庫
mysql> CREATE DATABASE huanqiu CHARACTER SET utf8 COLLATE utf8_general_ci;
Query OK, 1 row affected (0.00 sec)
mysql> use huanqiu;
Database changed
mysql> create table if not exists haha (id int(10) PRIMARY KEY AUTO_INCREMENT,name varchar(50) NOT NULL);
Query OK, 0 rows affected (0.02 sec)
mysql> insert into huanqiu.haha values(1,"wangshibo"),(2,"guohuihui");
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from huanqiu.haha;
+----+-----------+
| id | name |
+----+-----------+
| 1 | wangshibo |
| 2 | guohuihui |
+----+-----------+
2 rows in set (0.00 sec)
溫馨提示:
修改庫或表的字符集
mysql> alter database huanqiu default character set utf8; //修改huanqiu庫的字符集
mysql> alter table huanqiu.haha default character set utf8; //修改huanqiu.haha表的字符集
添加主鍵
mysql> Alter table huanqiu.haha add primary key(id); //將huanqiu.haha表的id添加主鍵
mysql> Alter table huanqiu.haha change id id int(10) not null auto_increment; //自增長屬性
刪除主鍵時要先刪除自增長注服,再刪除主鍵
mysql> Alter table huanqiu.haha change id id int(10); //刪除自增長
mysql> Alter table huanqiu.haha drop primary key; //刪除主建
下面是master數(shù)據(jù)庫上的操作:
1)設(shè)置master數(shù)據(jù)庫的my.cnf文件(在[mysqld]配置區(qū)域添加下面內(nèi)容)
[root@master ~]# vim /usr/local/mysql/my.cnf
.......
server-id=1 #數(shù)據(jù)庫唯一ID,主從的標(biāo)識號絕對不能重復(fù)措近。
log-bin=mysql-bin #開啟bin-log溶弟,并指定文件目錄和文件名前綴
binlog-do-db=huanqiu #需要同步的數(shù)據(jù)庫。如果是多個同步庫瞭郑,就以此格式另寫幾行即可辜御。如果不指明對某個具體庫同步,就去掉此行屈张,表示同步所有庫(除了ignore忽略的庫)擒权。
binlog-ignore-db=mysql #不同步mysql系統(tǒng)數(shù)據(jù)庫。如果是多個不同步庫阁谆,就以此格式另寫幾行碳抄;也可以在一行,中間逗號隔開场绿。
sync_binlog = 1 #確保binlog日志寫入后與硬盤同步
binlog_checksum = none #跳過現(xiàn)有的采用checksum的事件剖效,mysql5.6.5以后的版本中binlog_checksum=crc32,而低版本都是binlog_checksum=none
binlog_format = mixed #bin-log日志文件格式,設(shè)置為MIXED可以防止主鍵重復(fù)焰盗。
溫馨提示:在主服務(wù)器上最重要的二進(jìn)制日志設(shè)置是sync_binlog璧尸,這使得mysql在每次提交事務(wù)的時候把二進(jìn)制日志的內(nèi)容同步到磁盤上,即使服務(wù)器崩潰也會把事件寫入日志中熬拒。
sync_binlog這個參數(shù)是對于MySQL系統(tǒng)來說是至關(guān)重要的爷光,他不僅影響到Binlog對MySQL所帶來的性能損耗,而且還影響到MySQL中數(shù)據(jù)的完整性澎粟。對于"sync_binlog"參數(shù)的各種設(shè)置的說明如下:
sync_binlog=0蛀序,當(dāng)事務(wù)提交之后,MySQL不做fsync之類的磁盤同步指令刷新binlog_cache中的信息到磁盤捌议,而讓Filesystem自行決定什么時候來做同步哼拔,或者cache滿了之后才同步到磁盤引有。
sync_binlog=n瓣颅,當(dāng)每進(jìn)行n次事務(wù)提交之后,MySQL將進(jìn)行一次fsync之類的磁盤同步指令來將binlog_cache中的數(shù)據(jù)強(qiáng)制寫入磁盤舌劳。
在MySQL中系統(tǒng)默認(rèn)的設(shè)置是sync_binlog=0也切,也就是不做任何強(qiáng)制性的磁盤刷新指令,這時候的性能是最好的捧搞,但是風(fēng)險也是最大的粉怕。因為一旦系統(tǒng)Crash健民,在binlog_cache中的所有binlog信息都會被丟失。而當(dāng)設(shè)置為“1”的時候贫贝,是最安全但是性能損耗最大的設(shè)置秉犹。因為當(dāng)設(shè)置為1的時候,即使系統(tǒng)Crash稚晚,也最多丟失binlog_cache中未完成的一個事務(wù)崇堵,對實際數(shù)據(jù)沒有任何實質(zhì)性影響。
從以往經(jīng)驗和相關(guān)測試來看客燕,對于高并發(fā)事務(wù)的系統(tǒng)來說鸳劳,“sync_binlog”設(shè)置為0和設(shè)置為1的系統(tǒng)寫入性能差距可能高達(dá)5倍甚至更多。
2)導(dǎo)出master數(shù)據(jù)庫多余slave數(shù)據(jù)庫中的數(shù)據(jù)也搓,然后導(dǎo)入到slave數(shù)據(jù)庫中赏廓。保證雙方在同步環(huán)境實現(xiàn)前的數(shù)據(jù)一致。
導(dǎo)出數(shù)據(jù)庫之前先鎖定數(shù)據(jù)庫
mysql> flush tables with read lock; #數(shù)據(jù)庫只讀鎖定命令傍妒,防止導(dǎo)出數(shù)據(jù)庫的時候有數(shù)據(jù)寫入幔摸。unlock tables命令解除鎖定
導(dǎo)出master數(shù)據(jù)庫中多余的huanqiu庫(master數(shù)據(jù)庫的root用戶登陸密碼:123456)
[root@master ~]# mysqldump -uroot huanqiu -p123456 >/opt/huanqiu.sql
[root@master ~]# rsync -e "ssh -p22" -avpgolr /opt/huanqiu.sql 182.148.15.237:/opt/ #將導(dǎo)出的sql文件上傳到slave機(jī)器上
3)設(shè)置數(shù)據(jù)同步權(quán)限
mysql> grant replication slave,replication client on . to slave@'182.148.15.237' identified by "slave@123";
Query OK, 0 rows affected (0.02 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
溫馨提示:
權(quán)限查看方式
mysql> show grants;
mysql> show grants for slave@'182.148.1115.237';
4)查看主服務(wù)器master狀態(tài)(注意File與Position項,從服務(wù)器需要這兩項參數(shù))
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000007 | 120 | huanqiu | mysql | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
下面是slave數(shù)據(jù)庫上的操作:
1)設(shè)置slave數(shù)據(jù)庫的my.cnf配置文件
[root@master ~]# vim /usr/local/mysql/my.cnf
.......
server-id=2 #設(shè)置從服務(wù)器id颤练,必須于主服務(wù)器不同
log-bin=mysql-bin #啟動MySQ二進(jìn)制日志系統(tǒng)
replicate-do-db=huanqiu #需要同步的數(shù)據(jù)庫名抚太。如果不指明同步哪些庫,就去掉這行昔案,表示所有庫的同步(除了ignore忽略的庫)尿贫。
replicate-ignore-db=mysql #不同步mysql系統(tǒng)數(shù)據(jù)庫
slave-skip-errors = all #跳過所有的錯誤錯誤,繼續(xù)執(zhí)行復(fù)制操作
溫馨提示:
當(dāng)只針對某些庫的某張表進(jìn)行同步時踏揣,如下庆亡,只同步huanqiu庫的haha表和huanpc庫的heihei表:
replicate-do-db = huanqiu
replicate-wild-do-table = huanqiu.haha //當(dāng)只同步幾個或少數(shù)表時,可以這樣設(shè)置捞稿。注意這要跟上面的庫指定配合使用又谋;
replicate-do-db = huanpc
replicate-wild-do-table = huanpc.heihei //如果同步的庫的表比較多時,就不能這樣一一指定了娱局,就把這個選項配置去掉彰亥,直接根據(jù)指定的庫進(jìn)行同步。
2)在slave數(shù)據(jù)庫中導(dǎo)入從master傳過來的數(shù)據(jù)衰齐。
mysql> CREATE DATABASE huanqiu CHARACTER SET utf8 COLLATE utf8_general_ci; #先創(chuàng)建一個huanqiu空庫任斋,否則下面導(dǎo)入數(shù)據(jù)時會報錯說此庫不存在。
mysql> use huanqiu;
mysql> source /opt/huanqiu.sql; #導(dǎo)入master中多余的數(shù)據(jù)耻涛。
.......
3)配置主從同步指令
mysql> stop slave; #執(zhí)行同步前废酷,要先關(guān)閉slave
mysql> change master to master_host='182.148.15.238',master_user='slave',master_password='slave@123',master_log_file='mysql-bin.000007',master_log_pos=120;
mysql> start slave;
mysql> show slave status \G;
.......
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 182.148.15.238
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000007
Read_Master_Log_Pos: 120
Relay_Log_File: mysql-relay-bin.000002
Relay_Log_Pos: 279
Relay_Master_Log_File: mysql-bin.000007
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB: huanqiu
Replicate_Ignore_DB: mysql
.............
Seconds_Behind_Master: 0
如上瘟檩,當(dāng)IO和SQL線程的狀態(tài)均為Yes,則表示主從已實現(xiàn)同步了澈蟆!
查看slave數(shù)據(jù)庫中的數(shù)據(jù)情況
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| huanqiu |
| mysql |
| performance_schema |
| test |
+--------------------+
5 rows in set (0.00 sec)
mysql> select * from huanqiu.haha;
+----+-----------+
| id | name |
+----+-----------+
| 1 | wangshibo |
| 2 | guohuihui |
+----+-----------+
2 rows in set (0.00 sec)
下面測試下Mysql主從同步的效果
現(xiàn)在主數(shù)據(jù)庫上寫入新數(shù)據(jù)
mysql> unlock tables; #解鎖墨辛,否則新數(shù)據(jù)無法寫入
mysql> insert into huanqiu.haha values(100,"anhui");
Query OK, 1 row affected (0.00 sec)
然后在slave數(shù)據(jù)庫上查看,發(fā)現(xiàn)master上新寫入的數(shù)據(jù)已經(jīng)同步過來了
mysql> select * from huanqiu.haha;
+-----+-----------+
| id | name |
+-----+-----------+
| 1 | wangshibo |
| 2 | guohuihui |
| 100 | anhui |
+-----+-----------+
3 rows in set (0.00 sec)
至此趴俘,主從同步環(huán)境已經(jīng)實現(xiàn)睹簇!