一篇比較詳細的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上要用到的快照中已經記錄了日誌文件名以及偏移位置。 ([url]http://www.innodb.com/manual.php[/url])
方法二:記錄當前日誌文件及偏移位置,在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表。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章