MySQL手冊版本 5.0.20-MySQL同步

日期:2006-09-23  作者:喜騰小二  來源:PHPChina


6 MySQL 同步

同步功能在MySQL
3.23.15就開始引進了,它可以把一個MySQL服務器上的數據復制到另一個服務器上去。本章描述了MySQL的各種復制特性。介紹了同步的概念,如何設置同步服務器,以及可用服務器的參照。還提供了一繫列的常見問題及其答案,疑難解答。

"14.6 Replication Statements"中介紹了同步相關的SQL語句語法。

我們建議經常訪問"http://www.mysql.com"經常閱讀本章的最新內容。同步功能一直在改進,我們經常把這部分的手冊更新到當前的最新內容。

6.1 同步介紹

MySQL
3.23.15及更高的版本支持單嚮同步。一個服務器作為master(主服務器),一個或者多個服務器作為slave(從服務器)。master服務器把更新的內容寫到二進制日誌(binary
log或binlog)中,並且維護了一個索引文件來記錄日誌循環的情況。這些日誌中的更新部分會被發送到slave服務器。一個slave連接到master之後,它通知master最後一次成功增量更新的日誌位置。slave會找出所有從那個時刻開始的更新操作,然後阻塞並等待master發送新的更新操作。

如果想要做一個同步服務器鏈的話,slave同時也可以作為master。

注意,啓用同步後,所有要同步的更新操作都必須在master上執行。否則,必須注意不要造成用戶在master上的更新和在slave上的更新引起衝突。

單嚮同步的好處是穩健,高速,繫統易管理:

有了master/slave機制後,就更穩健了。當master上發生問題時,可以把slave作為備用切換過去。

可以在slave和master之間分擔一些查詢,這就能加速響應時間。SELECT
查詢就可以在slave上執行以減少master的負載。更新數據的語句則要放在mater上執行以保持master和slave的同步。當非更新操作占多數時,負載均衡就很有效了,不過這隻是普通情況而言。

另一個好處是可以在slave上備份數據,無需乾擾master。備份數據時master照樣繼續運作。詳情請看"5.7.1
Database Backups"。

6.2 同步機制實現概述

MySQL同步機制基於master把所有對數據庫的更新、刪除
等)都記錄在二進制日誌裡。因此,想要啓用同步機制,在master就必須啓用二進制日誌。詳情請看"5.9.4 The Binary Log"。

每個slave接受來自master上在二進制日誌中記錄的更新操作,因此在slave上執行了這個操作的一個拷貝。

應該非常重要地意識到,二進制日誌隻是從啓用二進制日誌開始的時刻才記錄更新操作的。所有的slave必須在啓用二進制日誌時把master上已經存在的數據拷貝過來。如果運行同步時slave上的數據和master上啓用二進制日誌時的數據不一緻的話,那麼slave同步就會失敗。

把master上的數據拷貝過來的方法之一實在slave上執行 LOAD DATA FROM MASTER
語句。不過要注意,LOAD DATA FROM MASTER 是從MySQL 4.0.0之後才開始可以用的,而且隻支持master上的 MyISAM
類型表。同樣地,這個操作需要一個全局的讀鎖,這樣的話傳送日誌到slave的時候在master上就不會有更新操作了。當實現了自由鎖表熱備份時(在MySQL
5.0中),全局讀鎖就沒必要了。

由於有這些限制,因此我們建議隻在master上相關數據比較小的時候才執行 LOAD DATA FROM
MASTER 語句,或者在master上允許一個長時間的讀鎖。由於每個繫統之間 LOAD DATA FROM MASTER
的速度各不一樣,一個比較好的衡量規則是每秒能拷貝1MB數據。這隻是的粗略的估計,不過master和slave都是奔騰700MHz的機器且用100MBit/s網絡連接時就能達到這個速度了。

slave上已經完整拷貝master數據後,就可以連接到master上然後等待處理更新了。如果master當機或者slave連接斷開,slave會定期嘗試連接到master上直到能重連並且等待更新。重試的時間間隔由
--master-connect-retry 選項來控制,它的默認值是60秒。

每個slave都記錄了它關閉時的日誌位置。msater是不知道有多少個slave連接上來或者哪個slave從什麼時候開始更新。

6.3 同步實現細節

MySQL同步功能由3個線程(master上1個,slave上2個)來實現。執行 START SLAVE
語句後,slave就創建一個I/O線程。I/O線程連接到master上,並請求master發送二進制日誌中的語句。master創建一個線程來把日誌的內容發送到slave上。這個線程在master上執行
SHOW PROCESSLIST 語句後的結果中的 Binlog Dump 線程便是。slave上的I/O線程讀取master的 Binlog Dump
線程發送的語句,並且把它們拷貝到其數據目錄下的中繼日誌(relay logs)中。第三個是SQL線程,salve用它來讀取中繼日誌,然後執行它們來更新數據。

如上所述,每個mster/slave上都有3個線程。每個master上有多個線程,它為每個slave連接都創建一個線程,每個slave隻有I/O和SQL線程。

在MySQL
4.0.2以前,同步隻需2個線程(master和slave各一個)。slave上的I/O和SQL線程合並成一個了,它不使用中繼日誌。

slave上使用2個線程的優點是,把讀日誌和執行分開成2個獨立的任務。執行任務如果慢的話,讀日誌任務不會跟着慢下來。例如,如果slave停止了一段時間,那麼I/O線程可以在slave啓動後很快地從master上讀取全部日誌,盡管SQL線程可能落後I/O線程好幾的小時。如果slave在SQL線程沒全部執行完就停止了,但I/O線程卻已經把所有的更新日誌都讀取並且保存在本地的中繼日誌中了,因此在slave再次啓動後就會繼續執行它們了。這就允許在master上清除二進制日誌,因為slave已經無需去master讀取更新日誌了。

執行 SHOW PROCESSLIST 語句就會告訴我們所關心的master和slave上發生的情況。

下例說明了 SHOW PROCESSLIST 結果中的3個線程是什麼樣的。這是在MySQL
4.0.15及更新上執行 SHOW PROCESSLIST 的結果,State 字段的內容已經比舊版本顯示的更有意義了。

在master上,SHOW PROCESSLIST 的結果如下:

mysql> SHOW PROCESSLISTG

*************************** 1. row
***************************

Id: 2

User: root

Host: localhost:32931

db: NULL

Command: Binlog Dump

Time: 94

State: Has sent all binlog to slave; waiting for
binlog to

be updated

Info: NULL

在這裡,線程2是為一個slave連接創建的。結果表明所有未完成的更新日誌已經都發送到slave了,master正等待新的更新日誌發生。

在slave上,SHOW PROCESSLIST 的結果如下:

mysql> SHOW PROCESSLISTG

*************************** 1. row
***************************

Id: 10

User: system user

Host:

db: NULL

Command: Connect

Time: 11

State: Waiting for master to send event

Info: NULL

*************************** 2. row
***************************

Id: 11

User: system user

Host:

db: NULL

Command: Connect

Time: 11

State: Has read all relay log; waiting for the slave
I/O

thread to update it

Info: NULL

這表明線程10是I/O線程,它正連接到master上;線程11是SQL線程,它執行中繼日誌中的更新操作。現在,這2個線程都處於空閒狀態,正等待新的更新日誌。

注意,Time 字段的值告訴我們slave上的日誌比master晚了多久。詳情請看"6.9
Replication FAQ"。

6.3.1 Master 同步線程狀態

以下列出了master的 Binlog Dump 線程 State
字段中最常見的幾種狀態。如果在master上沒有 Binlog Dump 線程,那麼同步就沒有在運行。也就是說,沒有slave連接上來。

Sending binlog event to slave

事件是由二進制日誌構成,一個事件通常由更新語句加上其他信息。線程讀取到一個事件並正發送到slave上。

Finished reading one binlog; switching to next
binlog

讀取完了一個二進制日誌,正切換到下一個。

Has sent all binlog to slave; waiting for binlog to
be updated

已經讀取完全部未完成更新日誌,並且全部都發送到slave了。它處於空閒狀態,正等待在master上執行新的更新操作以在二進制日誌中產生新的事件,然後讀取它們。

Waiting to finalize termination

當前線程停止了,這個時間很短。

6.3.2 Slave的I/O線程狀態

以下列出了slave的I/O線程 State 字段中最常見的幾種狀態。從MySQL
4.1.1開始,這個狀態在執行 SHOW SLAVE STATUS 語句結果的 Slave_IO_State 字段也會出現。這意味着可以隻執行 SHOW
SLAVE STATUS 語句就能了解到更多的信息。

Connecting to master

該線程證嘗試連接到master上。

Checking master version

確定連接到master後出現的一個短暫的狀態。

Registering slave on master

確定連接到master後出現的一個短暫的狀態。

Requesting binlog dump

確定連接到master後出現的一個短暫的狀態。該線程嚮master發送一個請求,告訴它要請求的二進制文件以及開始位置。

Waiting to reconnect after a failed binlog dump
request

如果二進制日誌轉儲(binary log
dump)請求失敗了(由於連接斷開),該線程在休眠時進入這個狀態,並定期重連。重連的時間間隔由 --master-connect-retry 選項來指定。

Reconnecting after a failed binlog dump request

該線程正嘗試重連到master。

Waiting for master to send event

已經連接到master,正等待它發送二進制日誌。如果master閒置時,這個狀態可能會持續較長時間,如果它等待超過
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

正嘗試重連到master。當連接確定後,狀態就變成 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

當前線程停止了,這個時間很短。

6.3.3 Slave的SQL線程狀態

以下列出了slave的SQL線程 State 字段中最常見的幾種狀態:

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

當前線程停止了,這個時間很短。

SQL線程的 State
字段有時候也可能是一個SQL語句。這意味着它從中繼日誌中讀取到一個事件了,從中提取出SQL語句,並執行它。

6.3.4 中繼日誌及狀態文件

默認地,中繼日誌的名字格式為 `host_name-relay-bin.nnn`,host_name
是服務器的主機名,nnn 是序號。中繼日誌是根據順序的序號來創建的,從 000001 (MySQL 4.0 及更舊是
001)開始。slave上用一個索引文件來跟蹤當前正在使用的中繼日誌。默認的中繼日誌索引文件名是
`host_name-relay-bin.index`。默認地,這個文件位於slave的數據文件目錄下。默認文件名可以根據的繫統選項 --relay-log 和
--relay-log-index 來替換。詳情請看"6.8 Replication Startup Options"。

中繼日誌和二進制日誌的格式一樣,因此也可以用 mysqlbinlog
來讀取。當SQL線程讀取完中繼日誌中的全部事件後就不再需要它了,會自動刪除它。中繼日誌沒有顯式的刪除機制,因為SQL線程會自動關注這個。不過,從MySQL
4.0.14開始,執行 FLUSH LOGS 的話就會輪轉(rotate)中繼日誌,會讓SQL線程刪除它們。

在下列條件中會創建一個新的中繼日誌:

slave啓動後,I/O線程第一次啓動(在MySQL
5.0中,每次I/O線程啓動後都會新建一個中繼日誌,而不隻是第一次啓動時)。

刷新日誌時;例如,執行 FLUSH LOGS 語句或運行 mysqladmin flush-logs
命令(從 MySQL 4.0.14開始才會創建新中繼日誌)。

當前的中繼日誌大小太大了;"太大了"是這麼判斷的:

max_relay_log_size, 如果 max_relay_log_size > 0 的話

max_binlog_size, 如果 max_relay_log_size = 0 或 MySQL
低於 4.0.14

slave會在數據文件目錄下創建兩個額外的文件。它們是狀態文件,名字默認為 `master.info`
and `relay-log.info`。它們的內容跟執行 SHOW SLAVE STATUS 語句的結果類似。詳情請看"14.6.2 SQL
Statements for Controlling Slave
Servers"。由於是磁盤上的文件,它們在slave關閉後還會留着。下一次slave啓動時,就會讀取這兩個文件來判斷從master讀取到二進制日誌的什麼位置了,處理中繼日誌到什麼位置了。

`master.info` 文件由來I/O線程更新。在MySQL 4.1以前,文件的內容和執行 SHOW
SLAVE STATUS 語句結果中相對應的字段值一樣,如下:

LineDescription
1 Master_Log_File
2 Read_Master_Log_Pos
3 Master_Host
4 Master_User
5 Password (not shown by SHOW SLAVE STATUS)
6 Master_Port
7 Connect_Retry

從MySQL 4.1開始,文件內容還包括了SSL選項:

Line Description

LineDescription
1 Number of lines in the file
2 Master_Log_File
3 Read_Master_Log_Pos
4 Master_Host
5 Master_User
6 Password (not shown by 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` 文件由SQL線程來更新。文件的內容和執行 SHOW SLAVE
STATUS 語句結果中相對應的字段值一樣:

LineDescription
1 Relay_Log_File
2 Relay_Log_Pos
3 Relay_Master_Log_File
4 Exec_Master_Log_Pos

備份slave數據時,要把這兩個文件也備份起來,和中繼日誌一道。想要恢復slave時就用得到它們了。如果丟失了中繼日誌,但是
`relay-log.info` 文件還存在,那麼就可以判斷出SQL線程執行了多少master二進制日誌。然後執行 CHANGE MASTER TO 語句,帶上
MASTER_LOG_FILE 和 MASTER_LOG_POS
選項告訴slave要從master的二進制日誌哪個位置重新讀取。當然了,這要求master上相關的二進制日誌都還留着。

如果slav打算同步 LOAD DATA INFILE 語句,那麼也要備份對應目錄下的任何
`SQL_LOAD-*` 文件。這可以在 LOAD DATA INFILE 被中斷後繼續保持同步。這個目錄由 --slave-load-tmpdir
選項來指定。默認地,如果沒有指定的話,它的值就是變量 tmpdir 的值。

<<<返回技術中心

技術文章

站內新聞

我要啦免费统计