MySQL同步功能由3個線程(master上1個,slave上2個)來實現。執行 DE>START SLAVEDE> 語句后,slave就創建一個I/O線程。I/O線程連接到master上,並請求master發送二進制日志中的語句。master創建一個線程來把日志的內容發送到slave上。這個線程在master上執行 DE>SHOW PROCESSLISTDE> 語句后的結果中的 DE>Binlog DumpDE> 線程便是。slave上的I/O線程讀取master的 DE>Binlog DumpDE> 線程發送的語句,並且把它們拷貝到其數據目錄下的中繼日志(relay logs)中。第三個是SQL線程,salve用它來讀取中繼日志,然后執行它們來更新數據。
如上所述,每個master/slave上都有3個線程。每個master上有多個線程,它為每個slave連接都創建一個線程,每個slave只有I/O和SQL線程。
show slave master 用於提供有關從屬服務器線程的關鍵參數的信息
mysql> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.17.2.40
Master_User: photorepl
Master_Port: 4331
Connect_Retry: 60
Master_Log_File: mysql-bin.005502
Read_Master_Log_Pos: 64401238
Relay_Log_File: mysqld-relay-bin.015418
Relay_Log_Pos: 13456757
Relay_Master_Log_File: mysql-bin.005152
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB: mysql
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table: photo.%
Replicate_Wild_Ignore_Table: mysql.%
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 13456620
Relay_Log_Space: 36764898503
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 249904
××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
SHOW SLAVE STATUS會返回以下字段:
? Slave_IO_State
SHOW PROCESSLIST輸出的State字段的拷貝。SHOW PROCESSLIST用於從屬I/O線程。如果線程正在試圖連接到主服務器,正在等待來自主服務器的時間或正在連接到主服務器等,本語句會通知您
? Master_User
被用於連接主服務器的當前用戶。
? Master_Port
當前的主服務器接口。
? Connect_Retry
–master-connect-retry選項的當前值
? Master_Log_File
I/O線程當前正在讀取的主服務器二進制日志文件的名稱。
? Read_Master_Log_Pos
在當前的主服務器二進制日志中,I/O線程已經讀取的位置。
? Relay_Log_File
SQL線程當前正在讀取和執行的中繼日志文件的名稱。
? Relay_Log_Pos
在當前的中繼日志中,SQL線程已讀取和執行的位置。
? Relay_Master_Log_File
由SQL線程執行的包含多數近期事件的主服務器二進制日志文件的名稱。
? Slave_IO_Running
I/O線程是否被啟動並成功地連接到主服務器上。
? Slave_SQL_Running
SQL線程是否被啟動。
? Replicate_Do_DB,Replicate_Ignore_DB
使用–replicate-do-db和–replicate-ignore-db選項指定的數據庫清單。
? Replicate_Do_Table,Replicate_Ignore_Table,Replicate_Wild_Do_Table,Replicate_Wild_Ignore_Table
使用–replicate-do-table,–replicate-ignore-table,–replicate-wild-do-table和–replicate-wild-ignore_table選項指定的表清單。
? Last_Errno,Last_Error
被多數最近被執行的查詢返回的錯誤數量和錯誤消息。錯誤數量為0並且消息為空字符串意味着“沒有錯誤”。如果Last_Error值不是空值,它也會在從屬服務器的錯誤日志中作為消息顯示。
舉例說明:
Last_Errno: 1051
Last_Error: error ‘Unknown table ‘z” on query ‘drop table z’
該消息指示,表z曾經存在於在主服務器中並已被取消了,但是它沒有在從屬服務器中存在過,因此對於從屬服務器,DROP TABLE失敗。(舉例說明,在設置復制時,如果您忘記了把此表拷貝到從屬服務器中,則這有可能發生。)
? Skip_Counter
最近被使用的用於SQL_SLAVE_SKIP_COUNTER的值。
? Exec_Master_Log_Pos
來自主服務器的二進制日志的由SQL線程執行的上一個時間的位置(Relay_Master_Log_File)。在主服務器的二進制日志中的(Relay_Master_Log_File, Exec_Master_Log_Pos)對應於在中繼日志中的(Relay_Log_File,Relay_Log_Pos)。
? Relay_Log_Space
所有原有的中繼日志結合起來的總大小。
? Until_Condition,Until_Log_File,Until_Log_Pos
在START SLAVE語句的UNTIL子句中指定的值。
Until_Condition具有以下值:
o 如果沒有指定UNTIL子句,則沒有值
o 如果從屬服務器正在讀取,直到達到主服務器的二進制日志的給定位置為止,則值為Master
o 如果從屬服務器正在讀取,直到達到其中繼日志的給定位置為止,則值為Relay
Until_Log_File和Until_Log_Pos用於指示日志文件名和位置值。日志文件名和位置值定義了SQL線程在哪個點中止執行。
? Master_SSL_Allowed,Master_SSL_CA_File,Master_SSL_CA_Path,Master_SSL_Cert,Master_SSL_Cipher,Master_SSL_Key
這些字段顯示了被從屬服務器使用的參數。這些參數用於連接主服務器。
Master_SSL_Allowed具有以下值:
o 如果允許對主服務器進行SSL連接,則值為Yes
o 如果不允許對主服務器進行SSL連接,則值為No
o 如果允許SSL連接,但是從屬服務器沒有讓SSL支持被啟用,則值為Ignored。
與SSL有關的字段的值對應於–master-ca,–master-capath,–master-cert,–master-cipher和–master-key選項的值。
? Seconds_Behind_Master
本字段是從屬服務器“落后”多少的一個指示。當從屬SQL線程正在運行時(處理更新),本字段為在主服務器上由此線程執行的最近的一個事件的時間標記開始,已經過的秒數。當此線程被從屬服務器I/O線程趕上,並進入閑置狀態,等待來自I/O線程的更多的事件時,本字段為零。總之,本字段測量從屬服務器SQL線程和從屬服務器I/O線程之間的時間差距,單位以秒計。
如果主服務器和從屬服務器之間的網絡連接較快,則從屬服務器I/O線程會非常接近主服務器,所以本字段能夠十分近似地指示,從屬服務器SQL線程比主服務器落后多少。如果網絡較慢,則這種指示不准確;從屬SQL線程經常會趕上讀取速度較慢地從屬服務器I/O線程,因此,Seconds_Behind_Master經常顯示值為0。即使I/O線程落后於主服務器時,也是如此。換句話說,本列只對速度快的網絡有用。
即使主服務器和從屬服務器不具有相同的時鍾,時間差計算也會起作用(當從屬服務器I/O線程啟動時,計算時間差。並假定從此時以后,時間差保持不變)。如果從屬SQL線程不運行,或者如果從屬服務器I/O線程不運行或未與主服務器連接,則 Seconds_Behind_Master為NULL(意義為“未知”)。舉例說明,如果在重新連接之前,從屬服務器I/O線程休眠了master- connect-retry秒,則顯示NULL,因為從屬服務器不知道主服務器正在做什么,也不能有把握地說落后多少
MySQL復制的概述、安裝、故障、技巧、工具
同MongoDB,Redis這樣的NoSQL數據庫的復制相比,MySQL復制顯得相當復雜!接下來就是詳細的介紹,相信下文中的內容對大家掌握MySQL數據庫的復制是非常有幫助的。
概述
首先主服務器把數據變化記錄到主日志,然后從服務器通過I/O線程讀取主服務器上的主日志,並且把它寫入到從服務器的中繼日志中,接着SQL線程讀取中繼日志,並且在從服務器上重放,從而實現MySQL復制。具體如下圖所示:
MySQL復制
整個過程反映到從服務器上,對應三套日志信息,可在從服務器上用如下命令查看:
mysql> SHOW SLAVE STATUS;
Master_Log_File & Read_Master_Log_Pos:下一個傳輸的主日志信息。
Relay_Master_Log_File & Exec_Master_Log_Pos:下一個執行的主日志信息。
Relay_Log_File & Relay_Log_Pos:下一個執行的中繼日志信息。
理解這些日志信息的含義對於解決故障至關重要,后文會詳細闡述。
安裝
先在主服務器上創建復制賬號:
mysql> GRANT REPLICATION SLAVE ON *.*
TO '<SLAVE_USER>'@'<SLAVE_HOST>'
IDENTIFIED BY '<SLAVE_PASSWORD>';
注:出於安全性和靈活性的考慮,不要把root等具有SUPER權限用戶作為復制賬號。
然后設置主服務器配置文件(缺省:/etc/my.cnf):
[mysqld]
server_id = 100
log_bin = mysql-bin
log_bin_index = mysql-bin.index
sync_binlog = 1
innodb_flush_log_at_trx_commit = 1
innodb_support_xa = 1
注:一定要保證主從服務器各自的server_id唯一,避免沖突。
注:如果沒有指定log_bin的話,缺省會使用主機名作為名字,如此一來一旦主機名發生改變,就會出問題,所以推薦指定log_bin(從服務器的relay_log存在一樣的問題)。
注:sync_binlog,innodb_flush_log_at_trx_commit,innodb_support_xa三個選項都是出於安全目的設置的,不是復制的必須選項。
接着設置從服務器配置文件(缺省:/etc/my.cnf):
[mysqld]
server_id = 200
log_bin = mysql-bin
log_bin_index = mysql-bin.index
relay_log = mysql-relay-bin
relay_log_index = mysql-relay-bin.index
read_only = 1
skip_slave_start = 1
log_slave_updates = 1
注:如果用戶有SUPER權限,則read_only無效。
注:有了skip_slave_start,除非使用START SLAVE命令,否則從服務器不會開始復制。
注:設置log_slave_updates,讓從服務器記錄日志,有助於在必要時把從切換成主。
下面最重要的步驟是如何克隆一份主服務器的數據:
如果數據庫使用的是MyISAM表類型的話,可按如下方式操作:
shell> mysqldump --all-databases --master-data=1 > data.sql
注:master-data選項缺省會打開lock-all-tables,並寫入CHANGE MASTER TO語句。
如果數據庫使用的是InnoDB表類型的話,則應該使用single-transcation:
shell> mysqldump --all-databases --single-transaction --master-data=1 > data.sql
有了數據文件,傳輸到從服務器上並導入:
shell> mysql < data.sql
如果數據量很大的話,mysqldump會非常慢,此時直接拷貝數據文件能節省不少時間:
在拷貝之前要先鎖定數據,然后再獲得相關的日志信息(FILE & POSITION):
mysql> FLUSH TABLES WITH READ LOCK;
mysql> SHOW MASTER STATUS;
接下來拷貝數據文件時,如果是MyISAM表類型的話,直接拷貝即可;如果是InnoDB表類型的話,一定要先停止MySQL服務再拷貝,否則拷貝文件可能無法使用。把拷貝的數據文件直接復制到從服務器的數據目錄。
最后還需要再指定一下日志信息:
mysql> CHANGE MASTER TO
MASTER_HOST='<MASTER_HOST>',
MASTER_USER='<SLAVE_USER>',
MASTER_PASSWORD='<SLAVE_PASSWORD>',
MASTER_LOG_FILE='<FILE>',
MASTER_LOG_POS=<POSITION>;
注:不要在my.cnf配置文件里設置MASTER_USER和MASTER_PASSWORD,因為最終生效的是CHANGE MASTER TO生成的master.info文件里的信息。
在主服務器上直接拷貝數據文件雖然很快,但需要鎖表或者停止服務,這會影響線上服務。如果先前已經有了從服務器,那么可以用舊的從服務器做母本來克隆新的從服務器:
先在舊的從服務器上查詢日志信息:
mysql> SHOW SLAVE STATUS;
我們需要的是其中的Relay_Master_Log_File & Exec_Master_Log_Pos。
然后在舊的從服務器上按照前面的方法得到數據,並在新的從服務器上還原。
接着在新的從服務器上設置日志信息:
mysql> CHANGE MASTER TO
MASTER_HOST='<MASTER_HOST>',
MASTER_USER='<SLAVE_USER>',
MASTER_PASSWORD='<SLAVE_PASSWORD>',
MASTER_LOG_FILE='<Relay_Master_Log_File>',
MASTER_LOG_POS=<Exec_Master_Log_Pos>;
不管用那個方法,最后記得在從服務器上啟動復制,並檢查工作是否正常:
mysql> START SLAVE;
mysql> SHOW SLAVE STATUS;
如果IO線程和SQL線程都顯示Yes,就可以感謝上帝了:
Slave_IO_Running 對應:Master_Log_File & Read_Master_Log_Pos
Slave_SQL_Running 對應:Relay_Master_Log_File & Exec_Master_Log_Pos
如果顯示No,則說明前面某些配置步驟出錯,或者對應的日志文件有問題。
故障
問題:主從復制不止何故停止了,我該怎么辦?
答案:復制錯誤多半是因為日志錯誤引起的,所以首先要搞清楚是主日志錯誤還是中繼日志錯誤,從錯誤信息里一般就能判斷,如果不能可以使用類似下面的mysqlbinlog命令:
shell> mysqlbinlog <MASTER_BINLOG_FILE> > /dev/null
shell> mysqlbinlog <SLAVE_BINLOG_FILE> > /dev/null
如果沒有錯誤,則不會有任何輸出,反之如果有錯誤,則會顯示出來。
如果是主日志錯誤,則需要在從服務器使用SET GLOBAL sql_slave_skip_counter,如下:
mysql> SET GLOBAL sql_slave_skip_counter = 1;
mysql> START SLAVE;
注:如果有多個錯誤,可能需要執行多次(提醒:主從服務器數據可能因此不一致)。
如果是中繼日志錯誤,只要在從服務器使用SHOW SLAVE STATUS結果中的日志信息重新CHANGE MASTER TO即可,系統會拋棄當前的中繼日志,重新下載:
mysql> CHANGE MASTER TO
MASTER_LOG_FILE='<Relay_Master_Log_File>',
MASTER_LOG_POS=<Exec_Master_Log_Pos>;
mysql> START SLAVE;
至於為什么使用的是Relay_Master_Log_File & Exec_Master_Log_Pos,參見概述。
問題:主服務器宕機了,如何把從服務器提升會主服務器?
答案:在一主多從的環境總,需選擇數據最新的從服務器做新的主服務器。如下圖所示:
提升從服務器為主服務器
在一主(Server1)兩從(Server2,、Server3)的環境中,Server1宕機后,等到Server1和Server2把宕機前同步到的日志都執行完,比較Master_Log_File和Read_Master_Log_Pos就可以判斷出誰快誰慢,因為Server2從 Server1同步的數據(1582)比Server3從Server1同步的數據(1493)新,所以應該提升Server2為新的主服務器,那么 Server3在CHANGE MASTER TO到Server2的時候應該使用什么樣的參數呢?1582-1493=89,而Server2的最后的二進制日志位置是8167,所以答案是 8167-89=8078。
技巧
主從服務器中的表可以使用不同的表類型。比如主服務器可以使用InnoDB表類型,提供事務,行鎖等高級特性,從服務器可以使用MyISAM表類型,內存消耗少,易備份等優點。還有一個例子,一台主服務器如果同時帶很多個從服務器的話,勢必會影響其性能,此時可以拿出一台服務器作為從服務器代理,使用BLACKHOLE表類型,只記錄日志,不寫數據,由它帶多台從服務器,從而提升性能。
主從服務器中的表可以使用不同的鍵類型。比如主服務器用InnoDB,鍵用VARCHAR的話節省空間,從服務器使用MyISAM,鍵用CHAR提高速度,因為MyISAM有靜態表一說。
主從服務器中的表可以使用不同的索引。主服務器主要用來應付寫操作,所以除了主鍵和唯一索引等保證數據關系的索引一般都可以不加,從服務器一般用來應付讀操作,所以可以針對查詢特征設置索引,再進一步,不同的從服務器可以針對不同的查詢設置不同的索引。
工具
有一些優秀的工具可以讓你的復制工作得到事半功倍的效果,詳細內容請參考各自文檔:
Multi-Master Replication Manager for MySQL
Percona XtraBackup
Maatkit
Tungsten-replicator