MySQL 二進制日誌是進行主從複製的基礎,它記錄了全部對 MySQL 數據庫的修改事件,包括增刪改查和表結構修改。當前 MySQL 一共支持三種二進制日誌格式,能夠經過 binlog-format 參數來進行控制,其可選值以下:html
一般在主備之間網絡狀況良好的時,能夠優先考慮使用 ROW 格式,此時數據一致性最高,其次是 MIXED 格式。在設置 ROW 格式時,還有一個很是重要的參數 binlog_row_image :mysql
binlog_row_image 有如下三個可選值:git
full:默認值,記錄行在修改先後全部列的值。github
minimal:只記錄修改涉及列的值。sql
noblob:與 full 相似,但若是 BLOB 或 TEXT 列沒有修改,則不對其進行記錄。shell
binlog-format 和 binlog_row_image 的默認值可能在不一樣版本存在差別,可使用如下命令進行查看。一般狀況下,爲了減小在主備複製中須要傳輸的數據量,能夠將 binlog_row_image 的值設置爲 minimal 或 noblob。數據庫
show variables like 'binlog_format';
show variables like 'binlog_row_image';
複製代碼
MySQL 的複製原理以下圖所示:segmentfault
若是沒有進行任何配置,主庫在將變動寫入到二進制日誌後,就會返回對客戶端的響應,所以默認狀況下的複製是徹底異步進行的,主備之間可能會短暫存在數據不一致的狀況。安全
首先主節點須要開啓二進制日誌,而且在同一個複製環境下,主備節點的 server-id 須要不同:bash
[mysqld]
server-id = 226
# 開啓二進制日誌
log-bin=mysql-bin
複製代碼
在備份節點配置中繼日誌:
[mysqld]
server-id = 227
# 配置中繼日誌
relay_log = mysql-relay-bin
# 爲了保證數據的一致性,從節點應該設置爲只讀
read_only = 1
# 如下兩個配置表明是否開啓二進制日誌,若是該從節點還做爲其餘備庫的主節點,則開啓,不然不用配置
log-bin = mysql-bin
# 是否將中繼節點收到的複製事件寫到本身的二進制日誌中
log_slave_updates = 1
複製代碼
登陸主節點 MySQL 服務,建立用於進行復制帳號,併爲其授予權限:
CREATE USER 'repl'@'192.168.0.%' IDENTIFIED WITH mysql_native_password BY '123456';
GRANT REPLICATION SLAVE on *.* TO 'repl'@'192.168.0.%' ;
複製代碼
查看主節點二進制日誌的狀態:
mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 887 | | | |
+------------------+----------+--------------+------------------+-------------------+
複製代碼
基於日誌和偏移量,創建複製鏈路:
CHANGE MASTER TO MASTER_HOST='192.168.0.226',\
MASTER_USER='repl', \
MASTER_PASSWORD='123456',\
MASTER_LOG_FILE='mysql-bin.000001',\
MASTER_LOG_POS=887;
複製代碼
開始複製:
START SLAVE;
複製代碼
查看從節點複製狀態,主要參數有 Slave_IO_Running 和 Slave_SQL_Running,其狀態都爲 Yes 表示用於複製的 IO 進程已經開啓。Seconds_Behind_Master 參數表示從節點複製的延遲量。此時能夠在主庫上進行任意更改,並在備庫上查看狀況。
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.0.226
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 887
Relay_Log_File: mysql-relay-bin.000002
Relay_Log_Pos: 322
Relay_Master_Log_File: mysql-bin.000001
# Slave_IO_Running: Yes
# Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 887
Relay_Log_Space: 530
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
# Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 226
# Master_UUID: e1148574-bdd0-11e9-8873-0800273acbfd
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
Master_public_key_path:
Get_master_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
複製代碼
基於二進制日誌的複製是 MySQL 最先使用的複製技術,所以 MySQL 對其的支持比較完善,對執行修改的 SQL 語句幾乎沒有任何限制。其主要的缺點是在一主多從的高可用複製架構中,若是主庫發生宕機,此時想要自動經過從庫的日誌和偏移量來肯定新的主庫比較困難。
MySQL 5.6 版本以後提供了一個新的複製模式:基於 GTID 的複製。GTID 全稱爲 Global Transaction ID,即全局事務 ID。它由每一個服務節點的惟一標識和其上的事務 ID 共同組成,格式爲: server_uuid : transaction_id 。經過 GTID ,能夠保證在主庫上的每個事務都能在備庫上獲得執行,不會存在任何疏漏。
主從服務器均增長如下 GTID 的配置:
gtid-mode = ON
# 防止執行不受支持的語句,下文會有說明
enforce-gtid-consistency = ON
複製代碼
若是配置過上面的基於二進制日誌的複製,還須要在從服務器上執行如下命令,關閉原有複製鏈路:
STOP SLAVE IO_THREAD FOR CHANNEL '';
複製代碼
創建新的基於 GTID 複製鏈路,指定 MASTER_AUTO_POSITION = 1
表示由程序來自動確認開始同步的 GTID 的位置:
CHANGE MASTER TO MASTER_HOST='192.168.0.226',\
MASTER_USER='repl',
MASTER_PASSWORD='123456',
MASTER_AUTO_POSITION=1;
複製代碼
開始複製:
START SLAVE;
複製代碼
在主節點上執行任意修改操做,並查看從節點狀態,關鍵的輸出以下:Retrieved_Gtid_Set 表明從主節點上接收到的兩個事務,Executed_Gtid_Set 表示這兩個事務已經在從庫上獲得執行。
mysql> SHOW SLAVE STATUS\G
....
Master_UUID : e1148574-bdd0-11e9-8873-0800273acbfd
Retrieved_Gtid_Set : e1148574-bdd0-11e9-8873-0800273acbfd:1-2
Executed_Gtid_Set : e1148574-bdd0-11e9-8873-0800273acbfd:1-2
.....
複製代碼
GTID 複製的優勢在於程序能夠自動確認開始複製的 GTID 點。但其仍然存在如下限制:
不支持 CREATE TABLE ... SELECT 語句。 由於在 ROW 格式下,該語句將會被記錄爲具備不一樣 GTID 的兩個事務,此時從服務器將沒法正確處理。
事務,過程,函數和觸發器內部的 CREATE TEMPORARY TABLE 和 DROP TEMPORARY TABLE 語句均不受支持。
爲防止執行不受支持的語句,建議配置和上文配置同樣,開啓 enforce-gtid-consistency 屬性, 開啓後在主庫上執行以上不受支持的語句都將拋出異常並提示。
在上面咱們介紹過,不管是基於二進制日誌的複製仍是基於 GTID 的複製,其本質上都是異步複製,假設從節點尚未獲取到二進制日誌信息時主節點就宕機了,那麼就會存在數據不一致的問題。想要解決這個問題能夠經過配置半同步複製來實現:進行半同步複製時,主節點會等待至少一個從節點獲取到二進制日誌後纔將事務的執行結果返回給客戶端。具體配置步驟以下:
MySQL 從 5.5 以後開始以插件的形式支持半同步複製,因此先須要先進行插件的安裝,命令以下:
-- 主節點上執行
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
-- 從節點上執行
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
複製代碼
若是你的複製是基於高可用架構的,即從節點可能會在主節點宕機後成爲新的主節點,而原主節點可能在失敗恢復後成爲從節點,那麼爲了保證半同步複製仍然有效,此時能夠在主從節點上都安裝主從插件。安裝後使用如下命令查看是否安裝成功:
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE '%semi%';
+----------------------+---------------+
| PLUGIN_NAME | PLUGIN_STATUS |
+----------------------+---------------+
| rpl_semi_sync_master | ACTIVE |
| rpl_semi_sync_slave | ACTIVE |
+----------------------+---------------+
複製代碼
半同步複製能夠基於日誌複製或 GTID 複製開啓,只須要在其原有配置上增長如下配置:
# 主節點上增長以下配置:
plugin-load=rpl_semi_sync_master=semisync_master.so
rpl_semi_sync_master_enabled=1
# 從節點上增長以下配置:
plugin-load=rpl_semi_sync_slave=semisync_slave.so
rpl_semi_sync_slave_enabled=1
# 和上面提到的同樣,若是是高可用架構下,則主從節點均可以增長主從配置:
plugin-load = "rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so"
rpl-semi-sync-master-enabled = 1
rpl-semi-sync-slave-enabled = 1
複製代碼
按照二進制日誌或 GTID 的方式正常啓動複製便可,此時可使用以下命令查看半同步日誌是否正在執行:
# 主節點
mysql> SHOW STATUS LIKE 'Rpl_semi_sync_master_status';
+-----------------------------+-------+
| Variable_name | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_status | ON |
+-----------------------------+-------+
# 從節點
mysql> SHOW STATUS LIKE 'Rpl_semi_sync_slave_status';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON |
+----------------------------+-------+
複製代碼
值爲 ON 表明半同步複製配置成功。
半同步日誌還有如下兩個可選配置:一個是 rpl_semi_sync_master_wait_for_slave_count
,它表示主節點須要至少等待幾個從節點複製完成,默認值爲 1,由於等待過多從節點可能會致使長時間的延遲,因此一般使用默認值便可。另外一個經常使用參數是 rpl_semi_sync_master_wait_point
,它主要是用於控制等待的時間點,它有如下兩個可選值:
第二種方式是 MySQL 5.7.2 以前默認方式,但這種方式會致使數據的丟失,因此在 5.7.2 版本後就引入了第一種方式做爲默認方式,它能夠實現無損複製 (lossless replication),數據基本無丟失,所以 rpl_semi_sync_master_wait_point
參數一般也不用進行修改,採用默認值便可。想要查看當前版本該參數的值,可使用以下命令:
mysql> SHOW VARIABLES LIKE 'rpl_semi_sync_master_wait_point';
+---------------------------------+------------+
| Variable_name | Value |
+---------------------------------+------------+
| rpl_semi_sync_master_wait_point | AFTER_SYNC |
+---------------------------------+------------+
複製代碼
雖然半同步複製可以最大程度的避免數據的丟失,可是由於網絡通信會致使額外的等待時間的開銷,因此儘可能在低延遲的網絡環境下使用,如處於同一機房的主機之間。
不管是主主複製結構,仍是一主多從複製結構,單存依靠複製只能解決數據可靠性的問題,並不能解決系統高可用的問題,想要保證高可用,系統必須可以自動進行故障轉移,即在主庫宕機時,主動將其它備庫升級爲主庫。經常使用的有如下兩種解決方案:
MMM (Master-Master replication manager for MySQL) 是由 Perl 語言開發的一套支持雙主故障切換以及雙主平常管理的第三方軟件。它包含兩類角色:writer
和 reader
,分別對應讀寫節點和只讀節點。使用 MMM 管理的雙主節點在同一時間上只容許一個進行寫入操做,當 writer
節點出現宕機(假設是 Master1),程序會自動移除該節點上的讀寫 VIP,而後切換到 Master2 ,並設置 Master2 的 read_only = 0,即關閉只讀限制,同時將全部 Slave 節點從新指向 Master2。
除了管理雙主節點,MMM 也負責管理全部 Slave節點,在出現宕機、複製延遲或複製錯誤,MMM 會移除該節點的 VIP,直至節點恢復正常。MMM 高可用的架構示例圖以下:
MMM 架構的缺點在於雖然其能實現自動切換,但卻不會主動補齊丟失的數據,因此會存在數據不一致性的風險。另外 MMM 的發佈時間比較早,因此其也不支持 MySQL 最新的基於 GTID 的複製,若是你使用的是基於 GTID 的複製,則只能採用 MHA。
MHA (Master High Availability) 是由 Perl 實現的一款高可用程序,相對於 MMM ,它能儘可能避免數據不一致的問題。它監控的是一主多從的複製架構,架構以下圖所示:
在 Master 節點宕機後,其處理流程以下:
按照以上的處理流程,MHA 可以最大程序的避免數據不一致的問題。但若是 Master 所在的服務器也宕機了,那麼過程的第一步就會失敗。在 MySQL 5.5 後,能夠開啓半同步複製後來避免這個問題,從而能夠保證數據的一致性和幾乎無丟失。固然 MHA 集羣也存在一下一些缺點:
以上就是 MMM 和 MHA 架構的簡單介紹,關於其具體搭建步驟,能夠參考如下兩篇博客: MySQL集羣搭建(3)-MMM高可用架構 和 MySQL集羣搭建(5)-MHA高可用架構。
更多文章,歡迎訪問 [全棧工程師手冊] ,GitHub 地址:github.com/heibaiying/…