<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ### 第6章:MySQL中的復制 ** 目錄** [ 6.1. 復制介紹](#)[ 6.2. 復制實施概述](#)[ 6.3. 復制實施細節](#)[ 6.3.1. 復制主線程狀態](#)[ 6.3.2. 復制從I/O線程狀態](#)[ 6.3.3. 復制從SQL線程狀態](#)[ 6.3.4. 復制傳遞和狀態文件](#)[ 6.4. 如何設置復制](#)[ 6.5. 不同MySQL版本之間的復制兼容性](#)[ 6.6. 升級復制設置](#)[ 6.6.1. 將復制升級到5.0版](#)[ 6.7. 復制特性和已知問題](#)[ 6.8. 復制啟動選項](#)[ 6.9. 復制FAQ](#)[ 6.10. 復制故障診斷與排除](#)[ 6.11. 通報復制缺陷](#)[ 6.12. 多服務器復制中的Auto-Increment](#) 本章描述了MySQL提供的各種復制特性。引入了復制概念,顯示如何設置復制服務器和服務以指導相應的復制選項。還提供了FAQ(以及答案) 列表,以及解決復制問題的排錯建議。 關于復制相關的SQL語句的語法描述,參見[13.6節,“復制語句”](# "13.6.?Replication Statements")。 我們建議你經常訪問我們的網址[http://www.mysql.com](http://www.mysql.com),并檢查對本章的修改。復制在不斷地得到改進,我們用最新的信息定期更新本手冊。 ### 6.1.?復制介紹 MySQL支持單向、異步復制,復制過程中一個服務器充當主服務器,而一個或多個其它服務器充當從服務器。(這與*同步*復制可以進行對比,*同步*復制是MySQL簇的一個特征—參見[第17章:](#)[*MySQL簇*](# "Chapter?17.?MySQL Cluster"))。主服務器將更新寫入二進制日志文件,并維護文件的一個索引以跟蹤日志循環。這些日志可以記錄發送到從服務器的更新。當一個從服務器連接主服務器時,它通知主服務器從服務器在日志中讀取的最后一次成功更新的位置。從服務器接收從那時起發生的任何更新,然后封鎖并等待主服務器通知新的更新。 如果你想要設置鏈式復制服務器,從服務器本身也可以充當主服務器。 請注意當你進行復制時,所有對復制中的表的更新必須在主服務器上進行。否則,你必須要小心,以避免用戶對主服務器上的表進行的更新與對從服務器上的表所進行的更新之間的沖突。 單向復制有利于健壯性、速度和系統管理: ·???????? 主服務器/從服務器設置增加了健壯性。主服務器出現問題時,你可以切換到從服務器作為備份。 ·???????? 通過在主服務器和從服務器之間切分處理客戶查詢的負荷,可以得到更好的客戶響應時間。SELECT查詢可以發送到從服務器以降低主服務器的查詢處理負荷。但修改數據的語句仍然應發送到主服務器,以便主服務器和從服務器保持同步。如果非更新查詢為主,該負載均衡策略很有效,但一般是更新查詢。 ·???????? 使用復制的另一個好處是可以使用一個從服務器執行備份,而不會干擾主服務器。在備份過程中主服務器可以繼續處理更新。參見[5.9.1節,“數據庫備份”](# "5.9.1.?Database Backups")。 ### 6.2.?復制實施概述 MySQL復制基于主服務器在二進制日志中跟蹤所有對數據庫的更改(更新、刪除等等)。因此,要進行復制,必須在主服務器上啟用二進制日志。參見[5.11.3節,“二進制日志”](# "5.11.3.?The Binary Log")。 每個從服務器從主服務器接收主服務器已經記錄到其二進制日志的保存的更新,以便從服務器可以對其數據拷貝執行相同的更新。 認識到二進制日志只是一個從啟用二進制日志的固定時間點開始的記錄*非常*重要。任何設置的從服務器需要主服務器上的*在主服務器上啟用二進制日志時的*數據庫拷貝。如果啟動從服務器時,其數據庫與主服務器上的啟動二進制日志時的狀態不相同,從服務器很可能失敗。 將主服務器的數據拷貝到從服務器的一個途徑是使用LOAD DATA FROM MASTER語句。請注意LOAD DATA FROM MASTER目前只在所有表使用MyISAM存儲引擎的主服務器上工作。并且,該語句將獲得全局讀鎖定,因此當表正復制到從服務器上時,不可能在主服務器上進行更新。當我們執行表的無鎖熱備份時,則不再需要全局讀鎖定。 由于這些限制,我們建議只有主服務器上的數據集相對較小,或者主服務器上延遲讀鎖定已經被接受,才可以使用LOAD DATA FROM MASTER。而LOAD DATA FROM MASTER的實際速度隨系統的不同而不同,對于執行時間,最好的規則是每1MB的數據用1秒鐘。這是一個粗略的估計,但你會發現如果主服務器和從服務器的性能上等價于700MHz Pentium CPU,通過100Mbps的網絡進行連接,則該估計相當準確。 從服務器設置為復制主服務器的數據后,它連接主服務器并等待更新過程。如果主服務器失敗,或者從服務器失去與主服務器之間的連接,從服務器保持定期嘗試連接,直到它能夠繼續幀聽更新。由--master-connect-retry選項控制重試間隔。 默認為60秒。 每個從服務器跟蹤復制時間。主服務器不知道有多少個從服務器或在某一時刻有哪些被更新了。 ### 6.3.?復制實施細節 [ 6.3.1. 復制主線程狀態](#)[ 6.3.2. 復制從I/O線程狀態](#)[ 6.3.3. 復制從SQL線程狀態](#)[ 6.3.4. 復制傳遞和狀態文件](#) MySQL使用3個線程來執行復制功能(其中1個在主服務器上,另兩個在從服務器上。當發出START SLAVE時,從服務器創建一個I/O線程,以連接主服務器并讓它發送記錄在其二進制日志中的語句。主服務器創建一個線程將二進制日志中的內容發送到從服務器。該線程可以識別為主服務器上SHOW PROCESSLIST的輸出中的Binlog Dump線程。從服務器I/O線程讀取主服務器Binlog Dump線程發送的內容并將該數據拷貝到從服務器數據目錄中的本地文件中,即*中繼日志*。第3個線程是SQL線程,是從服務器創建用于讀取中繼日志并執行日志中包含的更新。 在前面的描述中,每個從服務器有3個線程。有多個從服務器的主服務器創建為每個當前連接的從服務器創建一個線程;每個從服務器有自己的I/O和SQL線程。 這樣讀取和執行語句被分成兩個獨立的任務。如果語句執行較慢則語句讀取任務沒有慢下來。例如,如果從服務器有一段時間沒有運行了,當從服務器啟動時,其I/O線程可以很快地從主服務器索取所有二進制日志內容,即使SQL線程遠遠滯后。如果從服務器在SQL線程執行完所有索取的語句前停止,I/O 線程至少已經索取了所有內容,以便語句的安全拷貝保存到本地從服務器的中繼日志中,供從服務器下次啟動時執行。這樣允許清空主服務器上的二進制日志,因為不再需要等候從服務器來索取其內容。 SHOW PROCESSLIST語句可以提供在主服務器上和從服務器上發生的關于復制的信息。 下面的例子說明了這3個線程在SHOW PROCESSLIST中的顯示。 在主服務器上,SHOW PROCESSLIST的輸出看上去應為: ~~~ mysql> SHOW PROCESSLIST\G ~~~ ~~~ *************************** 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是一個連接從服務器的復制線程。該信息表示所有主要更新已經被發送到從服務器,主服務器正等待更多的更新出現。 在從服務器上,SHOW PROCESSLIST的輸出看上去應為: ~~~ mysql> SHOW PROCESSLIST\G ~~~ ~~~ *************************** 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線程,線程11是處理保存在中繼日志中的更新的SQL線程。SHOW PROCESSLIST運行時,兩個線程均空閑,等待其它更新。 請注意Time列的值可以顯示從服務器比主服務器滯后多長時間。參見[6.9節,“復制FAQ”](# "6.9.?Replication FAQ")。 ### 6.3.1.?復制主線程狀態 下面列出了主服務器的Binlog Dump線程的State列的最常見的狀態。如果你沒有在主服務器上看見任何Binlog Dump線程,這說明復制沒有在運行—即,目前沒有連接任何從服務器。 ·???????? 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 線程停止時發生的一個很簡單的狀態。 ### 6.3.2.?復制從I/O線程狀態 下面列出了從服務器的I/O線程的State列的最常見的狀態。該狀態也出現在Slave_IO_State列,由SHOW SLAVE STATUS顯示。這說明你可以只通過該語句仔細瀏覽所發生的事情。 ·???????? 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 線程停止時發生的一個很簡單的狀態。 ### 6.3.3.?復制從SQL線程狀態 下面列出了從服務器的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 線程停止時發生的一個很簡單的狀態。 I/O線程的State列也可以顯示語句的文本。這說明線程已經從中繼日志讀取了一個事件,從中提取了語句,并且正在執行語句。 ### 6.3.4.?復制傳遞和狀態文件 默認情況,中繼日志使用*host_name-relay-bin.nnnnnn*形式的文件名,其中*host_name*是從服務器主機名,*nnnnnn*是序列號。用連續序列號來創建連續中繼日志文件,從000001開始。從服務器跟蹤索引文件中目前正使用的中繼日志。 默認中繼日志索引文件名為*host_name-relay-bin.index*。默認情況,在從服務器的數據目錄中創建這些文件。可以用--relay-log和--relay-log-index服務器選項覆蓋 默認文件名。參見[6.8節,“復制啟動選項”](# "6.8.?Replication Startup Options")。 中繼日志與二進制日志的格式相同,并且可以用**mysqlbinlog**讀取。SQL線程執行完中繼日志中的所有事件并且不再需要之后,立即自動刪除它。沒有直接的刪除中繼日志的機制,因為SQL線程可以負責完成。然而,FLUSH LOGS可以循環中繼日志,當SQL線程刪除日志時會有影響。 在下面的條件下創建新的中繼日志: ·???????? 每次I/O線程啟動時創建一個新的中繼日志。 ·???????? 當日志被刷新時;例如,用FLUSH LOGS或**mysqladmin flush-logs**。 ·???????? 當當前的中繼日志文件變得太大時。“太大”含義的確定方法: o??????? max_relay_log_size,如果max_relay_log_size > 0 o??????? max_binlog_size,如果max_relay_log_size = 0 從屬復制服務器在數據目錄中另外創建兩個小文件。這些*狀態文件*默認名為主master.info和relay-log.info。它們包含SHOW SLAVE STATUS語句的輸出所顯示的信息(關于該語句的描述參見[13.6.2節,“用于控制從服務器的SQL語句”](# "13.6.2.?SQL Statements for Controlling Slave Servers"))。狀態文件保存在硬盤上,從服務器關閉時不會丟失。下次從服務器啟動時,讀取這些文件以確定它已經從主服務器讀取了多少二進制日志,以及處理自己的中繼日志的程度。 由I/O線程更新master.info文件。文件中的行和SHOW SLAVE STATUS顯示的列的對應關系為: <table border="1" cellpadding="0" id="table1"><tr><td> <p><strong><span>行</span></strong></p></td> <td> <p><strong><span>描述</span></strong></p></td> </tr><tr><td> <p><span>1</span></p></td> <td> <p>文件中的行號</p></td> </tr><tr><td> <p><span>2</span></p></td> <td> <p> <span>Master_Log_File</span></p></td> </tr><tr><td> <p><span>3</span></p></td> <td> <p> <span> Read_Master_Log_Pos</span></p></td> </tr><tr><td> <p><span>4</span></p></td> <td> <p> <span>Master_Host</span></p></td> </tr><tr><td> <p><span>5</span></p></td> <td> <p> <span>Master_User</span></p></td> </tr><tr><td> <p><span>6</span></p></td> <td> <p>密碼<span>(</span>不由<span>SHOW SLAVE STATUS</span>顯示<span>)</span></p></td> </tr><tr><td> <p><span>7</span></p></td> <td> <p> <span>Master_Port</span></p></td> </tr><tr><td> <p><span>8</span></p></td> <td> <p> <span>Connect_Retry</span></p></td> </tr><tr><td> <p><span>9</span></p></td> <td> <p> <span> Master_SSL_Allowed</span></p></td> </tr><tr><td> <p><span>10</span></p></td> <td> <p> <span> Master_SSL_CA_File</span></p></td> </tr><tr><td> <p><span>11</span></p></td> <td> <p> <span> Master_SSL_CA_Path</span></p></td> </tr><tr><td> <p><span>12</span></p></td> <td> <p> <span>Master_SSL_Cert</span></p></td> </tr><tr><td> <p><span>13</span></p></td> <td> <p> <span> Master_SSL_Cipher</span></p></td> </tr><tr><td> <p><span>14</span></p></td> <td> <p> <span>Master_SSL_Key</span></p></td> </tr></table> 由SQL線程更新relay-log.info文件。文件中的行和SHOW SLAVE STATUS顯示的列的對應關系為: <table border="1" cellpadding="0" id="table2"><tr><td> <p><strong><span>行</span></strong></p></td> <td> <p><strong><span>描述</span></strong></p></td> </tr><tr><td> <p><span>1</span></p></td> <td> <p> <span>Relay_Log_File</span></p></td> </tr><tr><td> <p><span>2</span></p></td> <td> <p> <span>Relay_Log_Pos</span></p></td> </tr><tr><td> <p><span>3</span></p></td> <td> <p> <span> Relay_Master_Log_File</span></p></td> </tr><tr><td> <p><span>4</span></p></td> <td> <p> <span> Exec_Master_Log_Pos</span></p></td> </tr></table> 當備份從服務器的數據時,你還應備份這兩個小文件以及中繼日志文件。它們用來在恢復從服務器的數據后繼續進行復制。如果丟失了中繼日志但仍然有relay-log.info文件,你可以通過檢查該文件來確定SQL線程已經執行的主服務器中二進制日志的程度。然后可以用Master_Log_File和Master_LOG_POS選項執行CHANGE MASTER TO來告訴從服務器重新從該點讀取二進制日志。當然,要求二進制日志仍然在主服務器上。 如果從服務器正復制LOAD DATA INFILE語句,你應也備份該目錄內從服務器用于該目的的任何SQL_LOAD-*文件。從服務器需要這些文件繼續復制任何中斷的LOAD DATA INFILE操作。用--slave-load-tmpdir選項來指定目錄的位置。如果未指定, 默認值為tmpdir變量的值。 ### 6.4.?如何設置復制 這里簡單描述了如何為你當前的MySQL服務器設置完整的復制。假設你想要復制主服務器上的所有數據庫,并且還沒有配置的復制。你需要關閉主服務器來完成下面所列的步驟。 下面的程序針對設置一個從服務器,你可以用來設置多個從服務器。 雖然該方法是設置從服務器的最直接的途徑,它并不是唯一的一個。例如,如果你有一個主服務器的數據快照,并且主服務器已經設置了服務器ID,啟用了二進制日志,不需要關閉主服務器或停止對它的更新也可以設置從服務器。詳情請參見[6.9節,“復制FAQ”](# "6.9.?Replication FAQ")。 如果想要管理MySQL復制設置,我們建議你通讀本章,并嘗試[13.6.1節,“用于控制主服務器的SQL語句”](# "13.6.1.?SQL Statements for Controlling Master Servers")和[13.6.2節,“用于控制從服務器的SQL語句”](# "13.6.2.?SQL Statements for Controlling Slave Servers")中的所有語句。還應熟悉[6.8節,“復制啟動選項”](# "6.8.?Replication Startup Options")中描述的復制啟動選項。 **注釋:**該程序和后面章節所示的復制SQL語句需要SUPER權限。 1.??? 確保在服務器和從服務器上安裝的MySQL版本與[6.5節,“不同MySQL版本之間的復制兼容性”](# "6.5.?Replication Compatibility Between MySQL Versions")所示的表兼容。理想情況,應在主服務器和從服務器上使用最近版本的MySQL。 請先證實問題不是出現在最新的MySQL版本中再通報bug。 2.??? 在主服務器上為服務器設置一個連接賬戶。該賬戶必須授予REPLICATION SLAVE權限。如果賬戶僅用于復制(推薦這樣做),則不需要再授予任何其它權限。(關于設置用戶 賬戶和權限的信息,參見[5.8節,“MySQL用戶賬戶管理”](# "5.8.?MySQL User Account Management"))。 假定你的域為mydomain.com,想要創建用戶名為repl的一個賬戶,從服務器可以使用該賬戶從你的域內的任何主機使用密碼slavepass來訪問主服務器。要創建該 賬戶,可使用GRANT語句: ~~~ mysql> GRANT REPLICATION SLAVE ON *.* ~~~ ~~~ ??? -> TO 'repl'@'%.mydomain.com' IDENTIFIED BY 'slavepass'; ~~~ 如果你計劃從從屬服務器主機使用LOAD TABLE FROM MASTER或LOAD DATA FROM MASTER語句,你需要授予該賬戶其它權限: ·???????? 授予賬戶SUPER和RELOAD全局權限。 ·???????? 為所有想要裝載的表授予SELECT權限。任何該 賬戶不能SELECT的主服務器上的表被LOAD DATA FROM MASTER忽略掉。 3.??? 執行FLUSH TABLES WITH READ LOCK語句清空所有表和塊寫入語句: ~~~ 4.??????????? mysql> FLUSH TABLES WITH READ LOCK; ~~~ 對于InnoDB表,請注意:FLUSH TABLES WITH READ LOCK還鎖定COMMIT操作。當獲得全局讀鎖定后,可以開始InnoDB表的文件系統快照。快照不能保證內部(在InnoDB存儲引擎內部)一致性(因為InnoDB緩存沒有刷新),但并不需要關心該問題,因為InnoDB可以在啟動時解決該問題并給出一致的結果。這說明InnoDB在啟動快照時可以進行崩潰恢復,而不會破壞。然而,當保證一致的InnoDB表快照時,還沒有途徑來停止MySQL服務器。 讓客戶程序保持運行,發出FLUSH TABLES語句讓讀鎖定保持有效。(如果退出客戶程序,鎖被釋放)。然后對主服務器上的數據進行快照。 創建快照最簡單的途徑是使用歸檔程序對主服務器上的數據目錄中的數據庫進行二進制備份。例如,在Unix中使用**tar**,或者在Windows中使用**PowerArchiver、WinRAR**、**WinZip**或者類似的軟件。要使用**tar**來創建包括所有數據庫的歸檔文件,進入主服務器的數據目錄,然后執行命令: ~~~ shell> tar -cvf /tmp/mysql-snapshot.tar . ~~~ 如果你想讓歸檔只包括this_db數據庫,應使用命令: ~~~ shell> tar -cvf /tmp/mysql-snapshot.tar ./this_db ~~~ 然后將歸檔文件復制到從服務器主機的/tmp目錄。在該機器上,進入從服務器的數據目錄,并使用下述命令解壓縮歸檔文件: ~~~ shell> tar -xvf /tmp/mysql-snapshot.tar ~~~ 如果從服務器的用戶賬戶與主服務器的不同,你可能不想復制mysql數據庫。在這種情況下,應從歸檔中排除該數據庫。你也不需要在歸檔中包括任何日志文件或者master.info或relay-log.info文件。 當FLUSH TABLES WITH READ LOCK所置讀鎖定有效時,讀取主服務器上當前的二進制日志名和偏移量值: ~~~ mysql > SHOW MASTER STATUS; ~~~ ~~~ +---------------+----------+--------------+------------------+ ~~~ ~~~ | File????????? | Position | Binlog_Do_DB | Binlog_Ignore_DB | ~~~ ~~~ +---------------+----------+--------------+------------------+ ~~~ ~~~ | mysql-bin.003 | 73?????? | test???????? | manual,mysql???? | ~~~ ~~~ +---------------+----------+--------------+------------------+ ~~~ File列顯示日志名,而Position顯示偏移量。在該例子中,二進制日志值為mysql-bin.003,偏移量為73。記錄該值。以后設置從服務器時需要使用這些值。它們表示復制坐標,從服務器應從該點開始從主服務器上進行新的更新。 取得快照并記錄日志名和偏移量后,可以在主服務器上重新啟用寫活動: ~~~ mysql> UNLOCK TABLES; ~~~ 如果你正使用InnoDB表,理想情況應使用**InnoDB Hot Backup**工具,使用該工具可以獲得一致的快照而不需要在主服務器上進行鎖定,并且可以對應從服務器上使用的快照來記錄日志名和偏移量。**Hot Backup**是一個附加的非免費(商業)工具,沒有包含在標準 MySQL分發中。詳細信息參見[http://www.innodb.com/manual.php](http://www.innodb.com/manual.php)的**InnoDB Hot Backup**主頁。 不使用**Hot Backup**工具,最快捷的途徑是使用InnoDB表的二進制快照來關閉主服務器并復制InnoDB數據文件、日志文件和表定義文件(.frm文件)。要記錄當前的日志文件名和偏移量,關閉服務器之前應發出下面的語句: ~~~ mysql> FLUSH TABLES WITH READ LOCK; ~~~ ~~~ mysql> SHOW MASTER STATUS; ~~~ 然后記錄前面所示的SHOW MASTER STATUS的輸出中顯示的日志名和偏移量。記錄日志名和偏移量后,*不*解鎖表關閉服務器以確保? 服務器關閉時的快照與當前的日志文件和偏移量相對應: ~~~ shell> mysqladmin -u root shutdown ~~~ 適合MyISAM和InnoDB表的另一個方法是對主服務器上的SQL進行轉儲而不是對前面討論的二進制復制進行轉儲。為了實現,可以在主服務器上使用**mysqldump --master-data**,以后將SQL轉儲文件裝入從服務器。但是,這樣比二進制復制要慢一些。 如果主服務器運行時沒有啟用--logs-bin,SHOW MASTER STATUS或**mysqldump --master-data**顯示的日志名和位置值為空。在這種情況下,當以后指定從服務器的日志文件和位置時需要使用的值為空字符串('')和4. 5.??? 確保主服務器主機上my.cnf文件的[mysqld]部分包括一個log-bin選項。該部分還應有一個server-id=Master_id選項,其中master_id必須為1到232–1之間的一個正整數值。例如: ~~~ 6.??????????? [mysqld] ~~~ ~~~ 7.??????????? log-bin=mysql-bin ~~~ ~~~ 8.??????????? server-id=1 ~~~ 如果沒有提供那些選項,應添加它們并重啟服務器。 9.??? 停止用于從服務器的服務器并在其my.cnf文件中添加下面的行: ~~~ 10.??????? [mysqld] ~~~ ~~~ 11.??????? server-id=slave_id ~~~ slave_id值同Master_id值一樣,必須為1到232–1之間的一個正整數值。并且,從服務器的ID必須與主服務器的ID不相同。例如: ~~~ [mysqld] ~~~ ~~~ server-id=2 ~~~ 如果設置多個從服務器,每個從服務器必須有一個唯一的server-id值,必須與主服務器的以及其它從服務器的不相同。可以認為server-id值類似于IP地址:這些ID值能唯一識別復制服務器群集中的每個服務器實例。 如果不指定一個server-id值,如果沒有定義master-host,則將它設置為1;否則設置為2。請注意如果server-id太長,主服務器 拒絕所有來自從服務器的連接,并且從服務器拒絕連接到主服務器。這樣,省略server-id只適合用二進制日志備份。 12.如果對主服務器的數據進行二進制備份,啟動從服務器之前將它復制到從服務器的數據目錄中。確保對這些文件和目錄的權限正確。服務器 MySQL運行的用戶必須能夠讀寫文件,如同在主服務器上一樣。 如果使用**mysqldum**備份,先啟動從服務器(看下一步)。 13.啟動從服務器。如果前面已經復制了,用--skip-slave-start選項啟動從服務器,以便它不立即嘗試連接主服務器。你也可能想要用--logs-warnings選項啟動從服務器(默認設置啟用),以便在錯誤日志中顯示更多的問題相關的信息(例如,網絡或連接問題)。放棄的連接將記入錯誤日志,除非其值大于1。 14.如果使用**mysqldump**備份主服務器的數據,將轉儲文件裝載到從服務器: ~~~ 15.??????? shell> mysql -u root -p < dump_file.sql ~~~ ~~~ 16.??????? 在從服務器上執行下面的語句,用你的系統的實際值替換選項值: ~~~ ~~~ 17.??????? mysql> CHANGE MASTER TO ~~~ ~~~ 18.??????? ????->???? MASTER_HOST='master_host_name', ~~~ ~~~ 19.??????? ????->???? MASTER_USER='replication_user_name', ~~~ ~~~ 20.??????? ????->???? MASTER_PASSWORD='replication_password', ~~~ ~~~ 21.??????? ????->???? MASTER_LOG_FILE='recorded_log_file_name', ~~~ ~~~ 22.??????? ????->???? MASTER_LOG_POS=recorded_log_position; ~~~ 下面的表顯示了字符串選項的最大長度: <table border="1" cellpadding="0" id="table3"><tr><td> <p> <span>Master_Host</span></p></td> <td> <p><span>60</span></p></td> </tr><tr><td> <p> <span>Master_USER</span></p></td> <td> <p><span>16</span></p></td> </tr><tr><td> <p> <span>Master_PASSWORD</span></p></td> <td> <p><span>32</span></p></td> </tr><tr><td> <p> <span>Master_Log_File</span></p></td> <td> <p><span>255</span></p></td> </tr></table> 23.啟動從服務器線程: ~~~ 24.??????? mysql> START SLAVE; ~~~ 執行這些程序后,從服務器應連接主服務器,并補充自從快照以來發生的任何更新。 如果你忘記設置主服務器的server-id值,從服務器不能連接主服務器。 如果你忘記設置從服務器的server-id值,在從服務器的錯誤日志中會出現下面的錯誤: ~~~ Warning: You should set server-id to a non-0 value if master_host is set; ~~~ ~~~ we will force server id to 2, but this MySQL server will not act as a slave. ~~~ 如果由于其它原因不能復制,從服務器的錯誤日志中也會出現錯誤消息。 從服務器復制時,會在其數據目錄中發現文件dmaster.info和relay-log.info。從服務器使用這兩個文件跟蹤已經處理了多少主服務器的二進制日志。不要移除或編輯這些文件,除非你確切知你正在做什么并完全理解其意義。即使這樣,最好是使用CHANGE MASTER TO語句。 **注釋:**master.info**的**內容會覆蓋命令行或in my.cnf中指定的部分選項。詳情參見[6.8節,“復制啟動選項”](# "6.8.?Replication Startup Options")。 有了一個快照,你可以用它根據剛剛描述的從服務器部分來設置其它從服務器。你不需要主服務器的另一個快照;每個從服務器可以使用相同的快照。 注釋:為了保證事務InnoDB復制設置的最大可能的耐受性和一致性,應在主服務器的my.cnf文件中使用innodb_flush_log_at_trx_commit=1和sync-binlog=1。 ### 6.5.?不同MySQL版本之間的復制兼容性 MySQL 5.1中使用的二進制日志格式與以前的版本中所使用的大大不同,特別是在字符集處理、LOAD DATA INFILE以及時區方面。 **注釋:**你不能從使用新二進制日志格式的主服務器向使用舊二進制日志格式的從服務器復制(例如,從MySQL 5.0到MySQL 4.1)。。這樣操作在復制設置升級服務器時后果嚴重,參見[6.6節,“升級復制設置”](# "6.6.?Upgrading a Replication Setup")。 我們推薦使用最近的MySQL版本,因為復制功能在不斷地改進中。我們還推薦主服務器和從服務器使用相同的版本。我們建議升級主服務器和從服務器,運行alpha或beta版本到新的(產品)版本。在許多情況下,從新的主服務器向舊的從服務器復制將會失敗。一般原則,運行MySQL 5.1.x的從服務器可以與舊的主服務器(可以運行MySQL 3.23、4.0或者4.1)一起使用,但不能反過來。 前面的信息適合協議級復制兼容性。然而,還會有一個約束條件,例如SQL級兼容性問題。例如, 5.1版本的主服務器不能復制到5.0版本的從服務器,如果復制語句使用5.1版本的SQL特性而不是5.0版本。這些問題和其它問題均在[6.7節,“復制特性和已知問題”](# "6.7.?Replication Features and Known Problems")中討論。 ### 6.6.?升級復制設置 [ 6.6.1. 將復制升級到5.0版](#) 當在復制設置中升級服務器時,升級過程取決于當前的服務器版本和要升級的服務器版本。 ### 6.6.1.?將復制升級到5.0版 該節適用于將復制從MySQL 3.23、4.0或者4.1升級到5.1。4.0服務器應為4.0.3或更新版。 當將早期MySQL版本系列主服務器升級到5.1時,應先確保該主服務器的所有從服務器使用了相同的5.1.x版本。如果不是這樣,你應先升級從服務器。升級從服務器時,應先關閉從服務器,升級到相應5.1.x版本,然后重啟從服務器并重新開始復制。5.1版本的從服務器能夠讀取升級前寫入的舊的中繼日志并執行日志中包含的語句。升級后從服務器創建的中繼日志為5.1格式。 從服務器升級后,關閉主服務器,將它升級到與從服務器相同的5.1.x版本并重啟它。5.1主服務器能夠讀取升級前寫入的舊的二進制日志并將它們發送到5.1從服務器。從服務器可以識別舊的格式并正確處理它。升級后主服務器創建的二進制日志采用5.1格式。這樣也可以由5.1從服務器識別。 換句話說,當升級到5.1時沒有什么措施,只有將主服務器升級到5.1之前先將從服務器升級到5.1。請注意從5.1降級到舊版本不會如此簡單:必須確保已經完全處理所有5.1版本的二進制日志或中繼日志,以便在降級前可以移除它們。 ### 6.7.?復制特性和已知問題 一般原則,SQL級復制兼容性要求主服務器和從服務器均支持使用的特性。例如,在MySQL 5.0.0中開始使用TIMESTAMPADD()函數。如果在主服務器上使用該函數,不能復制到MySQL 5.0.0之前的從服務器。如果你計劃在5.1和以前版本的MySQL之間進行復制,你應查閱對應以前版本系列的MySQL參考手冊,查詢該系列復制特征相關信息。 下面列出了關于支持什么和不支持什么的詳細信息。關于復制的其它InnoDB具體信息參見[15.2.6.5節,“InnoDB和MySQL復制”](# "15.2.6.5.?InnoDB and MySQL Replication")。 關于保存的程序和觸發器的復制問題在[20.4節,“存儲子程序和觸發程序的二進制日志功能”](# "20.4.?Binary Logging of Stored Routines and Triggers")中討論。 ·???????? 用AUTO_INCREMENT、LAST_INSERT_ID()和TIMESTAMP值正確實現復制。 ·???????? USER()、UUID()和LOAD_FILE()函數毫無改變地被,這樣不能可靠地在從服務器上工作。 ·???????? * 下面的限制只適合基于語句的復制,而不是基于行的復制。*處理用戶級鎖定的函數GET_LOCK()、RELEASE_LOCK()、IS_FREE_LOCK()、IS_USED_LOCK()復制時從服務器不知道在主服務器上同時進行的相關文本;因此如果從服務器上的內容不同,這些函數不用來插入到主服務器的表中(例如不執行INSERT INTO mytable VALUES(GET_LOCK(...)))。 ·???????? 在MySQL 5.1中FOREIGN_KEY_CHECKS、SQL_MODE、UNIQUE_CHECKS和SQL_AUTO_IS_NULL變量均復制。但TABLE_TYPE,即STORAGE_ENGINE變量 不復制,有利于在不同的存儲引擎之間進行復制。 ·???????? 即使主服務器和從服務器有不同的全局字符集變量,以及即使有不同的全局時區變量仍可以復制。 ·???????? 下面適合使用不同字符集的MySQL服務器之間的復制: 1.??? 必須在主服務器和從服務器上**總是**使用相同的**全局**字符集和校對規則(--default-character-set、--default-collation)。否則,會在從服務器上遇到復制鍵值錯誤,因為在主服務器的字符集中被認為是唯一的鍵值在從服務器的字符集中可能不是唯一的。 2.??? 如果主服務器早于MySQL 4.1.3,則會話中的字符集不應與其全局值不同(換句話說,不要使用SET NAMES、SET CHARACTER SET等等),因為從服務器不知道該字符集的更改。如果主服務器和從服務器均為4.1.3或更新版,可以隨便將會話的字符集變量設置為本地值(例如NAMES、CHARACTER SET、COLLATION_CLIENT和COLLATION_SERVER),因為這些設定值被寫入二進制日志,因此從服務器知道。然而,禁止更改會話中這些變量的**全局**值;如前面所述,主服務器和從服務器必須具有唯一的全局字符集值。 3.??? 如果在主服務器上的數據庫的字符集與全局collation_server值不同,則應設計CREATE TABLE語句,以便它們不隱含依賴數據庫的默認字符集([Bug #2326](http://bugs.mysql.com/2326));一個好的解決辦法是在CREATE TABLE中明顯說明字符集和校對規則。 ·???????? 應在主服務器和從服務器上設置相同的系統時區。否則一些語句,例如使用NOW()或FROM_UNIXTIME()函數的語句,將不會正確復制。可以使用腳本mysqld_safe的--timezone=*timezone_name*選項或通過設置TZ環境變量設置MySQL服務器運行的系統的時區。主服務器和從服務器還應有相同的默認連接時區設置;即主服務器和從服務器應有相同的--default-time-zone參數值。 ·???????? CONVERT_TZ(...,...,@global.time_zone)不能正確復制。只有主服務器和從服務器均為5.0.4或更新版才能正確復制CONVERT_TZ(...,...,@session.time_zone)。 ·???????? 會話變量只有在更新表的語句中使用時才能正確復制;例如:SET MAX_JOIN_SIZE=1000;INSERT INTO mytable VALUES(@MAX_JOIN_SIZE)不能將相同的數據插入到主服務器上和從服務器上。不適用于通用的SET TIME_ZONE=...;INSERT INTO mytable VALUES(CONVERT_TZ(...,...,@time_zone))。 ·???????? 可以將從服務器上的非事務表復為主服務器上的事務表。例如,可以將主服務器上的InnoDB表復制為從服務器上的MyISAM表。然而,復制過程中,如果從服務器在BEGIN/COMMIT塊過程中停止則會產生問題,因為從服務器在BEGIN塊開始時會重啟。該問題出現在TODO中,不久將會得到修復。 ·???????? 在MySQL 5.1中可以正確復制引用用戶變量(即@*var_name*形式的變量)的更新語句;但在4.1以前的版本中卻不可能。請注意從MySQL 5.1開始對用戶變量名的大小寫不再敏感;當在5.1和舊版本之間設置復制時應考慮該問題。 ·???????? 從服務器可以使用SSL連接到主服務器。 ·???????? 有一個全局系統變量slave_transaction_retries:如果因為某個InnoDB死鎖或超過 InnoDB的innodb_lock_wait_timeout或NDB簇的TransactionDeadlockDetectionTimeout或TransactionInactiveTimeout,REPLICATION SLAVESQL線程未能執行某個事務,在給出錯誤停止前自動重試slave_transaction_retries次。 默認值是10。從MySQL 5.0.4開始,可以從SHOW STATUS的輸出中看到重試總次數;參見[5.3.4節,“服務器狀態變量”](# "5.3.4.?Server Status Variables")。 ·???????? 如果在主服務器上的CREATE TABLE語句中使用了DATA DIRECTORY或INDEX DIRECTORY子句,子句也可以在從服務器上使用。如果在從服務器主機文件系統中不存在一致的目錄或雖然存在但不能被從服務器訪問,則會帶來問題。MySQL 5.1支持一個稱為NO_DIR_IN_CREATE的sql_mode選項。如果從服務器運行時將SQL模式設置為包括該選項,復制CREATE TABLE語句時將忽略這些子句。結果是在表的數據庫目錄中創建了MyISAM數據和索引文件。 ·???????? *下面的限制只適合**基于**語句的復制,而不是基于行的復制*:如果在查詢中數據修改不確定,主服務器和從服務器上的數據可以不同;也就是由查詢優化器確定。(這是常用的但不是很好的習慣,即使不是在復制中也不好)。關于該問題的詳細解釋,參見[A.8.1節,“MySQL中的打開事宜”](# "A.8.1.?Open Issues in MySQL")。 ·???????? 帶READ LOCK的FLUSH LOGS、FLUSH MASTER、FLUSH SLAVE和FLUSH TABLES不記入日志,因為如果復制到從服務器會造成問題。關于語法示例,參見[13.5.5.2節,“FLUSH語法”](# "13.5.5.2.?FLUSH Syntax")。FLUSH TABLES、ANALYZE TABLE、OPTIMIZE TABLE和REPAIR TABLE語句被寫入二進制日志并會復制到從服務器。一般情況不會造成問題,因為這些語句不修改表的數據。但是在某些情況下會帶來問題。如果你復制mysql數據庫中的授權表并且不使用GRANT直接更新那些表,必須在從服務器上執行FLUSH PRIVILEGES使新的權限生效。并且,如果使用FLUSH TABLES重新命名MERGE表的MyISAM表,必須手動在從服務器上執行FLUSH TABLES。如果不指定NO_WRITE_TO_BINLOG或其別名LOCAL,則這些語句被寫入二進制日志。 ·???????? MySQL只支持一個主服務器和多個從服務器。我們計劃將來添加一個投票算法,當前的主服務器出現問題時自動切換。我們還計劃引入代理過程通過向不同的從服務器發送SELECT查詢以幫助進行負載均衡。 ·???????? 當服務器關閉、重啟時,其MEMORY表將變為空。主服務器按下述方法復制該結果:啟動后第1次主服務器使用每個MEMORY表,它通知從服務器需要向表寫入DELETE FROM語句來清空二進制日志的表。詳細信息參見[15.4節,“MEMORY (HEAP)存儲引擎”](# "15.4.?The MEMORY (HEAP) Storage Engine")。 ·???????? 除了關閉從服務器(而不僅僅是從服務器線程) 臨時表都被復制,并且還沒有在從服務器上執行的更新所使用的臨時表也已經復制。如果關閉從服務器,從服務器重啟后更新需要的那些臨時表不可再用。為了避免該問題,臨時表打開時不要關閉從服務器。而應遵照下面的程序: 1.??? 執行STOP SLAVE語句。 2.??? 使用SHOW STATUS檢查slave_open_temp_tables變量的值。 3.??? 如果值為0,使用**mysqladmin shutdown**命令關閉從服務器。 4.??? 如果值不為0,用START SLAVE重啟從服務器線程。 5.??? 后面再重復該程序看下次的運氣是否好一些。 我們計劃在不久的將來修復該問題。 ·???????? 可以很安全地連接用--logs-slave-updates選項指定的循環主服務器/從服務器關系中的服務器。但請注意許多語句在這種設置中不能正確工作,除非你的客戶代碼關注了潛在的在不同的服務器不同順序的更新中可能發生的這類問題。 這說明你可以象這樣創建設置: ~~~ A -> B -> C -> A ~~~ 服務器ID被編碼在二進制日志事件中,因此服務器A知道何時自己首次創建它讀取的事件并且不執行事件(除非用--replicate-same-server-id選項啟動了服務器A,只在很少情況下有意義)。這樣,沒有無限循環。只有對表執行沒有沖突的更新時該類循環設置才能工作。換句話說,如果在A和C中插入數據,絕對不應在A中插入鍵值可能與插入到C中的行相沖突的一行。如果更新的順序很重要,還不應更新兩個服務器上相同的行。 ·???????? 如果從服務器上的某個語句產生錯誤,則從服務器上的SQL線程終止,并且從服務器向錯誤日志寫入一條消息。此時應手動連接從服務器,修復該問題(例如,一個不存在的表),然后運行START SLAVE。 ·???????? 可以很安全地關閉主服務器并在以后重啟。如果某個從服務器丟失與主服務器的連接,從服務器嘗試立即重新連接。如果失敗,從服務器定期重試。(默認設置是每60秒重試一次。可以通過--master-connect-retry選項更改)。從服務器也能夠處理網絡連接中斷。但是,只有從服務器超過slave_net_timeout秒沒有從主服務器收到數據才通知網絡中斷。如果中斷時間短,可以降低slave_net_timeout。參見[5.3.3節,“服務器系統變量”](# "5.3.3.?Server System Variables")。 ·???????? 關閉從服務器(凈關閉)也很安全,因為它可以跟蹤它離開的地點。不純凈的關閉操作會產生問題,特別是系統關閉前硬盤緩存未刷新到硬盤上時。如果有不間斷電源,可以大大提高系統容錯能力。不純凈的關閉主服務器會造成主服務器上的表和二進制日志內容之間的不一致性;在主服務器上使用InnoDB表和--innodb-safe-binlog選項可以避免該問題。參見[5.11.3節,“二進制日志”](# "5.11.3.?The Binary Log")。(**注釋:**MySQL 5.1中不需要--innodb-safe-binlog,由于引入了XA事務支持已經作廢了)。 ·???????? 由于MyISAM表的非事務屬性,可以有一個語句只是更新一個表并返回錯誤代碼。例如,多行插入時有一個行超過鍵值約束,或者如果長的更新語句更新部分行后被殺掉了。如果發生在主服務器上,除非錯誤代碼合法并且語句執行產生相同的錯誤代碼,從服務器線程將退出并等待數據庫管理員決定如何做。如果該錯誤代碼驗證行為不理想,可以用--slave-skip-errors選項掩蓋(忽視)部分或全部錯誤。 ·???????? 如果從BEGIN/COMMIT系列的非事務表更新事務表,如果提交事務前更新非事務表,對二進制日志的更新可能會不同步。這是因為事務提交后才被寫入二進制日志。 ·???????? 事務混合更新事務表和非事務表時,二進制日志中語句的順序是正確的,即使在ROLLBACK時,所有需要的語句也會寫入二進制日志。但是如果在第1個連接的事務完成前,第2個連接更新非事務表,語句記入日志時會出現順序錯誤,因為第2個連接的更新執行完后立即寫入日志,而不管第1個連接執行的事務的狀態如何。 ### 6.8.?復制啟動選項 在主服務器和從服務器上,均必須使用server-id選項為每個服務器建立唯一的復制ID。你應為每個主服務器和從服務器從1到232–1的范圍挑一個唯一的正整數。例如:server-id=3 用于主服務器上控制二進制日志的選項的相關描述見[5.11.3節,“二進制日志”](# "5.11.3.?The Binary Log")。 下表描述了可以用于MySQL 5.1從屬復制服務器的選項。你可以在命令行中或在選項文件中指定這些選項。 某些從服務器復制選項按特殊方式處理,當從服務器啟動時如果master.info文件存在并且包含選項值,它們將被忽略掉。下面的選項按這種方式處理: ·???????? --master-host ·???????? --master-user ·???????? --master-password ·???????? --master-port ·???????? --master-connect-retry ·???????? --master-ssl ·???????? --master-ssl-ca ·???????? --master-ssl-capath ·???????? --master-ssl-cert ·???????? --master-ssl-cipher ·???????? --master-ssl-key 5.1中的master.info文件格式包括對應SSL選項的值。并且,文件格式包括文件中的行號,如同第1行。如果你將舊的服務器升級到新的版本,新服務器啟動時自動將smaster.info文件升級到新的格式。然而,如果將新服務器降級到舊的版本,首次啟動舊版本的服務器之前應刪除第1行。 如果從服務器啟動時master.info文件不存在,選項采用選項文件或命令行中指定的值。首次將服務器作為從服務器啟動時,或者已經運行RESET SLAVE然后已經關閉并重啟從服務器時會發生。 如果從服務器啟動時master.info文件存在,服務器忽略那些選項。使用master.info文件中發現的值。 如果你使用與master.info文件中相對應的啟動選項的不同的值重啟從服務器,啟動選項的不同的值不會生效,因為服務器繼續使用master.info文件。要想使用啟動選項的不同的值,必須刪除master.info文件并重啟從服務器,或(最好是)在從服務器運行時使用CHANGE MASTER TO語句重新設置值。 假定在my.cnf文件中指定該選項: ~~~ [mysqld] ~~~ ~~~ master-host=some_host ~~~ 第1次作為復制從服務器啟動服務器時,從my.cnf文件讀取并使用選項。服務器然后記錄master.info文件中的值。下次啟動服務器時,它只從服務器的master.info文件讀取主服務器主機值并忽略選項文件中的值。如果你修改my.cnf文件為some_other_host指定其它主服務器主機,更改仍然不會生效。你應使用CHANGE MASTER TO。 因為服務器給已有master.info文件的優先權高于剛剛描述的啟動選項,可以選擇不使用這些值的啟動選項,而是使用CHANGE MASTER TO語句來指定。參見[13.6.2.1節,“CHANGE MASTER TO語法”](# "13.6.2.1.?CHANGE MASTER TO Syntax")。 下面的例子顯示了如何更廣泛地使用啟動選項來配置從服務器: ~~~ [mysqld] ~~~ ~~~ server-id=2 ~~~ ~~~ master-host=db-master.mycompany.com ~~~ ~~~ master-port=3306 ~~~ ~~~ master-user=pertinax ~~~ ~~~ master-password=freitag ~~~ ~~~ master-connect-retry=60 ~~~ ~~~ report-host=db-slave.mycompany.com ~~~ 下面列出了控制復制的啟動選項:許多選項可以在服務器運行時通過CHANGE MASTER TO語句重新進行設置。其它選項,例如--replicate-*選項,只能在從服務器啟動時進行設置。我們計劃將修復該問題。 ·???????? --logs-slave-updates 通常情況,從服務器從主服務器接收到的更新不記入它的二進制日志。該選項告訴從服務器將其SQL線程執行的更新記入到從服務器自己的二進制日志。為了使該選項生效,還必須用--logs-bin選項啟動從服務器以啟用二進制日志。如果想要應用鏈式復制服務器,應使用--logs-slave-updates。例如,可能你想要這樣設置: ~~~ A -> B -> C ~~~ 也就是說,A為從服務器B的主服務器,B為從服務器C的主服務器。為了能工作,B必須既為主服務器又為從服務器。你必須用--logs-bin啟動A和B以啟用二進制日志,并且用--logs-slave-updates選項啟動B。 ·???????? --logs-warnings 讓從服務器向錯誤日志輸出更詳細的關于其執行操作的消息。例如,通知你網絡/連接失敗后已經成功重新連接,并通知你每個從服務器線程如何啟動。該選項默認啟用;要想禁用它,使用--skip-logs-warnings。放棄的連接不記入錯誤日志,除非該值大于1。 請注意該選項的效果不限于復制。可以對服務器的部分動作產生警告。 ·???????? --master-connect-retry=*seconds* 在主服務器宕機或連接丟失的情況下,從服務器線程重新嘗試連接主服務器之前睡眠的秒數。如果主服務器.info文件中的值可以讀取則優先使用。如果未設置, 默認值為60。 ·???????? --master-host=*host* 主復制服務器的主機名或IP地址。如果沒有給出該選項,從服務器線程不啟動。如果主服務器.info文件中的值可以讀取則優先使用。 ·???????? --master-info-file=*file_name* 從服務器用于記錄主服務器的相關信息使用的文件名。默認名為數據目錄中的mysql.info。 ·???????? --master-password=*password* 連接主服務器時從服務器線程用于鑒定的賬戶的密碼。如果主服務器.info文件中的值可以讀取則優先使用。如果未設置,假定 密碼為空。 ·???????? --master-port=*port_number* 主服務器正幀聽的TCP/IP端口號。如果主服務器.info文件中的值可以讀取則優先使用。如果未設置,假定使用編譯進來的設定值。如果你未曾用**configure**選項進行修改,該值應為3306。 ·???????? --master-ssl、--master-ssl-ca=*file_name*、--master-ssl-capath=*directory_name*、--master-ssl-cert=*file_name*、--master-ssl-cipher=*cipher_list*、--master-ssl-key=*file_name* 這些選項用于使用SSL設置與主服務器的安全復制連接。它們的含義與[5.8.7.6節,“SSL命令行選項”](# "5.8.7.6.?SSL Command-Line Options")中描述的相應—ssl、--ssl-ca、--ssl-capath、--ssl-cert、--ssl-cipher、--ssl-key選項相同。如果主服務器.info文件中的值可以讀取則優先使用。 ·???????? --master-user=*username* 連接主服務器時從服務器線程用于鑒定的賬戶的用戶名。該賬戶必須具有REPLICATION SLAVE權限。如果主服務器.info文件中的值可以讀取則優先使用。如果未設置主服務器用戶,假定使用用戶test。 ·???????? --max-relay-logs-size=*size* 自動循環中繼日志。參見[5.3.3節,“服務器系統變量”](# "5.3.3.?Server System Variables")。 ·???????? --read-only 該選項讓從服務器只允許來自從服務器線程或具有SUPER權限的用戶的更新。可以確保從服務器不接受來自客戶的更新。 ·???????? --relay-log=*file_name* 中繼日志名。默認名為*host_name-relay-bin.nnnnnn*,其中*host_name*是從服務器主機的名,*nnnnnn*表示中繼日志在編號序列中創建。如果中繼日志太大(并且你不想降低max_relay_log_size),需要將它們放到數據目錄之外的其它地方,或者如果想要通過硬盤之間的負載均衡提高速度,可以指定選項創建與主機名無關的中繼日志名。 ·???????? --relay-log-index=*file_name* 中繼日志索引文件使用的位置和名稱。默認名為*host_name-relay-bin.index*,其中*host_name*為從服務器名。 ·???????? --relay-log-info-file=*file_name* 從服務器用于記錄中繼日志相關信息的文件名。默認名為數據目錄中的relay-log.info。 ·???????? --relay-log-purge={0|1} 禁用或啟用不再需要中繼日志時是否自動清空它們。默認值為1(啟用)。這是一個全局變量,可以用SET GLOBAL Relay_log_purge動態更改。 ·???????? --relay-log-space-limit=*size* 限制所有中繼日志在從服務器上所占用空間的上限(0值表示“無限制”)。從服務器主機硬盤空間有限時很有用。達到限制后,I/O線程停止從主服務器讀取二進制日志中的事件,直到SQL線程被閉鎖并且刪除了部分未使用的中繼日志。請注意該限制并不是絕對的:有可能SQL線程刪除中繼日志前需要更多的事件。在這種情況下,I/O線程將超過限制,直到SQL線程可以刪除部分中繼日志。(不這樣做將會造成死鎖)。--relay-log-space-limit的值不能小于--max-relay-logs-size(或如果--max-relay-logs-size為0,選--max-binlog-size)的值的兩倍。在這種情況下,有可能I/O線程等待釋放空間,因為超過了--relay-log-space-limit,但SQL線程沒有要清空的中繼日志,不能滿足I/O線程的需求。強制I/O線程臨時忽視--relay-log-space-limit。 ·???????? --replicate-do-db=*db_name* 告訴從服務器限制默認數據庫(由USE所選擇)為*db_name*的語句的復制。要指定多個數據庫,應多次使用該選項,每個數據庫使用一次。請注意不復制跨數據庫的語句,例如當已經選擇了其它數據庫或沒有數據庫時執行UPDATE *some_db.some_table* SET foo='bar'。如果需要跨數據庫進行更新,使用--replicate-wild-do-table=*db_name*.%。請讀取該選項列表后面的注意事項。 一個不能按照期望工作的例子:如果用--replicate-do-db=sales啟動從服務器,并且在主服務器上執行下面的語句,UPDATE語句不會復制: ~~~ USE prices; ~~~ ~~~ UPDATE sales.january SET amount=amount+1000; ~~~ 如果需要跨數據庫進行更新,應使用--replicate-wild-do-table=*db_name*.%。 “只檢查默認數據庫”行為的主要原因是語句自己很難知道它是否應被復制(例如,如果你正使用跨數據庫的多表DELETE語句或多表UPDATE語句)。如果不需要,只檢查默認數據庫比檢查所有數據庫要快得多。 ·???????? --replicate-do-table=*db_name.tbl_name* 告訴從服務器線程限制對指定表的復制。要指定多個表,應多次使用該選項,每個表使用一次。同--replicate-do-db對比,允許跨數據庫更新。請讀取該選項列表后面的注意事項。 ·???????? --replicate-ignore-db=*db_name* 告訴從服務器不要復制默認數據庫(由USE所選擇)為*db_name*的語句。要想忽略多個數據庫,應多次使用該選項,每個數據庫使用一次。如果正進行跨數據庫更新并且不想復制這些更新,不應使用該選項。請讀取該選項后面的注意事項。 一個不能按照期望工作的例如:如果用--replicate-ignore-db=sales啟動從服務器,并且在主服務器上執行下面的語句,UPDATE語句不會復制: ~~~ ·??????????????? USE prices; ~~~ ~~~ ·??????????????? UPDATE sales.january SET amount=amount+1000; ~~~ 如果需要跨數據庫更新,應使用--replicate-wild-ignore-table=*db_name*.%。 ·???????? --replicate-ignore-table=*db_name.tbl_name* 告訴從服務器線程不要復制更新指定表的任何語句(即使該語句可能更新其它的表)。要想忽略多個表,應多次使用該選項,每個表使用一次。同--replicate-ignore-db對比,該選項可以跨數據庫進行更新。請讀取該選項后面的注意事項。 ·???????? --replicate-wild-do-table=*db_name.tbl_name* 告訴從服務器線程限制復制更新的表匹配指定的數據庫和表名模式的語句。模式可以包含‘%’和‘_’通配符,與LIKE模式匹配操作符具有相同的含義。要指定多個表,應多次使用該選項,每個表使用一次。該選項可以跨數據庫進行更新。請讀取該選項后面的注意事項。 例如:--replicate-wild-do-table=foo%.bar%只復制數據庫名以foo開始和表名以bar開始的表的更新。 如果表名模式為%,可匹配任何表名,選項也適合數據庫級語句(CREATE DATABASE、DROP DATABASE和ALTER DATABASE)。例如,如果使用--replicate-wild-do-table=foo%.%,如果數據庫名匹配模式foo%,則復制數據庫級語句。 要想在數據庫或表名模式中包括通配符,用反斜線對它們進行轉義。例如,要復制名為my_own%db的數據庫的所有表,但不復制my1ownAABCdb數據庫的表,應這樣轉義‘_’和‘%’字符:--replicate-wild-do-table=my\_own\%db。如果在命令行中使用選項,可能需要雙反斜線或將選項值引起來,取決于命令解釋符。例如,用**bash**外殼則需要輸入--replicate-wild-do-table=my\\_own\\%db。 ·???????? --replicate-wild-ignore-table=*db_name.tbl_name* 告訴從服務器線程不要復制表匹配給出的通配符模式的語句。要想忽略多個表,應多次使用該選項,每個表使用一次。該選項可以跨數據庫進行更新。請讀取該選項后面的注意事項。 例如:--replicate-wild-ignore-table=foo%.bar%不復制數據庫名以foo開始和表名以bar開始的表的更新。 關于匹配如何工作的信息,參見--replicate-wild-do-table選項的描述。在選項值中包括通配符的規則與--replicate-wild-ignore-table相同。 ·???????? --replicate-rewrite-db=*from_name*->*to_name* 告訴從服務器如果默認數據庫(由USE所選擇)為主服務器上的*from_name*,則翻譯為*to_name*。只影響含有表的語句(不是類似CREATE DATABASE、DROP DATABASE和ALTER DATABASE的語句),并且只有*from_name*為主服務器上的默認數據庫時。該選項不可以跨數據庫進行更新。請注意在測試--replicate-*規則之前翻譯數據庫名。 如果在命令行中使用該選項, ‘>’字符專用于命令解釋符,應將選項值引起來。例如: ~~~ shell> mysqld --replicate-rewrite-db="olddb->newdb" ~~~ ·???????? --replicate-same-server-id 將用于從服務器上。通常可以默認設置為0以防止循環復制中的無限循環。如果設置為1,該從服務器不跳過有自己的服務器id的事件;通常只在有很少配置的情況下有用。如果使用--logs-slave-updates不能設置為1。請注意默認情況下如果有從服務器的id,服務器I/O線程不將二進制日志事件寫入中繼日志(該優化可以幫助節省硬盤的使用)。因此如果想要使用--replicate-same-server-id,讓從服務器讀取自己的SQL線程執行的事件前,一定要用該選項啟動。 ·???????? --report-host=*slave_name* 從服務器注冊過程中報告給主服務器的主機名或IP地址。該值出現在主服務器上SHOW SLAVE HOSTS的輸出中。如果不想讓從服務器自己在主服務器上注冊,則不設置該值。請注意從服務器連接后,主服務器僅僅從TCP/IP套接字讀取從服務器的IP號是不夠的。由于 NAT和其它路由問題,IP可能不合法,不能從主服務器或其它主機連接從服務器。 ·???????? --report-port=*slave_port* 連接從服務器的TCP/IP端口號,從服務器注冊過程中報告給主服務器。只有從服務器幀聽非默認端口或如果有一個特殊隧道供主服務器或其它客戶連接從服務器時才設置它。如果你不確定,不設置該選項。 ·???????? --skip-slave-start 告訴從服務器當服務器啟動時不啟動從服務器線程。使用START SLAVE語句在以后啟動線程。 ·???????? --slave_compressed_protocol={0|1} 如果該選項設置為 1,如果從服務器和主服務器均支持,使用壓縮從服務器/主服務器協議。 ·???????? --slave-load-tmpdir=*file_name* 從服務器創建臨時文件的目錄名。該選項默認等于tmpdir系統變量的值。當從服務器SQL線程復制LOAD DATA INFILE語句時,從中繼日志將待裝載的文件提取到臨時文件,然后將這些文件裝入到表中。如果裝載到主服務器上的文件很大,從服務器上的臨時文件也很大。因此,建議使用該選項告訴從服務器將臨時文件放到文件系統中有大量可用空間的目錄下。在這種情況下,也可以使用--relay-log選項將中繼日志放到該文件系統中,因為中繼日志也很大。--slave-load-tmpdir應指向基于硬盤的文件系統,而非基于內存的文件系統:從服務器需要用臨時文件在機器重啟時用于復制LOAD DATA INFILE。系統啟動過程中操作系統也不能清除該目錄。 ·???????? --slave-net-timeout=*seconds* 放棄讀之前從主服務器等候更多數據的秒數,考慮到連接中斷和嘗試重新連接。超時后立即開始第1次重試。由--master-connect-retry選項控制重試之間的間隔。 ·???????? --slave-skip-errors=[*err_code1*,*err_code2*,... | all] 通常情況,當出現錯誤時復制停止,這樣給你一個機會手動解決數據中的不一致性問題。該選項告訴從服務器SQL線程當語句返回任何選項值中所列的錯誤時繼續復制。 如果你不能完全理解為什么發生錯誤,則不要使用該選項。如果復制設置和客戶程序中沒有bug,并且MySQL自身也沒有bug,應不會發生停止復制的錯誤。濫用該選項會使從服務器與主服務器不能保存同步,并且你找不到原因。 對于錯誤代碼,你應使用從服務器錯誤日志中錯誤消息提供的編號和SHOW SLAVE STATUS的輸出。服務器錯誤代碼列于[附錄B:](#)[*錯誤代碼和消息*](# "Appendix?B.?Error Codes and Messages")。 你也可以(但不應)使用不推薦的all值忽略所有錯誤消息,不考慮所發生的錯誤。無需而言,如果使用該值,我們不能保證數據的完整性。在這種情況下,如果從服務器的數據與主服務器上的不相近請不要抱怨(或編寫bug報告)。*已經警告你了*。 例如: ~~~ --slave-skip-errors=1062,1053 ~~~ ~~~ --slave-skip-errors=all ~~~ 從服務器按下面評估--replicate-*規則,確定是否執行或忽視語句: 1.??? 是否有--replicate-do-db或--replicate-ignore-db規則? ·???????? *有*:測試--binlog-do-db和--binlog-ignore-db(參見[5.11.3節,“二進制日志”](# "5.11.3.?The Binary Log"))。測試結果是什么? o??????? 忽視語句:忽視并退出。 o??????? 許可語句:不立即執行語句。推遲決策;繼續下一步。 ·???????? *沒有*:繼續下一步。 2.??? 我們目前正執行保存的程序或函數嗎? ·???????? *是*:執行查詢并退出。 ·???????? *否*:繼續下一步。 3.??? 是否有--replicate-*-table規則? ·???????? *沒有*:執行查詢并退出。 ·???????? *有*:繼續下一步并開始按所示順序評估表規則(首先是非通配規則,然后是通配規則)。只有待更新的表根據這些規則進行比較(INSERT INTO sales SELECT * FROM prices:只有sales根據這些規則進行比較)。如果要更新幾個表(多表語句),第1個匹配的表(匹配“do”或“ignore”)獲贏。也就是說,根據這些規則比較第1個表。然后,如果不能進行決策,根據這些規則比較第2個表等等。 4.??? 是否有--replicate-do-table規則? ·???????? *有*:表匹配嗎? o??????? *是*:執行查詢并退出。 o??????? *否*:繼續下一步。 ·???????? *沒有*:繼續下一步。 5.??? 是否有--replicate-ignore-table規則? ·???????? *有*:表匹配嗎? o??????? *是*:忽視查詢并退出。 o??????? *否*:繼續下一步。 ·???????? *沒有*:繼續下一步。 6.??? 是否有--replicate-wild-do-table規則? ·???????? *有*:表匹配嗎? o??????? *是*:執行查詢并退出。 o??????? *否*:繼續下一步。 ·???????? *沒有*:繼續下一步。 7.??? 是否有--replicate-wild-ignore-table規則? ·???????? *有*:表匹配嗎? o??????? *是*:忽視查詢并退出。 o??????? *否*:繼續下一步。 ·???????? *沒有*:繼續下一步。 8.??? 沒有匹配的--replicate-*-table規則。要根據這些規則測試其它表嗎? ·???????? *是*:執行循環。 ·???????? *否*:我們現在已經測試了所有待更新的表,結果不能匹配任何規則。是否有--replicate-do-table或--replicate-wild-do-table規則? o??????? *有*:有“do”規則但不匹配。忽視查詢并退出。 o??????? *沒有*:執行查詢并退出。 ### 6.9.?復制FAQ **Q**:如果主服務器正在運行并且不想停止主服務器,怎樣配置一個從服務器? **A**:有多種方法。如果你在某時間點做過主服務器備份并且記錄了相應快照的二進制日志名和偏移量(通過SHOW MASTER STATUS命令的輸出),采用下面的步驟: 1.??? 確保從服務器分配了一個唯一的服務器ID號。 2.??? 在從服務器上執行下面的語句,為每個選項填入適當的值: ??????????? 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; ~~~ 3.??? 在從服務器上執行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轉儲到到你的從服務器。然而,這比進行二進制復制速度慢。 不管你使用這兩種方法中的那一個,當你有一個快照和記錄了日志名與偏移量時,后來根據說明操作。你可以使用相同的快照建立多個從服務器。一旦你擁有主服務器的一個快照,可以等待創建一個從服務器,只要主服務器的二進制日志完整。兩個能夠等待的時間實際的限制是指在主服務器上保存二進制日志的可用硬盤空間和從服務器同步所用的時間。 你也可以使用LOAD DATA FROM MASTER。這是一個方便的語句,它傳輸一個快照到從服務器并且立即調整日志名和偏移量。將來,LOAD DATA FROM MASTER將成為創建從服務器的推薦方法。然而需要注意,它只工作在MyISAM表上并且可能長時間持有讀鎖定。它并不象我們希望的那樣高效率地執行。如果你有大表,執行FLUSH TABLES WITH READ LOCK語句后,這時首選方法仍然是在主服務器上制作二進制快照。 **Q**:從服務器需要始終連接到主服務器嗎? **A**:不,不需要。從服務器可以宕機或斷開連接幾個小時甚至幾天,重新連接后獲得更新信息。例如,你可以在通過撥號的鏈接上設置主服務器/從服務器關系,其中只是偶爾短時間內進行連接。這意味著,在任何給定時間,從服務器不能保證與主服務器同步除非你執行某些特殊的方法。將來,我們將使用選項來阻塞主服務器直到有一個從服務器同步。 **Q**:我怎樣知道從服務器與主服務器的最新比較? 換句話說,我怎樣知道從服務器復制的最后一個查詢的日期? **A**:你可以查看SHOW SLAVE STATUS語句的Seconds_Behind_Master列的結果。參見[6.3節,“復制實施細節”](# "6.3.?Replication Implementation Details")。 當從服務器SQL線程執行從主服務器讀取的事件時,它根據事件時間戳修改自己的時間(這是TIMESTAMP能夠很好復制的原因)。在SHOW PROCESSLIST語句輸出的Time列內,為從服務器SQL線程顯示的秒數是最后一個復制事件的時間戳和從服務器主機的實際時間之間相差的秒數。你可以使用它來確定最后一個復制事件的日期。注意,如果你的從服務器與主服務器連接斷開一個小時,然后重新連接,在SHOW PROCESSLIST結果中,你可以立即看到從服務器SQL線程的Time值為3600。這可能是因為從服務器執行的語句是一個一小時之前的。 **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; ~~~ **Q**:當設置雙向復制時我應該知道發出那些語句? **A**:MySQL復制目前不支持主服務器和從服務器之間的任何鎖定協議來保證分布式(跨服務器)更新的原子性。換句話說,這樣做是可能的:客戶A根據協作-主服務器1更新,同時,在它傳給協作-主服務器2之前,客戶B能夠根據協作-主服務器2更新,這樣客戶A的更新與它在協作-主服務器1的更新不同。這樣,當客戶A根據協作-主服務器2更新時,它產生的表與在協作-主服務器1上的不同,即使所有根據協作-主服務器2的更新已經傳過來。這意味著,在雙向復制關系中,你不應該把兩個服務器串連在一起,除非你確信任何順序的更新是安全的,或者除非你在客戶端代碼中注意怎樣避免更新順序錯誤。 你還必須認識到從更新角度,雙向復制實際上并不能顯著地提高性能(或者根本不能提高性能)。兩個服務器都需要做相同數量的更新,如同在一個服務器做的那樣。唯一的差別是鎖競爭要少,這因為源于另一個服務器的更新在一個從線程中序列化。即使這個益處可能被網絡延遲抵消。 **Q**:怎樣通過復制來提高系統的性能? **A**:你應將一個服務器設置為主服務器并且將所有寫指向該服務器。然后根據預算配置盡可能多的從服務器以及棧空間,并且在主服務器和從服務器之間分發讀取操作。你也可以用--skip-innodb、--skip-bdb、--low-priority-updates以及--delay-key-write=ALL選項啟動從服務器,以便在從服務器端提高速度。在這種情況下,為了提高速度,從服務器使用非事務MyISAM表來代替InnoDB和BDB表。 **Q**:為了使用高性能的復制,我應該在自己的應用程序中怎樣準備客戶端代碼? **A**:如果你的代碼中數據庫訪問部分已經正確地模塊化,應該能夠平滑和容易地轉換為在復制步驟中運行的代碼。僅需要更改數據庫訪問執行部分,以便發送所有的寫操作到主服務器,以及發送讀操作到主服務器或某個從服務器。如果你的代碼沒有這個級別,設置一個復制系統以便清除。應先通過下面的函數創建一個包裝庫或模塊: ·???????? safe_writer_connect() ·???????? safe_reader_connect() ·???????? safe_reader_statement() ·???????? safe_writer_statement() 每個函數名的safe_意味著函數比較小心地處理所有錯誤。你可以使用不同名的函數。重要是對于讀連接、寫連接、讀和寫有一個統一的接口。 然后,你應該轉換客戶端代碼使用包裝庫。剛開始這可能是痛苦和恐慌的過程,但從長遠來看是值得的。使用剛才討論的方法的所有應用程序都能夠利用主服務器/從服務器配置的優越性,即使是含有多個從服務器的配置。代碼非常容易維護,并且添加排錯選項也很容易。你僅需要修改一兩個函數;例如,記錄每個語句執行的時間,或者你的上千個語句中哪個語句發生了錯誤。 如果你已經編寫了許多代碼,你可能想使用**replace**工具自動進行轉換,該工具隨標準MySQL一起發布,或可以自己編寫轉換腳本。理想情況,你的代碼使用一致的程序轉換風格。否則,可能最好重新編寫代碼,或者至少手工對其進行規則化以使用一致的風格。 **Q**:MySQL復制能夠何時和多大程度提高系統性能? **A**:MySQL復制對于頻繁讀和頻繁寫的系統具有最大好處。理論上,通過使用單個主服務器/多從服務器設置,可以通過添加更多的從服務器來擴充系統,直到用完網絡帶寬,或者你的更新負載已經增長到主服務器不能處理的點。 在獲得的收益開始吃平之前,為了確定可以有多少從服務器,以及可以將你的站點的性能提高多少,需要知道查詢模式,并且要通過基準測試并根據經驗確定一個典型的主服務器和從服務器中的讀取(每秒鐘讀取量,或者max_reads)吞吐量和寫(max_writes)吞吐量的關系。通過一個假設的帶有復制的系統,本例給出了一個非常簡單的計算結果。 假設系統負載包括10%的寫和90%的讀取,并且我們通過基準測試確定max_reads是1200 –2 × max_writes。換句話說,如果沒有寫操作,系統每秒可以進行1,200次讀取操作,平均寫操作是平均讀操作所用時間的兩倍,并且關系是線性的。我們假定主服務器和每個從服務器具有相同的性能,并且我們有一個主服務器和*N*個從服務器。那么,對于每個服務器(主服務器或從服務器),我們有: reads = 1200 – 2 × writes reads = 9 × writes / (*N* + 1) (讀取是分離的, 但是寫入所有服務器) 9 × writes / (*N* + 1) + 2 × writes = 1200 writes = 1200 / (2 + 9/(*N*+1)) 最后的等式表明了*N*個從服務器的最大寫操作數,假設最大可能的讀取速率是每分鐘1,200次,讀操作與寫操作的比率是9。 如上分析可以得到下面的結論: ·???????? 如果*N* = 0(這表明沒有復制),系統每秒可以處理大約1200/11 = 109個寫操作。 ·???????? 如果*N* = 1,每秒得到184個寫操作。 ·???????? 如果*N* = 8,每秒得到400個寫操作。 ·???????? 如果*N* = 17,每秒得到480個寫操作。 ·???????? 最后,當 *N*趨于無窮大(以及我們預算的負無窮大)時,可以得到非常接近每秒600個寫操作,系統吞吐量增加將近5.5倍。然而,如果只用8個服務器,增加接近4倍。 請注意,這些計算假設網絡帶寬無窮大并忽略掉了其它一些因素,那些因素可能對系統產生重要的影響。在許多情況下,不能執行與剛才類似的計算,即如果添加*N*臺復制從服務器,應該準確預報系統將發生哪些影響。回答下面的問題應能夠幫助你確定復制是否和在多大程度上能夠提高系統的性能: ·???????? 系統上的讀取/寫比例是什么? ·???????? 如果減少讀取操作,一個服務器可以多處理多少寫負載? ·???????? 網絡帶寬可滿足多少從服務器的需求? **Q**:如何使用復制來提供冗余/高可用性? **A**:利用目前的可用特性,必須設置一個主服務器和一個從服務器(或多個從服務器),以及寫一個腳本來監視主服務器是否啟動。如果主服務器失敗,通知應用程序和從服務器切換主服務器。下面是一些建議: ·???????? 告知從服務器更改其主服務器,使用CHANGE MASTER TO語句。 ·???????? 通知應用程序主服務器位置的一個很好的方法是對主服務器提供動態DNS入口。用bind可以使用nsupdate動態更新DNS。 ·???????? 應該用--logs-bin選項而不用 --logs-slave-updates選項運行從服務器。這樣,一旦你在其它從服務器上發出STOP SLAVE; RESET MASTER, 以及CHANGE MASTER TO語句,該從服務器可以切換為主服務器。例如,假設有下面的設置: ~~~ ·??????????????? ???????WC ~~~ ~~~ ·??????????????? ????????\ ~~~ ~~~ ·??????????????? ?????????v ~~~ ~~~ ·??????????????? ?WC----> M ~~~ ~~~ ·??????????????? ???????/ | \ ~~~ ~~~ ·??????????????? ??????/? |? \ ~~~ ~~~ ·??????????????? ?????v?? v?? v ~~~ ~~~ ·??????????????? ????S1?? S2? S3 ~~~ **M**代表主服務器,**S**代表從服務器,**WC**代表發出數據庫寫和讀取操作的客戶;只發出數據庫讀取操作的客戶沒有給出,因為它們不需要切換。**S1、S2**以及**S3**是從服務器,用--logs-bin選項而沒有用--logs-slave-updates運行。因為從服務器收到的主服務器的更新沒有記錄在二進制日志中,除非指定 --logs-slave-updates選項,每個從服務器上的二進制日志是空的。如果因為某些原因**M **變得不可用,你可以選取一個從服務器變為新的主服務器。例如,如果你選取了**S1**,所有**WC**應該重新指向**S1**和**S2**,并且**S3**然后應從**S1**復制**。** 確保所有從服務器已經處理了中繼日志中的所有語句。在每個從服務器上,發出STOP SLAVE IO_THREAD語句,然后檢查SHOW PROCESSLIST語句的輸出,直到你看到Has read all relay log。當所有從服務器都執行完這些,它們可以被重新配置為一個新的設置。在被提升為主服務器的從服務器**S1**上,發出STOP SLAVE和RESET MASTER語句。 在其它從服務器**S2**和**S3上**,使用STOP SLAVE和CHANGE MASTER TO MASTER_HOST='S1'(其中'S1'表示**S1**實際的主機名)。為CHANGE MASTER添加關于從**S2**或**S3**如何連接到**S1的**所有信息(*user*、*password*、*port*)。在CHANGE MASTER命令中,不需要指定從其讀取的**S1**的二進制日志名或二進制日志位置:我們知道它是第1個二進制日志,位置是4,這是CHANGE MASTER命令的默認值。最后,在**S2**和**S3上**使用START SLAVE 命令。 然后,指示所有**WC**把它們的語句指向**S1。**此后,**WC**發出的所有發送到**S1的**更新語句被寫入**S1的**二進制日志,**S1**則包含**M**死掉之后的發送到 **S1**的每一個更新語句。 結果是下面的配置: ~~~ ?????? WC ~~~ ~~~ ????? / ~~~ ~~~ ????? | ~~~ ~~~ WC?? |? M(unavailable) ~~~ ~~~ ? \?? | ~~~ ~~~ ?? \? | ~~~ ~~~ ??? v v ~~~ ~~~ ???? S1<--S2? S3 ~~~ ~~~ ????? ^?????? | ~~~ ~~~ ????? +-------+ ~~~ 當**M**重新啟動后,你必須在**M上**發出相同的CHANGE MASTER語句,與在**S2**和**S3**上發出的語句一樣,以便**M**變為**S1的**從服務器并且恢復在它宕機后丟失的所有**WC**寫操作。要把** M **再次作為主服務器(例如,因為它是功能最強的機器),使用前面的步驟,好像**S1**不可用并且**M**變為一個新的主服務器一樣。在這個過程中,在**S1、S2**以及**S3**作為**M的**從服務器之前,不要忘記在**M上**運行RESET MASTER。否則,它們可能拾取**M**變得不可用之前的舊**WC**寫操作。 我們目前正在MySQL集成自動主服務器選擇系統,但在準備好之前,你必須創建自己的監控工具。 ### 6.10.?復制故障診斷與排除 如果你遵從了上述說明,復制設置仍然不工作,首先檢查下面各項: ·???????? **檢查錯誤日志的消息**。許多用戶遇到問題后沒有及時地這樣做而浪費了時間。 ·???????? 主服務器記錄到了二進制日志?用SHOW MASTER STATUS檢查。如果已經記錄,Position應為非零。如果沒有記錄,確認正用log-bin和server-id選項運行主服務器。 ·???????? 是否從服務器在運行?使用SHOWSHOW SLAVE STATUS檢查是否slave_IO_Running和slave_SQL_Running的值均為Yes。如果不是,驗證當啟動從服務器時使用的選項。 ·???????? 如果從服務器正在運行,建立了與主服務器的連接嗎?使用SHOW PROCESSLIST,找出I/O和SQL線程并檢查它們的State列看它們如何顯示。參見[6.3節,“復制實施細節”](# "6.3.?Replication Implementation Details")。如果I/O線程狀態為Connecting to master,驗證主服務器上復制用戶的權限、主服務器主機名、DNS設置,是否主服務器真正在運行,以及是否可以從從屬服務器訪問。 ·???????? 如果從服務器以前在運行但是現在已經停止,原因通常是在主服務器上成功的部分語句在從服務器上失敗了。如果你正確快照了主服務器,并且從來沒有不通過服務器線程修改從服務器上的數據,這種現象不應發生。如果發生,應為一個bug或你遇到了一個[6.7節,“復制特性和已知問題”](# "6.7.?Replication Features and Known Problems")描述的已知的復制限制。如果是一個bug,參見[6.11節,“通報復制缺陷”](# "6.11.?Reporting Replication Bugs")查閱如何通報的說明。 ·???????? 如果某個在主服務器上成功的語句拒絕在從服務器上運行,并且不能執行完全的數據庫重新同步(即刪除從服務器的數據庫并從主服務器復制新的快照),嘗試: 1.??? 確定是否從服務器的表與主服務器的不同。盡力了解發生的原因。然后讓從服務器的表與主服務器的一樣并運行START SLAVE。 2.??? 如果前面的步驟不工作或不適合,盡力了解手動更新是否安全(如果需要),然后忽視來自主服務器的下一個語句。 3.??? 如果你確定可以跳過來自主服務器的下一個語句,執行下面的語句: ~~~ 4.????????????????? mysql> SET GLOBAL SQL_slave_SKIP_COUNTER = n; ~~~ ~~~ 5.????????????????? mysql> START SLAVE; ~~~ 如果來自主服務器的下一個語句不使用AUTO_INCREMENT或LAST_INSERT_ID(),*n*值應為1。否則,值應為2。使用AUTO_INCREMENT或LAST_INSERT_ID()的語句使用值2的原因是它們從主服務器的二進制日志中取兩個事件。 6.??? 如果你確保從服務器啟動時完好地與主服務器同步,并且沒有更新從服務器線程之外的表,則大概詫異是由于bug。如果你正運行最近的版本,請通報該問題。如果你正運行舊版本MySQL,盡力升級到最新的產品版本。 ### 6.11.?通報復制缺陷 如果你確定沒有用戶錯誤,但復制仍然不工作或不穩定,則是向我們發送bug通報的時候了。我們需要盡可能從你那兒獲得更多的信息已跟蹤bug。請花一些時間和努力編寫一份好的bug通報。 如果你有一個重復的測試案例來說明bug,請把它輸入我們的bug數據庫,位置為[http://bugs.mysql.com/](http://bugs.mysql.com/)。如果你有一個“phantom”問題(不能按照期望進行復制),則使用下面的程序: 1.??? 確認未包括用戶錯誤。例如,如果你不用從服務器線程來更新從服務器,數據將不同步,并且會遇到唯一的鍵值違背更新。在這種情況下,從服務器線程停止并等待你手動清理表使它們同步。*這不是復制問題。這是一個外部接口問題造成復制失敗。* 2.??? 用--logs-slave-updates和--logs-bin選項運行從服務器。這些選項使從服務器將從主服務器接收的更新記入自己的二進制日志。 3.??? 重新設置復制狀態之前保存所有的證據。如果我們沒有信息或只有粗略的信息,則難以或不可能跟蹤問題。應搜集的證據為: ·???????? 所有主服務器的二進制日志 ·???????? 所有從服務器的二進制日志 ·???????? 你發現問題時主服務器的SHOW MASTER STATUS的輸出 ·???????? 你發現問題時主服務器的SHOW SLAVE STATUS的輸出 ·???????? 主服務器和從服務器的錯誤日志 4.??? 使用**mysqlbinlog**檢查二進制日志。下面命令應有助于發現有問題的查詢,例如: ~~~ 5.??????????? shell> mysqlbinlog -j pos_from_slave_status \ ~~~ ~~~ 6.??????????? ???????????/path/to/log_from_slave_status | head ~~~ 搜集了問題的證據后,首先作為一個測試案例隔離開。然后將問題輸入我們的bug數據庫,位置為[http://bugs.mysql.com/](http://bugs.mysql.com/),應提供盡可能多的信息。 ### 6.12.?多服務器復制中的Auto-Increment 當將多個服務器配置為復制主服務器時,使用auto_increment時應采取特殊步驟以防止鍵值沖突,否則插入行時多個主服務器會試圖使用相同的auto_increment值。 服務器變量auto_increment_increment和auto_increment_offset可以幫助協調多主服務器復制和AUTO_INCREMENT列。每個變量有一個默認的(并且是最小的)值1,最大值為65,535。 將這些變量設置為非沖突的值,當在同一個表主插入新行時,多主服務器配置主的服務器將不會與AUTO_INCREMENT值沖突。 這兩個變量這樣影響AUTO_INCREMENT列: ·???????? auto_increment_increment控制列值增加的間隔。例如: ~~~ ·??????????????? mysql> SHOW VARIABLES LIKE 'auto_inc%'; ~~~ ~~~ ·??????????????? +--------------------------+-------+ ~~~ ~~~ ·??????????????? | Variable_name??????????? | Value | ~~~ ~~~ ·??????????????? +--------------------------+-------+ ~~~ ~~~ ·??????????????? | auto_increment_increment | 1???? | ~~~ ~~~ ·??????????????? | auto_increment_offset??? | 1???? | ~~~ ~~~ ·??????????????? +--------------------------+-------+ ~~~ ~~~ ·??????????????? 2 rows in set (0.00 sec) ~~~ ~~~ ·??????????????? ? ~~~ ~~~ ·??????????????? mysql> CREATE TABLE autoinc1 (col INT NOT NULL AUTO_INCREMENT PRIMARY KEY); ~~~ ~~~ ·??????????????? Query OK, 0 rows affected (0.04 sec) ~~~ ~~~ ·??????????????? ? ~~~ ~~~ ·??????????????? mysql> SET @auto_increment_increment=10; ~~~ ~~~ ·??????????????? Query OK, 0 rows affected (0.00 sec) ~~~ ~~~ ·??????????????? ? ~~~ ~~~ ·??????????????? mysql> SHOW VARIABLES LIKE 'auto_inc%'; ~~~ ~~~ ·??????????????? +--------------------------+-------+ ~~~ ~~~ ·??????????????? | Variable_name??????????? | Value | ~~~ ~~~ ·??????????????? +--------------------------+-------+ ~~~ ~~~ ·??????????????? | auto_increment_increment | 10??? | ~~~ ~~~ ·??????????????? | auto_increment_offset??? | 1???? | ~~~ ~~~ ·??????????????? +--------------------------+-------+ ~~~ ~~~ ·??????????????? 2 rows in set (0.01 sec) ~~~ ~~~ ·??????????????? ? ~~~ ~~~ ·??????????????? mysql> INSERT INTO autoinc1 VALUES (NULL), (NULL), (NULL), (NULL); ~~~ ~~~ ·??????????????? Query OK, 4 rows affected (0.00 sec) ~~~ ~~~ ·??????????????? Records: 4? Duplicates: 0? Warnings: 0 ~~~ ~~~ ·??????????????? ? ~~~ ~~~ ·??????????????? mysql> SELECT col FROM autoinc1; ~~~ ~~~ ·??????????????? +-----+ ~~~ ~~~ ·??????????????? | col | ~~~ ~~~ ·??????????????? +-----+ ~~~ ~~~ ·??????????????? |?? 1 | ~~~ ~~~ ·??????????????? |? 11 | ~~~ ~~~ ·??????????????? |? 21 | ~~~ ~~~ ·??????????????? |? 31 | ~~~ ~~~ ·??????????????? +-----+ ~~~ ~~~ ·??????????????? 4 rows in set (0.00 sec) ~~~ (這里注明如何使用SHOW VARIABLES以獲得這些變量的當前值)。 ·???????? auto_increment_offset確定AUTO_INCREMENT列值的起點。影響到在復制設置主可以有多少主服務器(例如將該值設置為10表示設置可以支持10個服務器)。 考慮下面的命令,假定在前面所示示例中的相同的會話中執行這些命令: ~~~ mysql> SET @auto_increment_offset=5; ~~~ ~~~ Query OK, 0 rows affected (0.00 sec) ~~~ ~~~ ? ~~~ ~~~ mysql> SHOW VARIABLES LIKE 'auto_inc%'; ~~~ ~~~ +--------------------------+-------+ ~~~ ~~~ | Variable_name??????????? | Value | ~~~ ~~~ +--------------------------+-------+ ~~~ ~~~ | auto_increment_increment | 10??? | ~~~ ~~~ | auto_increment_offset??? | 5???? | ~~~ ~~~ +--------------------------+-------+ ~~~ ~~~ 2 rows in set (0.00 sec) ~~~ ~~~ ? ~~~ ~~~ mysql> CREATE TABLE autoinc2 (col INT NOT NULL AUTO_INCREMENT PRIMARY KEY); ~~~ ~~~ Query OK, 0 rows affected (0.06 sec) ~~~ ~~~ ? ~~~ ~~~ mysql> INSERT INTO autoinc2 VALUES (NULL), (NULL), (NULL), (NULL); ~~~ ~~~ Query OK, 4 rows affected (0.00 sec) ~~~ ~~~ Records: 4 ?Duplicates: 0? Warnings: 0 ~~~ ~~~ ? ~~~ ~~~ mysql> SELECT col FROM autoinc2; ~~~ ~~~ +-----+ ~~~ ~~~ | col | ~~~ ~~~ +-----+ ~~~ ~~~ |?? 5 | ~~~ ~~~ |? 15 | ~~~ ~~~ |? 25 | ~~~ ~~~ |? 35 | ~~~ ~~~ +-----+ ~~~ ~~~ 4 rows in set (0.02 sec) ~~~ 詳細信息參見[5.3.3節,“服務器系統變量”](# "5.3.3.?Server System Variables")。 這是MySQL參考手冊的翻譯版本,關于MySQL參考手冊,請訪問[dev.mysql.com](http://dev.mysql.com/doc/mysql/en)。 原始參考手冊為英文版,與英文版參考手冊相比,本翻譯版可能不是最新的。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看