mysql 複製 等技巧

概述

首先主服務器把數據變化記錄到主日誌,然後從服務器通過I/O線程讀取主服務器上的主日誌,並且把它寫入到從服務器的中繼日誌中,接着SQL線程讀取中繼日誌,並且在從服務器上重放,從而實現MySQL複製。具體如下圖所示:

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_binloginnodb_flush_log_at_trx_commitinnodb_support_xa三個選項都是出於安全目的設置的,不是複製的必須選項,但如果沒設置的話,一旦主服務器宕機,數據可能來不及寫入磁盤,從而導致從服務器在複製過程中出現類似下面的錯誤:

  • Client requested master to start replication from impossible position

因爲日誌數據已經丟失了,所以此類問題基本上不能處理,只能重新安裝同步從服務器。

接下來設置從服務器配置文件(缺省:/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

當然,整個過程也可以利用管道符一次性操作:

shell> mysqldump --host=<MASTER_HOST> ... | mysql --host=<SLAVE_HOST> ...

因爲我們開始設置了master-data=1,所以系統會自動設置參數:MASTER_LOG_FILE和MASTER_LOG_POS,我們還需要設置剩下的參數:

mysql> CHANGE MASTER TO
       MASTER_HOST='<MASTER_HOST>',
       MASTER_USER='<SLAVE_USER>',
       MASTER_PASSWORD='<SLAVE_PASSWORD>';

如果數據量很大的話,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: Yes
  • Slave_SQL_Running: Yes

如果顯示No,則說明某些配置步驟有問題,請重新對照一遍前面所說的步驟。

故障

問題:主從複製不止何故停止了,我該怎麼辦?

答案:複製錯誤多半是因爲日誌錯誤引起的,所以首先要搞清楚是主日誌錯誤還是中繼日誌錯誤,從錯誤信息裏一般就能判斷,如果不能可以使用類似下面的mysqlbinlog命令:

shell> mysqlbinlog <MASTER_BINLOG_FILE> > /dev/null
shell> mysqlbinlog <RELAY_BINLOG_FILE> > /dev/null

如果沒有錯誤,則不會有任何輸出,反之如果有錯誤,則會顯示出來。

如果是主日誌錯誤,需要手動找到正確的日誌信息,重新CHANGE MASTER TO即可:

mysql> CHANGE MASTER TO
       MASTER_LOG_FILE='<GOOD_LOG_FILE>',
       MASTER_LOG_POS=<GOOD_LOG_POS>;
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,參見概述。

有時候由於BUG或者在從服務器執行了寫操作可能會造成鍵重複錯誤,錯誤信息如下:

  • Error ‘Duplicate entry …’ for key … on query

此時最好手動確認並刪除從服務器上的無效數據,然後從主服務器複製正確數據,如果錯誤仍然不能解決,可以在從服務器使用SET GLOBAL sql_slave_skip_counter,如下:

mysql> SET GLOBAL sql_slave_skip_counter = 1;
mysql> START SLAVE;

注:如果有多個錯誤,可能需要執行多次(提醒:主從服務器數據可能因此不一致,遇到這樣的情況可以使用pt-table-checksumpt-table-sync檢查並修復從服務器數據)。

問題:主服務器宕機了,如何把從服務器提升會主服務器?

答案:在一主多從的環境總,需選擇數據最新的從服務器做新的主服務器。如下圖所示:

提升從服務器爲主服務器

提升從服務器爲主服務器

在一主(Server1)兩從(Server2,、Server3)環境中,Server1宕機後,等到Server2和Server3把宕機前同步到的日誌都執行完,比較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有靜態表一說。

主從服務器中的表可以使用不同的索引。主服務器主要用來應付寫操作,所以除了主鍵和唯一索引等保證數據關係的索引一般都可以不加,從服務器用來應付讀操作,所以可以針對查詢特徵設置索引,甚至不同的從服務器可以針對不同的查詢設置不同的索引

發佈了165 篇原創文章 · 獲贊 18 · 訪問量 99萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章