使用MySQL內建複製功能來最佳化可用性(轉)

ba發表於2007-08-12
使用MySQL內建複製功能來最佳化可用性(轉)[@more@]在Soundbreak我們每天24小時不間斷地播放實況音訊和影片,所以對於MySQL的新增的複製特性,我們不能做出很令人信服的測試。透過測試我們發現,可以使用這個特性來與備份資料庫伺服器保持資料同步,這樣當主伺服器因為某種原因處理失效時,能夠使用備份機處理所有的查詢。對於這樣的要求,配置兩臺伺服器並不困難。我將詳細討論整個處理過程,同時討論一下當主伺服器失效時,如何使用PHP來重定向查詢。

  MySQL內部複製功能是建立在兩個或兩個以上伺服器之間,透過設定它們之間的主-從關係來實現的。其中一個作為主伺服器,其它的作為從伺服器。我將詳細討論如何配置兩臺伺服器,將一個設為主伺服器,另一個設為從伺服器。並且描述一下在它們之間進行切換的處理過程。我是在MySQL的3.23.23版本上進行的配置設定過程,並且也是在這個版本上進行的測試。MySQL開發人員建議最好使用最新版本,並且主-從伺服器均使用相同的版本。同時MySQL 3.23版本仍然是beta測試版,而且這個版本可能不能向下相容。所以因為這個原因,在實際的網站中,我現在還沒有使用這個版本。擁有容錯能力具有一個好處是,在不需中斷任何查詢的情況下,對伺服器進行升級。

第一步:配置主伺服器
  在這篇文章的剩下篇幅中,我將指定兩臺伺服器。A(IP為10.1.1.1)作為主伺服器(簡稱為主機)。B(IP為10.1.1.2)作為後備伺服器(簡稱為備機)。

  MySQL的複製功能的實現過程為:備機(B)與主機(A)連線,然後讀出主機的二進位制更新日誌,再將發生的變化合併到自已的資料庫中。備機需要一個使用者帳號來與主機連線,所以在主機上建立一個帳號,並只給它FILE許可權,如下操作:

GRANT FILE ON *.* TO replicate@10.1.1.2 IDENTIFIED BY password;

  為了備機能夠與主機連線,要在主機上執行FLUSH PRIVILEGES,不過不要擔心,因為我們將在下面的步驟中停掉伺服器。

  現在我們需要主機資料庫的一個快照,並且對主機進行配置,允許生成二進位制的更新日誌。首先編輯my.cnf檔案,以便允許二進位制更新日誌,所以在[mysqld]部分的下面某個地方增加一行:log-bin。在下一次伺服器啟動時,主機將生成二進位制更新日誌(名為:-bin.)。為了讓二進位制更新日誌有效,關閉MySQL服務程式,然後將主機上的所有資料庫目錄到另一個目錄中,接著重新啟動mysqld。
請確定得到了所有資料庫,否則在進行復制時,如果一個表在主機上存在但在備機上不存在,將因為出錯而退出。現在你已經得到了資料的快照,和一個從建立快照以來的二進位制日誌,上面記錄著任何對資料庫的修改。請注意MySQL資料檔案(*.MYD,*.MYI和*.frm)是依賴於檔案系統的,所以你不能僅僅進行檔案傳輸,如從Solaris到Linux。如果你處於一個異種的伺服器環境,你將不得不使用mysqldump實用程式或其它的定製指令碼來得到資料快照。

第二步:配置備機
  讓我們繼續。停掉備機上的MySQL服務程式,並且把從主機上複製來的資料庫目錄移到備機上的data目錄下。請確認將目錄的擁有者和屬組改變為MySQL使用者相應值,並且修改檔案模式為660(只對擁有者和屬組可讀、可寫),目錄本身為770(只對擁有者和屬組可讀、可寫和可執行)。

  繼續。在備機上啟動MySQL服務程式,確認MySQL工作正常。執行幾個select查詢(不要update或insert查詢),看一看在第一步中得到的資料快照是否成功。接著,在測試成功後關掉MySQL服務程式。

  在備機上配置需要訪問的主機,以便接收主機的更改。所以需要編輯務機上的my.cnf檔案,在[mysqld]部分中增加下面幾行:

master-host=10.1.1.1
master-user=replicate
master-password=password

  在啟動備機服務程式後,備機服務程式將檢視在my.cnf檔案中所指定的主機,檢視是否有改變,並且將這些改變合併到自已的資料庫中。備機保持了主機的更新記錄,這些記錄是從主機的master.info檔案中接收下來的。備機執行緒的狀態可以透過sql命令SHOW SLAVE-STATUS看到。在備機上處理二進位制日誌中如果
發生錯誤,都將導致備機執行緒的退出,並且在*.err的日誌檔案中生成一條資訊。然後錯誤可以被改正,接著可以使用sql語句SLAVE START來重新啟動備機執行緒。執行緒將從主機二進位制日誌處理中斷的地方繼續處理。

  至此,在主機上所發生的資料改變應該已經複製到備機上了,要測試它,你可以在主機上插入或更新一條記錄,而在備機上選擇這條記錄。

  現在我們擁有了從A機到B機的這種主-從關係,這樣當A機可能當機的時候,允許我們將所有的查詢重定向到B機上去,但是當A機恢復時,我們沒有辦法將發生的改變恢復到A機中去。為了解決這個問題,我們建立從B機到A機的主-從關係。

第三步:建立相互的主從關係
  首先在B機上的my.cnf檔案中,在[mysqld]部分中加入log-bin,接著重新啟動mysqld,然後建立可在它的上面執行復制功能的使用者帳號,使用:

GRANT FILE ON *.* TO replicate@10.1.1.1 IDENTIFIED BY password;

  在B機上執行FLUSH PRIVILEGES命令,以便裝入在加入複製使用者後的新的授權表,接著回到A機上,在它的my.cnf中加入下面幾行:

master-host=10.1.1.2
master-user=replicate
master-password=password

  在重啟A機的服務程式之後,現在我們一擁有了在A機與B機之間的相互主-從關係。不管在哪個伺服器上更新一條記錄或插入一條記錄,都將被複制到另一臺伺服器上。要注意的是:我不敢確定一個備機合併二進位制日誌變化的速度有多快,所以用這種方法來進行插入或更新語句的負載平衡可能不是一個好辦法。

第四步:修改你的資料庫連線程式
  既然你已經在A機和B機之間建立了一個相互的關係,你需要修改資料庫連線程式,以便從這種方式中得到好處。下面的函式首先試圖與A機連線,如果不能建立連線則與B機連線。


/********************************************************
function db_connect()

returns a link identifier on success, or false on error
********************************************************/
function db_connect(){
 $username = "replUser";
 $password = "password";
 $primary = "10.1.1.1";
 $backup = "10.1.1.2";

# attempt connection to primary
if(! $link_id = @mysql_connect( $primary,  $username,  $password))
# attempt connection to secondary
 $link_id = @mysql_connect( $secondary,  $username,  $password)
return  $link_id;
}

?>

  我在兩種情況下對使用了上面技術的資料庫連線建立過程進行了測試,一種是主MySQL服務程式關閉了,但是伺服器還在執行,另一種情況是主伺服器關閉了。如果只是mysqld關閉了,連線會馬上轉向備機;但是如果整個伺服器關閉了,就出現了無限地等待(兩分鐘後我放棄了跟蹤 -- 很短的注意跨度),因為PHP在查詢一個不存在的伺服器。不幸地是,不象fsockopen函式,mysql_connect函式沒有一個超時引數,然而我們可以使用fsockopen來模擬一個超時處理。

第五步:一個改進的資料庫連線程式

/********************************************************
function db_connect_plus()

returns a link identifier on success, or false on error
********************************************************/
function db_connect_plus(){
 $username = "username";
 $password = "password";
 $primary = "10.1.1.1";
 $backup = "10.1.1.2";
 $timeout = 15; // timeout in seconds

if( $fp = fsockopen( $primary, 3306, & $errno, & $errstr,  $timeout)){
fclose( $fp);
return  $link = mysql_connect( $primary,  $username,  $password);
}
if( $fp = fsockopen( $secondary, 3306, & $errno, & $errstr,  $timeout)){
fclose( $fp);
return  $link = mysql_connect( $secondary,  $username,  $password);
}

return 0;
}

?>

  這個新改進的函式向我們提供了一個可調的超時特性,這正是mysql_connect函式所缺少的。如果連線立即失敗,這種情況如機器"活"著,但mysqld"當"掉了,函式立即移到第二個伺服器。上面的函式相當健壯,在試圖進行連線之前先測試一下,檢視服務程式是否在指定埠進行監聽,讓你的指令碼在一段可接受的時間段後超時,允許你適當地對出錯情況進行處理。如果你修改了預設埠3306,請保證對埠號進行修改。

結論和意見
  首先,要確定得到了一個完整的資料快照。如果忘記複製一個表或資料庫將導致備機執行緒序停止。生成快照的時刻是很關健的。你應該確保在複製資料檔案之前二進位制日誌功能是無效的。如果在得到快照之前就允許了二進位制日誌功能,備機的執行緒可能會停止,原因就是當執行緒試圖匯入重要的記錄時,可能會由於主鍵重複而停止。最好就是接照第二部分所討論的處理辦法來做:關閉-複製-允許二進位制日誌功能重啟。

  你可能想要按照最初的一種方式來配製複製處理,並且在合適的時間關注備機,確保備機與主機保持同步。

  我沒有測試過一個使用了複製特性的系統的負載平衡處理效能,但是我會靈活地使用這樣系統來平衡插入和更新。例如,如果在兩臺伺服器上兩條記錄都給出了同一個auto_increment值,這種情況備機執行緒會在哪一條記錄上停掉呢?象這樣的問題將會讓負載平衡作為只讀的處理,一臺伺服器處理所有的插入和更新,同時一組備機(是的,你可以有多個與主機分離的備機)處理所有的選擇。

  我非常高興,MySQL已經具備了複製系統的某些功能,並且配置很簡單。使用它,你就可以開始針對失控的事件提供額外的安全措施了。我僅僅涉及了複製特性,這個我已經測試並且使用了,但是在MySQL的線上文件中的第11部分有中更詳細的說明。



--------------------------------------------------------------------------------

譯者的話:

  由於我原來使用的是3.22版的MySQL,所以為了測試一下我只好下載了3.23.24版的最新程式。而且因為只有一臺機器,我只是增加了二進位制日誌的設定。不過,正如本文所說,的確有檔案生成。如果大家對此感興趣只好請自行測試了。另外,在最新的MySQL的使用手冊中,我發現這個複製功能是在3.23.15版以後才有的,請大家檢查自已的MySQL的版本。同時,文中關於二進位制日誌的設定是說在my.cnf中設定的。在我使用的3.23.24版本中,手冊上說可以有三個檔案進行引數設定,分別為windows目錄下的my.ini檔案,c:my.cnf和c:mysqldatamy.cnf中可以設定。我在設定log-bin時(不需要先設log引數)是使用mysql自帶的
WinMySQLadmin軟體進行設定的,並且在my.ini中設定的,與文中不同,請大家自行測試。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617731/viewspace-950261/,如需轉載,請註明出處,否則將追究法律責任。

相關文章