6.5 不同MySQL版本之間的同步相容性
最早的二進位格式是在MySQL 3.23中開發出來的。在MySQL 4.0中改進了,MySQL 5.0又改進了。在配置同步時需要升級伺服器的話,它們之間的因果關係在"6.6 Upgrading a Replication Setup"中描述了。
如果只關心同步,任何MySQL 4.1.x版本和MySQL 4.0.x是一樣的,因為它們都使用相同格式的二進位日誌。所以,這些版本是互相相容的,它們之間可以無縫地運行同步。一個例外的情況是,MySQL 4.0.0到4.0.2由於開發的較早,無法和後來的版本互相相容,所以不要使用它們(它們是4.0版本的alpha系列。它們之間的相容性在發布包的手冊中均有相關文檔)。
下表展示了不同版本的MySQL之間的master/slave同步相容性。
|
|
Master |
Master |
Master |
|
|
3.23.33 and up |
4.0.3 and up or any 4.1.x |
5.0.0 |
Slave |
3.23.33 and up |
yes |
no |
no |
Slave |
4.0.3 and up |
yes |
yes |
no |
Slave |
5.0.0 |
yes |
yes |
yes |
一個通常的規則是,我們建議使用最近的MySQL版本,因為同步相容性一直在改善。我們也建議master和slave都使用同一個版本。
6.6 升級同步
如果升級伺服器時涉及到配置同步,升級設定的步驟跟目前的版本以及升級後的版本不同而異。
6.6.1 升級同步到 4.0 或 4.1
本節適用於從MySQL 3.23升級到4.0或者4.1的情況。4.0的伺服器必須是4.0.3或者更高,"6.5 Replication Compatibility Between MySQL Versions"中提到了。
把master從MySQL 3.23升級到4.0或4.1時,首先要確認這個master的所有slave都已經是4.0或4.1了,否則的話,要先升級slave:挨個關閉,升級,重啟,重啟同步等。
通過以下步驟可以實現安全地升級,假定master要升級到3.23,而slave已經是4.0或4.1了。注意,master升級後,不要重啟使用任何舊的二進位日誌的同步,因為它會干擾到4.0或4.1 slave的同步。
在master上執行 FLUSH TABLES WITH READ LOCK 語句,阻止所有的更新。
等到所有的slave都跟上了master的資料更新。在master上執行 SHOW MASTER STATUS 語句取得二進位日誌以及位移位置。然後,再slave用這些值執行 SELECT MASTER_POS_WAIT() 語句,它會阻止slave上的同步且返回它已經同步的位移位置。然後在slave上執行 STOP SLAVE 語句。
關閉master,將它升級到MySQL 4.0或4.1。
重啟master,記下它的新的二進位檔案名。可以在master上執行 SHOW MASTER STATUS 語句來取得這些資訊。然後在每個slave上都執行如下語句:
mysql> CHANGE MASTER TO MASTER_LOG_FILE='binary_log_name',
-> MASTER_LOG_POS=4;
mysql> START SLAVE;
6.6.2 升級同步到 5.0
本節適用於從MySQL 3.23,4.0或4.1升級到5.0的情況。4.0的伺服器必須是4.0.3或者更高,"6.5 Replication Compatibility Between MySQL Versions"中提到了。
首先,注意到MySQL 5.0還是alpha發布系列。它在各方面都比舊版本好(更容易升級一些同步中重要的會話變數,例如 sql_mode;詳情請看"C.1.3 Changes in release 5.0.0 (22 Dec 2003: Alpha")。不過,它還沒經過廣泛測試。由於是alpha版本,我們不建議用於任何生產環境(現在已經可以用於生產了,譯者注)。
把master從MySQL 3.23,4.0或4.1升級到5.0.0時,首先要確認這個master的所有slave都已經是5.0.0了,否則的話,要先升級slave:挨個關閉,升級,重啟,重啟同步等。5.0.0的slave可以讀取升級前寫入的執行語句的中繼日誌。升級完後的slave建立的中繼日誌就是5.0格式了。
當所有的slave都升級完了,關閉master,升級到5.0.0,然後重啟。5.0.0的master也可以讀取舊格式的二進位日誌。slave能識別舊的格式並且合理處理它們。master上建立的二進位日誌都是5.0.0格式的。slave也能識別這格式。
換言之,在升級到5.0.0時無需特殊的規定,除非在升級master到5.0.0之前slave必須使用舊版本的。注意,把5.0.0降級到舊版本中不能自動地做了:必須確保所有的5.0.0格式二進位日誌和中繼日誌都已經處理完了,然後才能把它們刪除完成降級。
6.7 同步特性及已知問題
以下列出了同步支援什麼,不支援什麼。附加的 InnoDB 特殊相關的資訊以及同步請看"16.7.5 InnoDB and MySQL Replication"。
AUTO_INCREMENT, LAST_INSERT_ID(), 和 TIMESTAMP 的值都能被正常同步。
USER(), UUID(), 和 LOAD_FILE() 函數都完完全全地同步到slave,因此可能不大可靠。MySQL 4.1.1以前的版本中的 CONNECTION_ID() 函數也是如此。從MySQL 4.1.1及更高以後,新的 PASSWORD() 函數可以正常同步,當然了,slave必須是4.1.1或更高或者不同步它。如果有舊版本的slave必須要同步 PASSWORD() 函數,那麼master啟動時必須增加 --old-password 選項,這樣在master上就用舊的方法來實現 PASSWORD() 了(注意,MySQL 4.1.0的 PASSWORD() 函數實現跟其他的版本都不同,最好不要同步4.1.0)。
從MySQL 4.0.14開始同步 FOREIGN_KEY_CHECKS 變數。從5.0.0開始同步 sql_mode, UNIQUE_CHECKS,和 SQL_AUTO_IS_NULL 變數。 SQL_SELECT_LIMIT 和 table_type 變數目前還不能被同步。
現在討論使用不同字元集的MySQL伺服器間同步的問題。
首先,在master和slave上必須總是使用同樣的全域字元集以及校正字元集(--default-character-set, --default-collation 都是相關的全域變數)。否則,slave上可能會出現鍵重複(duplicate-key)的錯誤,因為用master的字元集認為該鍵可能是唯一的,但是用slave的字元集則未必然。
第二,如果master必須低於MySQL 4.1.3,則會話(session)的字元集必須和全域值一樣(也就是說,不能執行 SET NAMES, SET CHARACTER SET 等語句),因為這些對字元集的修改在slave不能識別。如果master是4.1.3或者更高,slave也是這樣的話,那麼會話字元集就可以隨便修改了(執行 NAMES, CHARACTER SET, COLLATION_CLIENT, COLLATION_SERVER 等),並且這些修改都會被記錄到二進位日誌中,然後同步到slave上,它就知道怎麼做了。該會話還會阻止試圖修改這些全域變數的操作;就如前面所說,master和slave必須使用同樣的全域字元集。
如果在master上有和全域變數 collation_server 不一樣字元集的資料庫,那麼就要設計 CREATE TABLE 語句使得資料表不隱式地使用該資料庫的預設字元集,因為這目前還是一個bug(Bug #2326);一個變通的辦法是在 CREATE TABLE 語句中顯式地聲明資料表的字元集以及校正字元集。
有時可能會把master上的事務表同步到slave後變成非事務表。例如,可以在slave上把master的 InnoDB 表當成 MyISAM 表。不過,slave在一個 BEGIN/COMMIT 區塊中停止的話就有問題了,因為slave會從 BEGIN 重新開始。這個問題已經放到TODO中,很快會被修複。
更新語句中如果用到了使用者自訂變數(例如變數 @var_name)的情況下,在MySQL 3.23和4.0不能被正確同步。在 4.1 這已經修複了。注意,從MySQL 5.0開始,使用者變數就不區分大小寫了。在做MySQL 5.0和舊版本間的同步需要考慮到這個問題。
從4.1.1以及更高版本中,slave可以用SSL方式串連到master。
在master上執行的 CREATE TABLE 語句如果包括了 DATA DIRECTORY或 INDEX DIRECTORY 子句,那麼它也會應用於slave上。如果slave上不存在對應的目錄或者沒有許可權時便出現問題。從MySQL 4.0.15開始,有個 sql_mode 選項叫 NO_DIR_IN_CREATE。如果slave的SQL模式包含這個選項,那麼它在同步 CREATE TABLE 語句前會忽略前面提到的2個子句。結果就是 MyISAM 的資料和索引檔案都只能放在該表的資料庫目錄下。
儘管沒聽說過發生過類似的情況,不過理論上確實存在這種可能性:如果一個查詢被設計為非確定方式的修改資料,那麼可能導致master和slave的資料不一致。那麼,就把決定的權力交給查詢最佳化工具吧。(通常這不是一個好的做法,甚至超出了同步的範圍,詳情請看"1.8.7.3 Open Bugs and Design Deficiencies in MySQL")
在MySQL 4.1.1之前,FLUSH, ANALYZE TABLE, OPTIMIZE TABLE,和 REPAIR TABLE 語句沒有寫入到二進位日誌中,因此也不會同步到slave上。這通常不會引發問題,因為它們並沒有修改資料。不過在特定情況下可能導致問題。如果同步 mysql 資料庫下的許可權表,在更新時不是用 GRANT 語句,那麼必須在slave上執行那麼必須在slave上執行 FLUSH PRIVILEGES 語句才能使之生效。同樣地,如果還有一個 MyISAM 表是 MERGE 表的一部分,那麼必須在slave上手工執行 FLUSH TABLES 語句。從MySQL 4.1.1開始,這些語句都寫入二進位日誌了(除非指定選項 NO_WRITE_TO_BINLOG 或它的同名選項 LOCAL)。一些例外的情況是 FLUSH LOGS, FLUSH SLAVE, 和 FLUSH TABLES WITH READ LOCK (它們中的任何一個同步到slave的話都可能導致問題)。例子可見"14.5.4.2 FLUSH Syntax"。
MySQL只支援一個master多個slave的機制。以後我們會增加一個表決演算法,如果當前master出現問題時能自動切換。同時也會引進一個"代理"進程來協助將 SELECT 查詢發送到不同的slave上達到負載平衡。
當伺服器關閉,重啟後,所有的 MEMORY (HEAP) 表都清空了。從MySQL 4.0.18開始,master用以下方式同步它們:一旦master開始使用一個 MEMORY 表,它會在用完這些表之後在二進位日誌中寫入一個 DELETE FROM 語句告訴slave把它們刪除。詳情請看"15.3 The MEMORY (HEAP) Storage Engine"。
除非關閉slave(只是關閉slave線程),暫存資料表也會同步;並且在slave上已經記錄了一些還未被執行的需要用到暫存資料表的更新語句。關閉slave再重啟後更新所需的暫存資料表就不複存在了。為了避免這個問題,在有暫存資料表時就不要關閉slave。或者,使用以下步驟:
提交一個 STOP SLAVE 語句。 使用 SHOW STATUS 語句檢查變數 Slave_open_temp_tables 的值。 如果它的值是0,運行 mysqladmin shutdown 命令關閉slave。 如果它的值不是0,用 START SLAVE 語句重啟slave線程。 如果還有這樣的好運氣就再次執行同樣的步驟吧。^_^ 我們會儘快解決這個問題。 如果在一個迴圈master/slave同步關係中指定 --log-slave-updates 選項,那麼就可以安全地串連到各個伺服器上。注意,很多語句可能在這種設定環境下不能正常工作,除非程式中已經特別注意避免這種更新時潛在的問題了,因為可能在不同伺服器上不同的順序上發生更新問題。這意味著可以設定像下面的迴圈: A -> B -> C -> A 伺服器ID都已經編碼到二進位日誌中了,因此伺服器A知道那些自己建立的日誌,從而不會去執行它們(除非在伺服器A上啟動時增加 --replicate-same-server-id 選項,這個選項只在極少數情況下設定有意義)。因此,這就不會存在無限迴圈了。不過這個迴圈只有在更新表時沒有發生衝突才不會發生問題。換言之,如果在A和C中同時插入一條記錄,那麼可能在A中不可能插入資料,因為它的鍵可能跟C的鍵衝突了。同樣地,也不能在兩個伺服器上更新同一條記錄,除非2次更新操作間有足夠的時間間隔。 如果在slave上執行一個SQL語句後產生錯誤,那麼slave的SQL線程就終止,然後它在錯誤記錄檔中寫入一條資訊。可以串連到slave上,解決問題(例如,不存在表)後,運行 START SLAVE 語句重啟它。 可以放心地關閉master(乾淨地)之後再重啟它。如果slave到master的串連斷開了,它會立刻重連。如果失敗了,slave會定期重試(預設是每60秒重試一次,可通過 --master-connect-retry 選項來修改)。slave也會處理網路斷開的情況。不過,slave會在 slave_net_timeout 秒之後如果還沒收到來自master的資料才會當作網路斷開的情況來處理。如果斷開時間不長,可以減少 slave_net_timeout 的值。詳情請看"5.2.3 Server System Variables"。 也可以放心地關閉slave(乾淨地),它會記錄停止的地方。不乾淨地關閉slave可能產生問題,特別是系統關閉了但緩衝還沒重新整理到磁碟時。可以提供不斷電供應系統來提高系統容錯性。master的不乾淨關閉可能導致表和二進位內容的不一致;如果是 InnoDB 表,使用 --innodb-safe-binlog 選項在master上就能避免這個問題。詳情請看"5.9.4 The Binary Log"。 由於 MyISAM 表的非事務本質,就可能發生一個語句只更新了部分表就返回錯誤碼的情況。例如,一個多重插入語句中,有一條記錄違反了約束鍵規則,一個更新語句在更新了一些記錄後輩殺掉了。如果在master上發生這種情況了,那麼slave線程會推出,等待資料庫管理員決定要怎麼做,除非這個錯誤碼是合法的並且這個語句的執行結果也是一樣的錯誤碼。並沒有關於錯誤碼是否合法的詳細描述,一些錯誤碼可以用 --slave-skip-errors 選項屏蔽掉。這個選項從MySQL 3.23.47開始就可以用了。 如果把非事務表同步到事務表時在一個 BEGIN/COMMIT 段內更新資料表了,如果在非事務表提交之前有其他線程更新它了,那麼這個更新操作就不會正確地同步到二進位日誌中。這是因為只有整個事務成功提交了才會寫到二進位日誌中。 在4.0.15之前,任何在非事務表的更新操作會在它執行的時候立刻寫入到二進位日誌中,然而事務表的更新只有在 COMMIT 後才寫入,ROLLBACK 的話就不寫入了。因此在一些事務中更新事務表或非事務表時就需要考慮這個情況了(不只是同步時會碰到這個問題,想要把二進位日誌作為備份時也一樣)。在MySQL 4.0.15中,我們已經修改了更新事務和非事務表混合的情況下的日誌記錄行為,它解決了這個問題(對於二進位日誌來說順序地記錄語句是比較不錯的做法,所有必須的語句都會寫進去,ROLLBACK 也一樣)。當第二個串連更新非事務表而第一個串連的事務還沒結束時,就會有同樣的問題了;仍會發記錄語句順序發生錯誤的問題,因為第二個串連會在更新完成後立刻寫入到日誌中。 當4.x的slave從3.23的master上同步 LOAD DATA INFILE 時,SHOW SLAVE STATUS 中的 Exec_Master_Log_Pos 和 Relay_Log_Space 欄位的值就不正確了。Exec_Master_Log_Pos 值不正確的話在重啟slave之後會導致問題;因此最好在重啟前修改一下這個值,只需在master上運行 FLUSH LOGS。這個bug在MySQL 5.0.0的slave中已經解決了。 下表列出了MySQL 3.23同步時會發生的問題,它們在MySQL 4.0已經解決了: LOAD DATA INFILE 能正確處理,只要那個資料檔案在更新開始時仍然存在於master上。 LOAD DATA LOCAL INFILE 不再像以前3.23那樣被略過了。 在3.23中,RAND() 更新同步不正常。因此在使用 RAND() 更新時採用 RAND(some_non_rand_expr) 格式。例如,可以用 UNIX_TIMESTAMP() 作為 RAND() 的參數。 |
引用:
http://database.ccidnet.com/art/1105/20060814/803053_1.html
http://database.ccidnet.com/art/1105/20060814/803053_2.html
http://database.ccidnet.com/art/1105/20060814/803053_3.html