mysql的擴展性設計之主輔架構

原創文章,轉載請註明:上善若水 http://www.usewo.com/ 或 http://mysuim.iteye.com

 

引言

由於mysql的master/slave架構各方面優良的特性,使得在各種互聯網應用中被廣泛應用。它主要用於解決兩方面的問題,即數據的冗餘備 份和性能擴展。本文主要講解以下幾個問題:master/slave的實現原理、系統搭建、實際場景中的各種架構,以及日常管理維護和一些問題的解決和思 路。

實現原理

實現主輔架構,使用的是mysql的複製(replication)這個特性。這個特性使得可以把一個mysql服務器(master)上的數據改 變實時的傳送到另一個mysql服務器(slave)上,這個過程是異步進行的。整個複製的過程通過mysql的3個線程來完成,其中一個是master 上的IO線程,另外兩個是slave上的IO線程和SQL線程。我們首先要打開master服務器的bin-log功能,打開這個功能後,在master 上面執行的DML操作語句都會記錄在二進制日誌裏面,mysql的主輔架構就是讓slave服務器通過讀取這些日誌並執行來保證兩臺服務器的數據同步。

mysql複製的過程如下:
(1) slave的IO線程不斷的連接master服務器,請求指定的日誌文件的指定位置的內容。讀取哪個日誌文件、從哪個位置開始讀取,這些參數都存儲在slave服務器上。

(2) master接到請求後,負責複製的IO線程就去讀取指定位置的日誌再返回給slave的IO線程,除此之外返回的信息還會包括新的日誌文件名稱(如果上一個日誌文件寫滿的話)和新的位置。

(3) slave的IO線程接到返回的信息後,將日誌內容寫入relay log文件,新的日誌文件名稱和新的位置寫入到本地的配置文件(master-info)。

(4) slave的sql線程不斷的檢測relay log,當發生變化的時候,會馬上解析該文件,還原成可執行query語句並執行。實際上,master和slave執行了同樣的query,所以兩端的數據是一致的。


系統搭建

我們這裏把系統的搭建分爲這幾步,首先是master端的準備工作;然後倒出master的數據到slave,保證slave的數據和master 一致;slave端的設置。首先要準備兩臺服務器,一臺做爲master(192.168.0.245),另一臺作爲 slave(192.168.0.246),並且都已經安裝上了相同版本的mysql。

master端的準備工作:

(1)  配置my.cnf文件
首先打開log-bin選項:log-bin=mysql-bin
設置server-id:默認配置可能已經有這個server-id了,只需要取消註釋即可,值要唯一,不能和slave的server-id一樣,例如server-id = 1
重啓mysql服務器。

(2)  創建一個賬戶,slave會使用到這個帳號來連接master。
GRANT REPLICATION rep ON *.* TO ‘replication’@'%’ IDENTIFIED BY ’123456′;

倒出數據,獲取當前日誌文件和指定位置

(1)  flush tables with read lock;

(2) 此時再打開一個終端,用mysqldump將數據倒出:

mysqldump -h192.168.0.245(master的ip) -uexample -p –all-database > example.sql;

(3) show master status;
show-master-status

File的值和Position的值要記下來,初始化slave的時候需要用到 。

(4) unlock tables;

slave端的設置

(1) 首先檢查my.cnf的設置,如果打開了server-id選項,看看它的值是否和master的server-id是否一樣,一樣的話一定要修改然後重啓mysql服務器。

(2) 導入數據,使得slave端的原始數據和master保持一致。

mysql  -uxxx -p < example.sql

(3) 初始化配置

CHANGE MASTER TO MASTER_HOST=’192.168.0.245′,
MASTER_PORT=3306,MASTER_USER=’replication’,
MASTER_PASSWORD=’123456′,
MASTER_LOG_FILE=’mysql-bin.000018′,
MASTER_LOG_POS=503;

(4) 啓動slave線程:START SLAVE;

檢查是否成功:執行show slave status;   主要查看Slave_IO_Running、Slave_SQL_Running這兩個選項的值,如果都爲yes則說明大功告成,如果有一個爲no則說明失敗,我會在文章的後面給出可能的解決方法。


實際場景中的各種主輔架構

最普通的互聯網應用使用上一步的方式搭建就可以滿足了,不過現實環境中有各種各樣的業務需求,我們一樣可以利用mysql的replication特性,搭建出更多更合適的主輔架構,如s雙向複製架構、級聯複製架構。

常規主輔架構(master-slaves)

也就是一主多從架構,也是使用最普遍的一種架構,見下圖:master-slaves

伴隨着master-slaves的通常是讀寫分離策略。在web應用中,隨着數據的不斷膨脹,數據庫方面自然出現了瓶頸,一般會面臨着大量的讀取和寫入操作,而通常情況下讀操作都會比寫操作更密集,通過讀寫分離策略可以在很大程度上解決這樣的問題。

我們必須讓所有寫入更新操作都在master上執行,這是讀寫分離策略需要遵循的最基本原則,而讀操作都指向了slave。

master-slaves2

一旦使用了讀寫分離後,應用程序的代碼就需要修改,主要是修改數據訪問層的代碼,一定程度上也就造成了數據訪問層的代碼複雜度。其實也可以做到不修 改或少量修改代碼,這時候需要用到一箇中間代理,應該程序直接訪問這個代理服務器,就像以前訪問mysql一樣,讀寫分離需要配置到代理服務器上。目前可 以使用的開源中間代理有mysql proxy和amoeba for mysql,其中amoeba是中國一個開發者開發的,目前已經一些企業嘗試着在使用,我試用過,確實很方便,抽空再寫一篇介紹amoeba的文章。

雙向複製架構(master-master)

雙向複製架構也就是說,A服務器作爲B服務器的master的同時,也是B的slave,B也同理。

爲什麼會有這樣的架構呢?比方說,有時候master可能需要做一些特別的維護必須停止,如果你只有一臺master就不太好辦了,或者你的master宕機了呢,於是乎就衍生出了雙向複製這種架構。

如果你擔心採用雙向複製會發生循環複製的話,大可不必了,因爲每個mysql都會有一個唯一的server-id,mysql很容易判斷某個變更是從那個一個mysql服務器最初產生的。

雙向架構的搭建也很容易,一般的結構如下圖:

dual-master_conew1

如何搭建這裏就不詳細寫了,方法在“系統搭建”已經寫過,只不過雙向master架構,需要多執行幾步操作而已。

實際使用中可能只會提供一臺master供應用程序寫操作,因爲如果同時提供外部讀寫的話,在某些情況下可能出現錯誤。

級聯複製(master-slaves-slaves)

在實際場景中,也許讀寫壓力比較大,讀壓力特別的大,假如一個master需要10臺slave才能支撐,這時候master就會比較吃力,因爲連接上來的slave IO線程就會比較多,很容易造成複製的延遲。

那怎麼辦呢?這裏就可以使用到級聯複製,那什麼又是級聯複製呢?我們這裏把最上層的master稱之爲頂級master,把從屬於頂級master 的slaves稱之爲第一級slaves,而第一級slaves同時又做爲master,提供給第二級的slaves進行復制。如下圖:

cascade-master-slave_conew2

要搭建這種結構,需要打開第一級的log-slave-update選項。這樣的結構就解決了頂級master附屬了太多slave造成的問題。

這種架構也有一些不好的地方,比如數據從頂級master傳送到第二級slaves需要經過的mysql更多了,當然風險就更大了。實際使用中還可以通過拆分成多個集羣來解決。


主輔架構的管理維護

查看slave的狀態,確認slave是否工作正常

SHOW SLAVE STATUS\G;

正常情況下可以顯示這樣的結果:

Slave_IO_Running: Yes        Slave_SQL_Running: Yes

Slave_IO_Running:此線程負責slave從master服務器上讀取binlog日誌,並寫入slave服務器上的relay log中。
Slave_SQL_Running:此線程負責讀取並且執行relay log中的binlog日誌
只要其中有一個進程的狀態是no,則表示複製進程停止,錯誤原因可以從Last_Errno後面看到。

IO線程停止的幾種情況

網絡不通了、配置slave同步時因爲slave訪問master沒有權限導致、master上的mysql-bin.xxxxxx文件被誤刪除了。如果是master二進制日誌被刪除了,可以採取下面的方式解決:

(1) 重啓master:service mysqld restart

show master status; 【獲取二進制文件名和位置】

(2) 在slave上執行以下sql:

slave stop;
change master to Master_Log_File=’mysql-bin.****’,Master_Log_Pos=**;
slave start;
show slave status;

強制slave立即和master保持同步

master/slave架構經過長時間運行,可能造成slave延遲的情況,這會造成很不好的結果,所以需要我們手動的強制讓他們保持一致。步驟如下:

(1) 在master上執行以下操作

mysql> FLUSH TABLES WITH READ LOCK;
mysql> SHOW MASTER STATUS;

記錄SHOW語句的輸出的日誌名和偏移量。這些是複製座標。

(2) 在從服務器上執行以下操作

mysql> SELECT MASTER_POS_WAIT(‘log_name’, log_offset);

SELECT語句阻塞直到從服務器達到指定的日誌文件和偏移量。此時,從服務器與主服務器同步,語句返回。

(3) 在master執行解鎖操作,unlock tables;

在master執行的sql語句在slave上卻執行失敗的一種解決方法

這樣的問題通常會導致SQL線程停止,可以用下面的步驟試着解決。

(1) 確定是否從服務器的表與主服務器的不同。盡力瞭解發生的原因。然後讓從服務器的表與主服務器的一樣並運行START SLAVE。

(2) 如果前面的步驟不工作或不適合,盡力瞭解手動更新是否安全(如果需要),然後忽視來自主服務器的下一個語句。如果你確定可以跳過來自主服務器的下一個語句,執行下面的語句:
SET GLOBAL SQL_slave_SKIP_COUNTER = n;
START SLAVE;

如果來自主服務器的下一個語句不使用AUTO_INCREMENT或LAST_INSERT_ID(),n 值應爲1。否則,值應爲2。使用AUTO_INCREMENT或LAST_INSERT_ID()的語句使用值2的原因是它們從主服務器的二進制日誌中取兩個事件。

其他問題

其外,在複製實施的過程中還可能遇到很多問題,或者很多不明白的地方,目前最有效的手段就是去看mysql手冊,那裏面的介紹應該說是最詳細的了,我在這裏介紹的一些知識,也是從手冊看來的。mysql手冊的第六章就是複製的完整介紹。我在下面隨便列舉幾個問題。

Q :我怎樣知道從服務器與主服務器的最新比較? 換句話說,我怎樣知道從服務器複製的最後一個查詢的日期?

A :你可以查看SHOW SLAVE STATUS語句的Seconds_Behind_Master列的結果。

當從服務器SQL線程執行從主服務器讀取的事件時,它根據事件時間戳修改自己的時間(這是TIMESTAMP能夠很好複製的原因)。在 SHOW PROCESSLIST語句輸出的Time列內,爲從服務器SQL線程顯示的秒數是最後一個複製事件的時間戳和從服務器主機的實際時間之間相差的秒數。你 可以使用它來確定最後一個複製事件的日期。注意,如果你的從服務器與主服務器連接斷開一個小時,然後重新連接,在SHOW PROCESSLIST結果中,你可以立即看到從服務器SQL線程的Time值爲3600。這可能是因爲從服務器執行的語句是一個一小時之前的。

Q :從服務器需要始終連接到主服務器嗎?

A :不,不需要。從服務器可以宕機或斷開連接幾個小時甚至幾天,重新連接後獲得更新信息。例如,你可以 在通過撥號的鏈接上設置主服務器/從服務器關係,其中只是偶爾短時間內進行連接。這意味着,在任何給定時間,從服務器不能保證與主服務器同步除非你執行某 些特殊的方法。將來,我們將使用選項來阻塞主服務器直到有一個從服務器同步。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章