程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> MySQL主從復制的原理及配置方法(比較詳細)

MySQL主從復制的原理及配置方法(比較詳細)

編輯:MySQL綜合教程

一、復制的原理

MySQL 復制基於主服務器在二進制日志中跟蹤所有對數據庫的更改(更新、刪除等等)。每個從服務器從主服務器接收主服務器已經記錄到其二進制日志的保存的更新,以便從服務器可以對其數據拷貝執行相同的更新。

將主服務器的數據拷貝到從服務器的一個途徑是使用LOAD DATA FROM MASTER語句。請注意LOAD DATA FROM MASTER目前只在所有表使用MyISAM存儲引擎的主服務器上工作。並且,該語句將獲得全局讀鎖定。

MySQL 使用3個線程來執行復制功能,其中1個在主服務器上,另兩個在從服務器上。當發出START SLAVE時,從服務器創建一個I/O線程,以連接主服務器並讓它發送記錄在其二進制日志中的語句。
主服務器創建一個線程將二進制日志中的內容發送到從服務器。該線程可以識別為主服務器上SHOW PROCESSLIST的輸出中的Binlog Dump線程。
從服務器I/O線程讀取主服務器Binlog Dump線程發送的內容並將該數據拷貝到從服務器數據目錄中的本地文件中,即中繼日志。   
第3個線程是SQL線程,是從服務器創建用於讀取中繼日志並執行日志中包含的更新。
有多個從服務器的主服務器創建為每個當前連接的從服務器創建一個線程;每個從服務器有自己的I/O和SQL線程。

二、復制線程的狀態

1.復制主線程的狀態

復制代碼 代碼如下:
Sending binlog event to slave
二進制日志由各種事件組成,一個事件通常為一個更新加一些其它信息。線程已經從二進制日志讀取了一個事件並且正將它發送到從服務器。
Finished reading one binlog; switching to next binlog
線程已經讀完二進制日志文件並且正打開下一個要發送到從服務器的日志文件。
Has sent all binlog to slave; waiting for binlog to be updated
線程已經從二進制日志讀取所有主要的更新並已經發送到了從服務器。線程現在正空閒,等待由主服務器上新的更新導致的出現在二進制日志中的新事件。
Waiting to finalize termination
線程停止時發生的一個很簡單的狀態。

2.復制從I/O線程狀態

復制代碼 代碼如下:Connecting to master
線程正試圖連接主服務器。

Checking master version
建立同主服務器之間的連接後立即臨時出現的狀態。

Registering slave on master
建立同主服務器之間的連接後立即臨時出現的狀態。

Requesting binlog dump
建立同主服務器之間的連接後立即臨時出現的狀態。線程向主服務器發送一條請求,索取從請求的二進制日志文件名和位置開始的二進制日志的內容。

Waiting to reconnect after a failed binlog dump request
如果二進制日志轉儲請求失敗(由於沒有連接),線程進入睡眠狀態,然後定期嘗試重新連接。可以使用–master-connect-retry選項指定重試之間的間隔。

Reconnecting after a failed binlog dump request
線程正嘗試重新連接主服務器。

Waiting for master to send event
線程已經連接上主服務器,正等待二進制日志事件到達。如果主服務器正空閒,會持續較長的時間。如果等待持續slave_read_timeout秒,則發生超時。此時,線程認為連接被中斷並企圖重新連接。

Queueing master event to the relay log
線程已經讀取一個事件,正將它復制到中繼日志供SQL線程來處理。

Waiting to reconnect after a failed master event read
讀取時(由於沒有連接)出現錯誤。線程企圖重新連接前將睡眠master-connect-retry秒。

Reconnecting after a failed master event read
線程正嘗試重新連接主服務器。當連接重新建立後,狀態變為Waiting for master to send event。

Waiting for the slave SQL thread to free enough relay log space
正使用一個非零relay_log_space_limit值,中繼日志已經增長到其組合大小超過該值。I/O線程正等待直到SQL線程處理中繼日志內容並刪除部分中繼日志文件來釋放足夠的空間。

Waiting for slave mutex on exit
線程停止時發生的一個很簡單的狀態。

3.復制從SQL線程狀態

復制代碼 代碼如下:
Reading event from the relay log
線程已經從中繼日志讀取一個事件,可以對事件進行處理了。

Has read all relay log; waiting for the slave I/O thread to update it
線程已經處理了中繼日志文件中的所有事件,現在正等待I/O線程將新事件寫入中繼日志。

Waiting for slave mutex on exit
線程停止時發生的一個很簡單的狀態。

三、復制傳遞和狀態文件

從服務器靠中繼日志來接收從主服務器上傳回來的日志。並依靠狀態文件來記錄已經從主服務器接收了哪些日志,已經恢復了哪些日志。

中繼日志與二進制日志的格式相同,並且可以用mysqlbinlog讀取。SQL線程執行完中繼日志中的所有事件並且不再需要之後,立即自動刪除它。可以采用–relay-log和–relay-log-index服務器選項覆蓋默認中繼日志和索引文件名。其中索引文件名的作用是記錄目前正在使用中繼日志。

在下面的條件下將創建新的中繼日志:
1.每次I/O線程啟動時創建一個新的中繼日志。
2.當日志被刷新時;例如,用FLUSH LOGS或mysqladmin flush-logs。
3.當當前的中繼日志文件變得太大時。“太大”含義的確定方法:
max_relay_log_size,如果max_relay_log_size > 0
max_binlog_size,如果max_relay_log_size = 0
狀態文件名默認為master.info和relay-log.info。其中IO線程更新master.info文件,SQL線程更新relay-log.info文件。
文件中的行和SHOW SLAVE STATUS顯示的列的對應關系為:
master.info文件:
復制代碼 代碼如下:行 描述
1 文件中的行號
2 Master_Log_File
3 Read_Master_Log_Pos
4 Master_Host
5 Master_User
6 密碼(不由SHOW SLAVE STATUS顯示)
7 Master_Port
8 Connect_Retry
9 Master_SSL_Allowed
10 Master_SSL_CA_File
11 Master_SSL_CA_Path
12 Master_SSL_Cert
13 Master_SSL_Cipher
14 Master_SSL_Key

relay-log.info文件:
復制代碼 代碼如下:行 描述
1 Relay_Log_File
2 Relay_Log_Pos
3 Relay_Master_Log_File
4 Exec_Master_Log_Pos

當備份從服務器的數據時,你還應備份這兩個小文件以及中繼日志文件。它們用來在恢復從服務器的數據後繼續進行復制。如果丟失了中繼日志但仍然有 relay-log.info文件,你可以通過檢查該文件來確定SQL線程已經執行的主服務器中二進制日志的程度。然後可以用 Master_Log_File和Master_LOG_POS選項執行CHANGE MASTER TO來告訴從服務器重新從該點讀取二進制日志。當然,要求二進制日志仍然在主服務器上。所以最好建議將自動刪除中繼日志的特性關閉,手工寫shell角本來防止空間滿的問題。

四、復制的配置步驟

1.創建專門用於復制的用戶(建議這樣做),從服務器采用該帳戶登陸主服務器:
復制代碼 代碼如下:
GRANT REPLICATION SLAVE ON *.* TO 'rep'@'%' IDENTIFIED BY 'logzgh' ;


如果你計劃從從屬服務器主機使用LOAD TABLE FROM MASTER或LOAD DATA FROM MASTER語句,你需要授予該賬戶其它權限:

授予賬戶SUPER和RELOAD全局權限。
為所有想要裝載的表授予SELECT權限。任何該 賬戶不能SELECT的主服務器上的表被LOAD DATA FROM MASTER忽略掉。

2.將數據庫文件移到從服務器上

情況一:若只用到MyISAM表
復制代碼 代碼如下:mysql> FLUSH TABLES WITH READ LOCK;
(刷新所有表並且阻止其它寫入,不要退出該客戶端,以保持讀鎖有效。若退出,讀鎖就會釋放。)
比較簡單的辦法就是把數據目錄打包壓縮。

復制代碼 代碼如下:$ tar -cvf /home/mysql/snapshot.tar ./data (在master上)
$ tar -xvf /home/mysql/snapshot.tar (在slave上)

可能不需要同步 mysql 數據庫,因為在slave上的權限表和master不一樣。這時,解開壓縮包的時候要排除它。
同時在壓縮包中也不要包含任何日志文件,和狀態文件master.info、relay-log.info。

復制代碼 代碼如下:mysql> SHOW MASTER STATUS;
+——————+———-+————–+——————+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+——————+———-+————–+——————+
| mysql-bin.000058 | 45036137 | | |
+——————+———-+————–+——————+

mysql> UNLOCK TABLES;

情況二:若用到InnoDB表

方法一:使用InnoDB Hot Backup工具。它無需在master上請求任何鎖就能做到快照的一致性,並且在後面中在slave上要用到的快照中已經記錄了日志文件名以及偏移位置。

方法二:記錄當前日志文件及偏移位置,在master關閉前執行:
復制代碼 代碼如下:mysql> FLUSH TABLES WITH READ LOCK;
mysql> SHOW MASTER STATUS;

盡快記下顯示結果中的日志文件及偏移位置。然後,在不解鎖的情況下關閉master,確保master上的快照和記錄的結果一致。

關閉master服務器,$ mysqladmin -u root shutdown
拷貝 InnoDB 數據文件,日志文件,以及表結構定義文件(.frm文件)。

情況三:可以同時用於MyISAM和InnoDB表
在master上做SQL轉儲而無需如上所述備份二進制日志。運行mysqldump –master-data命令,然後把結果文件轉儲到slave上。
不過,這比拷貝二進制日志慢點。

3.修改my.cnf文件
在master上my.cnf文件:(重啟生效)
復制代碼 代碼如下:[mysqld]
log_bin
server_id=1 (值是 1 到 2^32-1 之間的正整數)
在slave上my.cnf文件:
復制代碼 代碼如下:[mysqld]
server_id=2 (ID必須和master的ID不同。若有多個slave,則每個slave都必須有唯一的id。)

配置slave的擴展選項
復制代碼 代碼如下:master_host=db-master.mycompany.com
master_port=3306
master_user=rep
master_password=freitag
master_connect_retry=60 (若master宕機或者slave連接斷開,slave會定期嘗試連接到master上,重試的間隔由該選項來控制,默認值是60秒。)
report_host=db-slave.mycompany.com
slave_net_timeout=3600 (slave默認會在3600秒後,若還沒收到來自master的數據,則會當作網絡斷開的情況來處理。)

服務器認為master.info的優先級比配置文件my.cnf高,
第一次啟動slave時,master.info不存在,它從my.cnf中讀取選項值,然後把它們保存在master.info中。
下次重啟slave時,它只讀取master.info的內容,而不會讀取my.cnf中的選項值。
想要使用不同的選項值,可以刪除master.info後重啟slave,或者使用CHANGE MASTER TO語句(推薦)重置選項值。

4.啟動從服務器線程

復制代碼 代碼如下:mysqld_safe –user=mysql –skip-slave-start & (啟動MySQL服務器,但不啟動slave)
設置master_log_file等參數
mysql> CHANGE MASTER TO MASTER_HOST='qa-sandbox-1′,
MASTER_USER='rep',
MASTER_PASSWORD='logzgh',
MASTER_LOG_FILE='mysql-bin.000007′,
MASTER_LOG_POS=471632;

mysql> START SLAVE;
執行這些程序後,從服務器應連接主服務器,並補充自從快照以來發生的任何更新。
如果你忘記設置主服務器的server-id值,從服務器不能連接主服務器。

注釋:為了保證事務InnoDB復制設置的最大可能的耐受性和一致性,
應在主服務器的my.cnf文件中使用innodb_flush_log_at_trx_commit=1和sync-binlog=1。
復制代碼 代碼如下:
mysql> show variables; (檢查是否read-only,該選項令slave除了slave線程或者擁有SUPER權限用戶之外的都不能更新數據,確保slave不會接受來自其他客戶端的更新。)
mysql> show processlist; (檢查是否slave-start)

在啟動mysql的同時啟動slave:
復制代碼 代碼如下:mysqld_safe –user=mysql –read-only & (啟動MySQL服務器,同時啟動slave的I/O線程)

mysql> SHOW SLAVE STATUSG;

5.切換slave為master,在slave上:

復制代碼 代碼如下:mysql> STOP SLAVE;
mysql> RESET MASTER;

五.復制啟動選項

–read_only
該選項讓從服務器只允許來自從服務器線程或具有SUPER權限的用戶的更新。可以確保從服務器不接受來自客戶的更新。

–replicate_do_db=db_name
告訴從服務器只做默認數據庫(由USE所選擇)為db_name的語句的復制。要指定多個數據庫,應多次使用該選項,每個數據庫使用一次。請注意不復制跨數據庫的語句

–replicate_do_table=db_name.tbl_name
告訴從服務器線程只做對指定表的復制。要指定多個表,應多次使用該選項,每個表使用一次。同–replicate-do-db對比,允許跨數據庫更新。

–replicate_ignore_db=db_name
告訴從服務器不要復制默認數據庫(由USE所選擇)為db_name的語句。要想忽略多個數據庫,應多次使用該選項,每個數據庫使用一次。

–replicate-ignore-table=db_name.tbl_name
告訴從服務器線程不要復制更新指定表的任何語句(即使該語句可能更新其它的表)。要想忽略多個表,應多次使用該選項,每個表使用一次。

–replicate_wild_do_table=db_name.tbl_name
告訴從服務器線程限制復制更新的表匹配指定的數據庫和表名模式的語句。模式可以包含‘%'和‘_'通配符,與LIKE模式匹配操作符具有相同的含義。要指定多個表,應多次使用該選項,每個表使用一次。該選項可以跨數據庫進行更新。

–replicate_wild_ignore_table=db_name.tbl_name
告訴從服務器線程不要復制表匹配給出的通配符模式的語句。要想忽略多個表,應多次使用該選項,每個表使用一次。該選項可以跨數據庫進行更新。

–replicate_rewrite_db=from_name->to_name
告訴從服務器如果默認數據庫(由USE所選擇)為主服務器上的from_name,則翻譯為to_name。只影響含有表的語句

–report_host=slave_name
從服務器注冊過程中報告給主服務器的主機名或IP地址。該值出現在主服務器上SHOW SLAVE HOSTS的輸出中。如果不想讓從服務器自己在主服務器上注冊,則不設置該值。

–report_port=slave_port
連接從服務器的TCP/IP端口號,從服務器注冊過程中報告給主服務器。

–skip_slave_start
告訴從服務器當服務器啟動時不啟動從服務器線程。使用START SLAVE語句在以後啟動線程。

–slave_skip_errors=[err_code1,err_code2,… | all]
通常情況,當出現錯誤時復制停止,這樣給你一個機會手動解決數據中的不一致性問題。該選項告訴從服務器SQL線程當語句返回任何選項值中所列的錯誤時繼續復制。
例如:
–slave-skip-errors=1062,1053
–slave-skip-errors=all

六、不停機配置復制的方法

方法一:

如果你在某時間點做過主服務器備份並且記錄了相應快照的二進制日志名和偏移量(通過SHOW MASTER STATUS命令的輸出),采用下面的步驟:

1. 確保從服務器分配了一個唯一的服務器ID號。
2. 將備份文件拷到從服務器上。
3. 在從服務器上執行下面的語句,為每個選項填入適當的值:
復制代碼 代碼如下:mysql> CHANGE MASTER TO
-> MASTER_HOST='master_host_name',
-> MASTER_USER='master_user_name',
-> MASTER_PASSWORD='master_pass',
-> MASTER_LOG_FILE='recorded_log_file_name',
-> MASTER_LOG_POS=recorded_log_position;

4.在從服務器上執行START SLAVE語句。

如果你沒有備份主服務器,這裡是一個創建備份的快速程序。所有步驟都應該在主服務器主機上執行。

1. 發出該語句:
復制代碼 代碼如下:mysql> FLUSH TABLES WITH READ LOCK;
2. 仍然加鎖時,執行該命令(或它的變體):
復制代碼 代碼如下:shell> tar zcf /tmp/backup.tar.gz /var/lib/mysql
並拷到從服務器上。
3. 發出該語句並且確保記錄了以後用到的輸出:
復制代碼 代碼如下:mysql>SHOW MASTER STATUS;
4. 釋放鎖:
復制代碼 代碼如下:mysql> UNLOCK TABLES;

方法二:

一個可選擇的方法是,轉儲主服務器的SQL來代替前面步驟中的二進制復制。要這樣做,你可以在主服務器上使用mysqldump –master-data,以後裝載SQL轉儲到到你的從服務器。然而,這比進行二進制復制速度慢。

七、其他

1.不能從使用新二進制日志格式的主服務器向使用舊二進制日志格式的從服務器復制。

2.升級從服務器時,應先關閉從服務器,升級到相應5.1.x版本,然後重啟從服務器並重新開始復制。5.1版本的從服務器能夠讀取升級前寫入的舊的中繼日志並執行日志中包含的語句。升級後從服務器創建的中繼日志為5.1格式。

3.必須在主服務器和從服務器上總是使用相同的全局字符集和校對規則(–default-character-set、–default- collation)。否則,會在從服務器上遇到復制鍵值錯誤,因為在主服務器的字符集中被認為是唯一的鍵值在從服務器的字符集中可能不是唯一的。

4.Q:從服務器需要始終連接到主服務器嗎?
A:不,不需要。從服務器可以宕機或斷開連接幾個小時甚至幾天,重新連接後獲得更新信息。

5.Q:我怎樣知道從服務器與主服務器的最新比較? 換句話說,我怎樣知道從服務器復制的最後一個查詢的日期?
A:你可以查看SHOW SLAVE STATUS語句的Seconds_Behind_Master列的結果。

6. Q:我怎樣強制主服務器阻塞更新直到從服務器同步?
A:使用下面的步驟:
1. 在主服務器上,執行這些語句:
復制代碼 代碼如下:mysql> FLUSH TABLES WITH READ LOCK;
mysql> SHOW MASTER STATUS;
記錄SHOW語句的輸出的日志名和偏移量。這些是復制坐標。

2.在從服務器上,發出下面的語句,其中Master_POS_WAIT()函數的參量是前面步驟中的得到的復制坐標值:
mysql> SELECT MASTER_POS_WAIT('log_name', log_offset);
SELECT語句阻塞直到從服務器達到指定的日志文件和偏移量。此時,從服務器與主服務器同步,語句返回。

3.在主服務器上,發出下面的語句允許主服務器重新開始處理更新:
復制代碼 代碼如下:mysql> UNLOCK TABLES;

7.Q:怎樣通過復制來提高系統的性能?
A:你應將一個服務器設置為主服務器並且將所有寫指向該服務器。然後根據預算配置盡可能多的從服務器以及棧空間,並且在主服務器和從服務器之間分發讀取操作。你也可以用–skip-innodb、–skip-bdb、–low-priority-updates以及–delay-key- write=ALL選項啟動從服務器,以便在從服務器端提高速度。在這種情況下,為了提高速度,從服務器使用非事務MyISAM表來代替InnoDB和 BDB表。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved