雙機熱備的概念簡單說一下,就是要保持兩個數(shù)據(jù)庫的狀態(tài)自動同步。對任何一個數(shù)據(jù)庫的操作都自動應(yīng)用到另外一個數(shù)據(jù)庫,始終保持兩個數(shù)據(jù)庫數(shù)據(jù)一致。 這樣做的好處多。 1. 可以做災(zāi)備,其中一個壞了可以切換到另一個。 2. 可以做負載均衡,可以將請求分攤到其中任何一臺上,提高網(wǎng)站吞吐量。 對于異地?zé)醾?,尤其適合災(zāi)備。廢話不多說了。我們直接進入主題。 我們會主要介紹兩部分內(nèi)容:
一, mysql 備份工作原理
二, 備份實戰(zhàn)
我們開始。
我使用的是mysql 5.5.34,
一, mysql 備份工作原理
簡單的說就是把 一個服務(wù)器上執(zhí)行過的sql語句在別的服務(wù)器上也重復(fù)執(zhí)行一遍, 這樣只要兩個數(shù)據(jù)庫的初態(tài)是一樣的,那么它們就能一直同步。
當然這種復(fù)制和重復(fù)都是mysql自動實現(xiàn)的,我們只需要配置即可。
我們進一步詳細介紹原理的細節(jié), 這有一張圖:
上圖中有兩個服務(wù)器, 演示了從一個主服務(wù)器(master) 把數(shù)據(jù)同步到從服務(wù)器(slave)的過程。
這是一個主-從復(fù)制的例子。 主-主互相復(fù)制只是把上面的例子反過來再做一遍。 所以我們以這個例子介紹原理。
對于一個mysql服務(wù)器, 一般有兩個線程來負責(zé)復(fù)制和被復(fù)制。當開啟復(fù)制之后。
1. 作為主服務(wù)器Master, 會把自己的每一次改動都記錄到 二進制日志 Binarylog 中。 (從服務(wù)器會負責(zé)來讀取這個log, 然后在自己那里再執(zhí)行一遍。)
2. 作為從服務(wù)器Slave, 會用master上的賬號登陸到 master上, 讀取master的Binarylog, 寫入到自己的中繼日志 Relaylog, 然后自己的sql線程會負責(zé)讀取這個中繼日志,并執(zhí)行一遍。 到這里主服務(wù)器上的更改就同步到從服務(wù)器上了。
在mysql上可以查看當前服務(wù)器的主,從狀態(tài)。 其實就是當前服務(wù)器的 Binary(作為主服務(wù)器角色)狀態(tài)和位置。 以及其RelayLog(作為從服務(wù)器)的復(fù)制進度。
例如我們在主服務(wù)器上查看主狀態(tài):
mysql> show master status\G*************************** 1. row *************************** File: mysql-bin.000014 Position: 107 Binlog_Do_DB: Binlog_Ignore_DB: mysql,information_schema,performance_schema,amh1 row in set (0.00 sec)
稍微解釋一下這幾行的意思:
1. 第一行表明 當前正在記錄的 binarylog文件名是: mysql-bin.000014.
我們可以在mysql數(shù)據(jù)目錄下,找到這個文件:
2. 第二行, 107. 表示當前的文件偏移量, 就是寫入在mysql-bin.000014 文件的記錄位置。
這兩點就構(gòu)成了 主服務(wù)器的狀態(tài)。 配置從服務(wù)器的時候,需要用到這兩個值。 告訴從服務(wù)器從哪讀取主服務(wù)器的數(shù)據(jù)。 (從服務(wù)器會登錄之后,找到這個日志文件,并從這個偏移量之后開始復(fù)制。)
3. 第三行,和第四行,表示需要記錄的數(shù)據(jù)庫和需要忽略的數(shù)據(jù)庫。 只有需要記錄的數(shù)據(jù)庫,其變化才會被寫入到mysql-bin.000014日志文件中。 后面會再次介紹這兩個參數(shù)。
我們還可以在從服務(wù)器上,查看從服務(wù)器的復(fù)制狀態(tài)。
1: mysql> show slave status\G
2: *************************** 1. row ***************************
3: Slave_IO_State: Waiting for master to send event
4: Master_Host: 198.**.***.***
5: Master_User: r*******
6: Master_Port: 3306
7: Connect_Retry: 60
8: Master_Log_File: mysql-bin.000014
9: Read_Master_Log_Pos: 107
10: Relay_Log_File: mysqld-relay-bin.000013
11: Relay_Log_Pos: 253
12: Relay_Master_Log_File: mysql-bin.000014
13: Slave_IO_Running: Yes
14: Slave_SQL_Running: Yes
15: Replicate_Do_DB:
16: Replicate_Ignore_DB: mysql,information_schema,amh,performance_schema
17: Replicate_Do_Table:
18: Replicate_Ignore_Table:
19: Replicate_Wild_Do_Table:
20: Replicate_Wild_Ignore_Table:
21: Last_Errno: 0
22: Last_Error:
23: Skip_Counter: 0
24: Exec_Master_Log_Pos: 107
25: Relay_Log_Space: 556
26: Until_Condition: None
27: Until_Log_File:
28: Until_Log_Pos: 0
29: Master_SSL_Allowed: No
我們還是來重點解釋途中的紅圈的部分:
1. Master_host 指的是 主服務(wù)器的地址。
2. Master_user 指的是主服務(wù)器上用來復(fù)制的用戶。 從服務(wù)器會用此賬號來登錄主服務(wù)。進行復(fù)制。
3. Master_log_file 就是前面提到的, 主服務(wù)器上的日志文件名.
4. Read_Master_log_pos 就是前面提到的主服務(wù)器的日志記錄位置, 從服務(wù)器根據(jù)這兩個條件來選擇復(fù)制的文件和位置。
5. Slave_IO_Running: 指的就是從服務(wù)器上負責(zé)讀取主服務(wù)器的線程工作狀態(tài)。 從服務(wù)器用這個專門的線程鏈接到主服務(wù)器上,并把日志拷貝回來。
6. Slave_SQL_Running: 指的就是專門執(zhí)行sql的線程。 它負責(zé)把復(fù)制回來的Relaylog執(zhí)行到自己的數(shù)據(jù)庫中。 這兩個參數(shù)必須都為Yes 才表明復(fù)制在正常工作。
其他的參數(shù)之后再介紹。
二, mysql 雙機熱備實戰(zhàn)
了解了上面的原理之后, 我們來實戰(zhàn)。 這里有兩個重點, 要想同步數(shù)據(jù)庫狀態(tài), 需要相同的初態(tài),然后配置同步才有意義。 當然你可以不要初態(tài),這是你的自由。 我們這里從頭開始配置一遍。
我們先以A服務(wù)器為起點, 配置它的數(shù)據(jù)庫同步到B。 這就是主-從復(fù)制了。 之后再反過來做一次,就可以互相備份了。
1, 第一步,
在A上面創(chuàng)建專門用于備份的 用戶:
grant replication slave on *.* to 'repl_user'@'192.***.***.***' identified by 'hj34$%&mnkb';
上面把ip地址換成B機器的ip地址。 只允許B登錄。安全。
用戶名為: repl_user
密碼為: hj34$********nkb
這個等會在B上面要用。
2. 開啟主服務(wù)器的 binarylog。
很多服務(wù)器是默認開啟的,我們這里檢查一下:
打開 /etc/my.cnf
我來解釋一下紅框中的配置:
前面三行, 你可能已經(jīng)有了。
binlog-do-db 用來表示,只把哪些數(shù)據(jù)庫的改動記錄到binary日志中。 可以寫上關(guān)注hello數(shù)據(jù)庫。 但是我把它注釋掉了。 只是展示一下。 可以寫多行,表示關(guān)注多個數(shù)據(jù)庫。
binlog-ignore-db 表示,需要忽略哪些數(shù)據(jù)庫。我這里忽略了其他的4個數(shù)據(jù)庫。
后面兩個用于在 雙主(多主循環(huán))互相備份。 因為每臺數(shù)據(jù)庫服務(wù)器都可能在同一個表中插入數(shù)據(jù),如果表有一個自動增長的主鍵,那么就會在多服務(wù)器上出現(xiàn)主鍵沖突。 解決這個問題的辦法就是讓每個數(shù)據(jù)庫的自增主鍵不連續(xù)。 上圖說是, 我假設(shè)需要將來可能需要10臺服務(wù)器做備份, 所以auto-increment-increment 設(shè)為10. 而 auto-increment-offset=1 表示這臺服務(wù)器的序號。 從1開始, 不超過auto-increment-increment。
這樣做之后, 我在這臺服務(wù)器上插入的第一個id就是 1, 第二行的id就是 11了, 而不是2.
(同理,在第二臺服務(wù)器上插入的第一個id就是2, 第二行就是12, 這個后面再介紹) 這樣就不會出現(xiàn)主鍵沖突了。 后面我們會演示這個id的效果。
3. 獲取主服務(wù)器狀態(tài), 和同步初態(tài)。
假設(shè)我現(xiàn)在有這些數(shù)據(jù)庫在A上面。
如果你是全新安裝的, 那么不需要同步初態(tài),直接跳過這一步,到后面直接查看主服務(wù)器狀態(tài)。
這里我們假設(shè)有一個 hello 數(shù)據(jù)庫作為初態(tài)。
先鎖定 hello數(shù)據(jù)庫:
FLUSH TABLES WITH READ LOCK;
然后導(dǎo)出數(shù)據(jù):
我這里只需要導(dǎo)出hello數(shù)據(jù)庫, 如果你有多個數(shù)據(jù)庫作為初態(tài)的話, 需要導(dǎo)出所有這些數(shù)據(jù)庫:
然后查看A服務(wù)器的binary日志位置:
記住這個文件名和 位置, 等會在從服務(wù)器上會用到。
主服務(wù)器已經(jīng)做完了, 可以解除鎖定了:
4. 設(shè)置從服務(wù)器 B 需要復(fù)制的數(shù)據(jù)庫
打開從服務(wù)器 B 的 /etc/my.cnf 文件:
解釋一下上面的內(nèi)容。
server-id 必須保證每個服務(wù)器不一樣。 這可能和循環(huán)同步有關(guān)。 防止進入死循環(huán)。
replicate-do-db 可以指定需要復(fù)制的數(shù)據(jù)庫, 我這里注掉了。 演示一下。
replicate-ignore-db 復(fù)制時需要排除的數(shù)據(jù)庫, 我使用了,這個。 除開系統(tǒng)的幾個數(shù)據(jù)庫之外,所有的數(shù)據(jù)庫都復(fù)制。
relay_log 中繼日志的名字。 前面說到了, 復(fù)制線程需要先把遠程的變化拷貝到這個中繼日志中, 在執(zhí)行。
log-slave-updates 意思是,中繼日志執(zhí)行之后,這些變化是否需要計入自己的binarylog。 當你的B服務(wù)器需要作為另外一個服務(wù)器的主服務(wù)器的時候需要打開。 就是雙主互相備份,或者多主循環(huán)備份。 我們這里需要, 所以打開。
保存, 重啟mysql。
5. 導(dǎo)入初態(tài), 開始同步。
把剛才從A服務(wù)器上導(dǎo)出的 hello.sql 導(dǎo)入到 B的hello數(shù)據(jù)庫中, 如果B現(xiàn)在沒有hello數(shù)據(jù)庫,請先創(chuàng)建一個, 然后再導(dǎo)入:
創(chuàng)建數(shù)據(jù)庫:
mysql> create database hello default charset utf8;
把hello.sql 上傳到B上, 然后導(dǎo)入:
如果你剛才導(dǎo)出了多個數(shù)據(jù)庫, 需要把他們都一一上傳導(dǎo)入。
開啟同步, 在B服務(wù)器上執(zhí)行:
CHANGE MASTER TO MASTER_HOST='192.***.***.***', MASTER_USER='repl_user', MASTER_PASSWORD='hj3****', MASTER_LOG_FILE='mysql-bin.000004', MASTER_LOG_POS=7145;
上面幾個參數(shù)我就不解釋了。 前面說過了。
重啟mysql, 然后查看slave線程開啟了沒:
注意圖中的紅框, 兩個都是Yes, 說明開啟成功。
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
如果其中一個是No, 那就說明不成功。需要查看mysql的錯誤日志。 我在第一次做的時候就遇到這個問題。有時候密碼填錯了, 有時候防火墻的3306沒有打開。ip地址不對,等等。 都會導(dǎo)致失敗。
我們看錯誤日志: mysql的錯誤日志一般在:
文件名應(yīng)該是你的機器名, 我這里叫做host1.err 你換成你自己的。
到這里主-從復(fù)制已經(jīng)打開了。 我們先來實驗一下。
我們在A的數(shù)據(jù)庫里面去 添加數(shù)據(jù):
我在A的 hello數(shù)據(jù)庫的test表中 連續(xù)插入了3條數(shù)據(jù), 注意看他們的自增長id, 分別是1,11,21. 知道這是為什么嗎。 前面已經(jīng)說過了,不懂再回去看。
我們?nèi)タ匆幌翨數(shù)據(jù)庫有沒有這三條數(shù)據(jù):
打開B的數(shù)據(jù)庫:
發(fā)現(xiàn)已經(jīng)在這了。 這里效果不直觀。
此時不要在B中修改數(shù)據(jù)。 我們接著配置從B到A的復(fù)制。 如果你只需要主從復(fù)制的話, 到這里就結(jié)束了。后面可以不看了。 所有A中的修改都能自動同步到B, 但是對B的修改卻不能同步到A。 因為是單向的。 如果需要雙向同步的話,需要再做一次從B到A的復(fù)制。
基本跟上面一樣:我們簡單一點介紹:
2. 打開 /etc/my.cnf , 開啟B的binarylog:
注意紅框中所新添加的部分。
3. 我們不需要導(dǎo)出B的初態(tài)了,因為它剛剛才從A導(dǎo)過來。 直接記住它的master日志狀態(tài):
記住這兩個數(shù)值,等會在A上面要用。
B服務(wù)器就設(shè)置完了。
4. 登錄到A 服務(wù)器。 開啟中繼:
注意框中心添加的部分, 不解釋了。
5. 啟動同步:
上面的ip地址是B的ip地址, 因為A把B當做master了。 不解釋了。
然后重啟mysql服務(wù)。
然后查看,slave狀態(tài)是否正常:
圖中出現(xiàn)了兩個No。
Slave_IO_Running: No
Slave_SQL_Running: No
說明slave沒有成功, 即,從B到A的同步?jīng)]有成功。 我們?nèi)ゲ榭磎ysql錯誤日志,前面說過位置:
找到 機器名.err 文件,打開看看:
看圖中的error信息。 說找不到中繼日志文件。
這是因為我們在配置A的中繼文件時改了中繼文件名,但是mysql沒有同步。解決辦法很簡單。
先停掉mysql服務(wù)。 找到這三個文件,把他們刪掉。 一定要先停掉mysql服務(wù)。不然還是不成功。你需要重啟一下機器了。 或者手動kill mysqld。
好了, 啟動mysql之后。 我們在來檢查一下slave狀態(tài):
注意圖中兩個大大的Yes。 哈哈。
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
證明從B到A的復(fù)制也成功了。
此時我們?nèi)服務(wù)器中插入幾條數(shù)據(jù)試試:
我在B中插入了兩條數(shù)據(jù)。 注意看他們的id。 不解釋。
然后我們,登錄去A中看看,A數(shù)據(jù)庫變了沒。
可以看到已經(jīng)自動同步到A了。
至此, AB雙主互相熱備就介紹完了。
原理其實很簡單,是不是。
理解了這個原理, 多機循環(huán)互備就簡單了。這里就不再展開了。
花了一天時間寫這個博客,大家要頂啊。
歡迎大家訪問我的獨立博客:http://blog.byneil.com 多多交流。
參考:
1. mysql-keepalived-實現(xiàn)雙主熱備讀寫分離
2. MySQL數(shù)據(jù)同步【雙主熱備】http://www.cnblogs.com/zhongweiv/archive/2013/02/01/mysql_replication_circular.html
3. Mysql雙機熱備實現(xiàn)
http://yunnick.iteye.com/blog/1845301
4. 高性能Mysql主從架構(gòu)的復(fù)制原理及配置詳解http://blog.csdn.net/hguisu/article/details/7325124