先來看mysql5.6主從同步操作時遇到的一個報錯:
mysql> change master to master_host='192.168.10.59',master_user='repli',master_password='repli@123',master_log_file='mysql-bin.000004',master_log_pos=49224392;
ERROR 1776 (HY000): Parameters MASTER_LOG_FILE, MASTER_LOG_POS, RELAY_LOG_FILE and RELAY_LOG_POS cannot be set when MASTER_AUTO_POSITION is active.
產生原因:主從數據庫雙方都開啟了gtid功能(通過命令"show variables like '%gtid%';"查看),gtid功能是mysql5.6版本出來的新特性!
解決辦法:
1)方法一: 提前執行下面語句
mysql> change master to master_auto_position=1;
mysql> change master to master_host='192.168.10.59',master_user='repli',master_password='repli@123',master_log_file='mysql-bin.000004',master_log_pos=49224392;
2)方法二: 在change語句后面添加
mysql> change master to master_host='192.168.10.59',master_user='repli',master_password='repli@123',master_port=3306,master_auto_position=1;
一、GTID概念介紹
GTID即全局事務ID (global transaction identifier), 其保證為每一個在主上提交的事務在復制集群中可以生成一個唯一的ID。GTID最初由google實現,官方MySQL在5.6才加入該功能。mysql主從結構在一主一從情況下對於GTID來說就沒有優勢了,而對於2台主以上的結構優勢異常明顯,可以在數據不丟失的情況下切換新主。使用GTID需要注意: 在構建主從復制之前,在一台將成為主的實例上進行一些操作(如數據清理等),通過GTID復制,這些在主從成立之前的操作也會被復制到從服務器上,引起復制失敗。也就是說通過GTID復制都是從最先開始的事務日志開始,即使這些操作在復制之前執行。比如在server1上執行一些drop、delete的清理操作,接着在server2上執行change的操作,會使得server2也進行server1的清理操作。
GTID實際上是由UUID+TID (即transactionId)組成的。其中UUID(即server_uuid) 產生於auto.conf文件(cat /data/mysql/data/auto.cnf),是一個MySQL實例的唯一標識。TID代表了該實例上已經提交的事務數量,並且隨着事務提交單調遞增,所以GTID能夠保證每個MySQL實例事務的執行(不會重復執行同一個事務,並且會補全沒有執行的事務)。GTID在一組復制中,全局唯一。 下面是一個GTID的具體形式 :
mysql> show master status; +-----------+----------+--------------+------------------+-------------------------------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +-----------+----------+--------------+------------------+-------------------------------------------+ | on.000003 | 187 | | | 7286f791-125d-11e9-9a9c-0050568843f8:1-362| +-----------+----------+--------------+------------------+-------------------------------------------+ 1 row in set (0.00 sec) GTID:7286f791-125d-11e9-9a9c-0050568843f8:1-362 UUID:7286f791-125d-11e9-9a9c-0050568843f8 transactionId:1-362 在整個復制架構中GTID 是不變化的,即使在多個連環主從中也不會變。 例如:ServerA --->ServerB ---->ServerC GTID從在ServerA ,ServerB,ServerC 中都是一樣的。
了解了GTID的格式,通過UUID可以知道這個事務在哪個實例上提交的。通過GTID可以極方便的進行復制結構上的故障轉移,新主設置,這就很好地解決了下面這個圖所展現出來的問題。

如圖, Server1(Master)崩潰,根據從上show slave status獲得Master_log_File/Read_Master_Log_Pos的值,Server2(Slave)已經跟上了主,Server3(Slave)沒有跟上主。這時要是把Server2提升為主,Server3變成Server2的從。這時在Server3上執行change的時候需要做一些計算。
這個問題在5.6的GTID出現后,就顯得非常的簡單。由於同一事務的GTID在所有節點上的值一致,那么根據Server3當前停止點的GTID就能定位到Server2上的GTID。甚至由於MASTER_AUTO_POSITION功能的出現,我們都不需要知道GTID的具體值,直接使用CHANGE MASTER TO MASTER_HOST='xxx', MASTER_AUTO_POSITION命令就可以直接完成failover的工作。
====== GTID和Binlog的關系 ======
- GTID在binlog中的結構

- GTID event 結構

- Previous_gtid_log_event
Previous_gtid_log_event 在每個binlog 頭部都會有每次binlog rotate的時候存儲在binlog頭部Previous-GTIDs在binlog中只會存儲在這台機器上執行過的所有binlog,不包括手動設置gtid_purged值。換句話說,如果你手動set global gtid_purged=xx; 那么xx是不會記錄在Previous_gtid_log_event中的。
- GTID和Binlog之間的關系是怎么對應的呢? 如何才能找到GTID=? 對應的binlog文件呢?
假設有4個binlog: bin.001,bin.002,bin.003,bin.004
bin.001 : Previous-GTIDs=empty; binlog_event有: 1-40
bin.002 : Previous-GTIDs=1-40; binlog_event有: 41-80
bin.003 : Previous-GTIDs=1-80; binlog_event有: 81-120
bin.004 : Previous-GTIDs=1-120; binlog_event有: 121-160
假設現在我們要找GTID=$A,那么MySQL的掃描順序為:
- 從最后一個binlog開始掃描(即: bin.004)
- bin.004的Previous-GTIDs=1-120,如果$A=140 > Previous-GTIDs,那么肯定在bin.004中
- bin.004的Previous-GTIDs=1-120,如果$A=88 包含在Previous-GTIDs中,那么繼續對比上一個binlog文件 bin.003,然后再循環前面2個步驟,直到找到為止.
====== GTID 重要參數的持久化 =======
- GTID相關參數

- 重要參數如何持久化
1) 如何持久化gtid_executed (前提是log-bin=mysql-bin, log_slave_update=1 )
gtid_executed = mysql.gtid_executed #正常情況下 或者 gtid_executed = mysql.gtid_executed + last_binlog中最后沒寫到mysql.gtid_executed中的gtid_event #恢復情況下
2) 如何持久化重置的gtid_purged值?
reset master; set global gtid_purged=$A:a-b; ================================================================================================ 1. 由於有可能手動設置過gtid_purged=$A:a-b, binlog.index中,last_binlog的Previous-GTIDs並不會包含$A:a-b 2. 由於有可能手動設置過gtid_purged=$A:a-b, binlog.index中,first_binlog的Previous-GTIDs肯定不會出現$A:a-b 3. 重置的gtid_purged = @@global.gtid_executed(mysql.gtid_executed:注意,考慮到這個表的更新觸發條件,所以這里 用@@global.gtid_executed代替) - last_binlog的Previous-GTIDs - last_binlog所有的gtid_event 4. 下面就用 $reset_gtid_purged 來表示重置的gtid
3) 如何持久化gtid_purged (前提是log-bin=mysql-bin, log_slave_update=1 )
gtid_purged=binlog.index:first_binlog的Previous-GTIDs + $reset_gtid_purged
====== 開啟GTID的必備條件 ======
- MySQL 5.6 版本,在my.cnf文件中添加:
gtid_mode=on (必選) #開啟gtid功能 log_bin=log-bin=mysql-bin (必選) #開啟binlog二進制日志功能 log-slave-updates=1 (必選) #也可以將1寫為on enforce-gtid-consistency=1 (必選) #也可以將1寫為on
- MySQL 5.7或更高版本,在my.cnf文件中添加:
gtid_mode=on (必選) enforce-gtid-consistency=1 (必選) log_bin=mysql-bin (可選) #高可用切換,最好開啟該功能 log-slave-updates=1 (可選) #高可用切換,最好打開該功能
====== 新的復制協議 COM_BINLOG_DUMP_GTID ======
- Slave sends to master range of identifiers of executed transactions to master
- Master send all other transactions to slave
- 同樣的GTID不能被執行兩次,如果有同樣的GTID,會自動被skip掉。

slave1 : 將自身的UUID1:1 發送給 master,然后接收到了 UUID1:2,UUID1:3 event
slave2 : 將自身的UUID1:1,UUID1:2 發送給 master,然后接收到了UUID1:3 event
Binlog dump
最開始的時候,MySQL只支持一種binlog dump方式,也就是指定binlog filename + position,向master發送COM_BINLOG_DUMP命令。在發送dump命令的時候,我們可以指定flag為BINLOG_DUMP_NON_BLOCK,這樣master在沒有可發送的binlog event之后,就會返回一個EOF package。不過通常對於slave來說,一直把連接掛着可能更好,這樣能更及時收到新產生的binlog event。在MySQL 5.6之后,支持了另一種dump方式,也就是GTID dump,通過發送COM_BINLOG_DUMP_GTID命令實現,需要帶上的是相應的GTID信息.
二、GTID的工作原理
從服務器連接到主服務器之后,把自己執行過的GTID (Executed_Gtid_Set: 即已經執行的事務編碼)<SQL線程> 、獲取到的GTID (Retrieved_Gtid_Set: 即從庫已經接收到主庫的事務編號) <IO線程>發給主服務器,主服務器把從服務器缺少的GTID及對應的transactions發過去補全即可。當主服務器掛掉的時候,找出同步最成功的那台從服務器,直接把它提升為主即可。如果硬要指定某一台不是最新的從服務器提升為主, 先change到同步最成功的那台從服務器, 等把GTID全部補全了,就可以把它提升為主了。
GTID是MySQL 5.6的新特性,可簡化MySQL的主從切換以及Failover。GTID用於在binlog中唯一標識一個事務。當事務提交時,MySQL Server在寫binlog的時候,會先寫一個特殊的Binlog Event,類型為GTID_Event,指定下一個事務的GTID,然后再寫事務的Binlog。主從同步時GTID_Event和事務的Binlog都會傳遞到從庫,從庫在執行的時候也是用同樣的GTID寫binlog,這樣主從同步以后,就可通過GTID確定從庫同步到的位置了。也就是說,無論是級聯情況,還是一主多從情況,都可以通過GTID自動找點兒,而無需像之前那樣通過File_name和File_position找點兒了。
簡而言之,GTID的工作流程為:
- master更新數據時,會在事務前產生GTID,一同記錄到binlog日志中。
- slave端的i/o 線程將變更的binlog,寫入到本地的relay log中。
- sql線程從relay log中獲取GTID,然后對比slave端的binlog是否有記錄。
- 如果有記錄,說明該GTID的事務已經執行,slave會忽略。
- 如果沒有記錄,slave就會從relay log中執行該GTID的事務,並記錄到binlog。
- 在解析過程中會判斷是否有主鍵,如果沒有就用二級索引,如果沒有就用全部掃描。
三、GTID的優缺點
GTID的優點
- 一個事務對應一個唯一ID,一個GTID在一個服務器上只會執行一次;
- GTID是用來代替傳統復制的方法,GTID復制與普通復制模式的最大不同就是不需要指定二進制文件名和位置;
- 減少手工干預和降低服務故障時間,當主機掛了之后通過軟件從眾多的備機中提升一台備機為主機;
GTID復制是怎么實現自動同步,自動對應位置的呢?
比如這樣一個主從架構:ServerC <-----ServerA ----> ServerB
即一個主數據庫ServerA,兩個從數據庫ServerB和ServerC
當主機ServerA 掛了之后 ,此時ServerB執行完了所有從ServerA 傳過來的事務,ServerC 延時一點。這個時候需要把 ServerB 提升為主機 ,Server C 繼續為備機;當ServerC 鏈接ServerB 之后,首先在自己的二進制文件中找到從ServerA 傳過來的最新的GTID,然后將這個GTID 發送到ServerB ,ServerB 獲得這個GTID之后,就開始從這個GTID的下一個GTID開始發送事務給ServerC。這種自我尋找復制位置的模式減少事務丟失的可能性以及故障恢復的時間。
GTID的缺點(限制)
- 不支持非事務引擎;
- 不支持create table ... select 語句復制(主庫直接報錯);(原理: 會生成兩個sql, 一個是DDL創建表SQL, 一個是insert into 插入數據的sql; 由於DDL會導致自動提交, 所以這個sql至少需要兩個GTID, 但是GTID模式下, 只能給這個sql生成一個GTID)
- 不允許一個SQL同時更新一個事務引擎表和非事務引擎表;
- 在一個復制組中,必須要求統一開啟GTID或者是關閉GTID;
- 開啟GTID需要重啟 (mysql5.7除外);
- 開啟GTID后,就不再使用原來的傳統復制方式;
- 對於create temporary table 和 drop temporary table語句不支持;
- 不支持sql_slave_skip_counter;
====== 那么到底為什么要用GTID呢?======
1. classic replication [傳統復制 , 運維之痛]

2. GTID replication [GTID復制,很簡單]

3. GTID的Limitation (及應對措施)
- 不安全的事務
設置enforce-gtid-consistency=1
- MySQL5.7 GTID crash-safe
1) 單線程復制 Non-GTID 推薦配置: relay_log_recovery=1 relay_log_info_repository=TABLE master_info_repository=TABLE GTID 推薦配置 MASTER_AUTO_POSITION=on relay_log_recovery=0 2) 多線程復制 Non-GTID 推薦配置: relay_log_recovery=1 sync_relay_log=1 relay_log_info_repository=TABLE master_info_repository=TABLE GTID 推薦配置: MASTER_AUTO_POSITION=on relay_log_recovery=0
====== Mysql開啟GTID時,需要注意的問題 ======
- slave不能執行任何sql,包括超級用戶;
- read_only=on, slave必須要開啟這個,避免業務執行sql;
- 保證當前slave的事務id為1;
當slave同步出現問題時,手動跳過,需要考慮的問題
- 執行的sql,不能記錄事務id,否則slave切換為master時,會導致從同步失敗,因為binglog早已刪除。
- SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;
- SET @@SESSION.SQL_LOG_BIN= 0;
需要執行的sql操作:
SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN;
查看當前數據的uuid
show GLOBAL VARIABLES like 'server_uuid';
查看當前數據庫的已執行過的事務
show master status;
手動設置事務id
SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN; SET @@SESSION.SQL_LOG_BIN= 0; SET @@GLOBAL.GTID_PURGED='132028ab-abc5-11e6-b2f0-000c29a60c3d:1-45679'; SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN;
另外還需要注意
- 開啟GTID以后,無法使用sql_slave_skip_counter跳過事務,因為主庫會把從庫缺失的GTID,發送給從庫,所以skip是沒有用的。
- 為了提前發現問題,在gtid模式下,直接禁止使用set global sql_slave_skip_counter =x。正確的做法: 通過set grid_next= 'aaaa'('aaaa'為待跳過的事務),然后執行BIGIN; 接着COMMIT產生一個空事務,占據這個GTID,再START SLAVE,會發現下一條事務的GTID已經執行過,就會跳過這個事務了
- 如果一個GTID已經執行過,再遇到重復的GTID,從庫會直接跳過,可看作GTID執行的冪等性。
四、GTID測試解析
1) 復制的測試環境
因為支持GTID,所以5.6多了幾個參數:
mysql> show variables like '%gtid%'; +----------------------------------+------------------------------------------+ | Variable_name | Value | +----------------------------------+------------------------------------------+ | binlog_gtid_simple_recovery | ON | | enforce_gtid_consistency | ON | | gtid_executed | | | gtid_executed_compression_period | 1000 | | gtid_mode | ON | | gtid_next | AUTOMATIC | | gtid_owned | | | gtid_purged | d47f31fd-eba4-11e7-af2a-56b1d2e75ff8:1-9 | | session_track_gtids | OFF | +----------------------------------+------------------------------------------+ 9 rows in set (0.00 sec)
這里簡單說下幾個常用參數的作用:
gtid_executed
在當前實例上執行過的 GTID 集合,實際上包含了所有記錄到 binlog 中的事務。設置 set sql_log_bin=0 后執行的事務不會生成 binlog 事件,也不會被記錄到 gtid_executed 中。執行 RESET MASTER 可以將該變量置空。
gtid_purged
binlog 不可能永遠駐留在服務上,需要定期進行清理(通過 expire_logs_days 可以控制定期清理間隔),否則遲早它會把磁盤用盡。gtid_purged 用於記錄本機上已經執行過,但是已經被清除了的 binlog 事務集合。它是 gtid_executed 的子集。只有 gtid_executed 為空時才能手動設置該變量,此時會同時更新 gtid_executed 為和 gtid_purged 相同的值。
gtid_executed 為空意味着要么之前沒有啟動過基於 GTID 的復制,要么執行過 RESET MASTER。執行 RESET MASTER 時同樣也會把 gtid_purged 置空,即始終保持 gtid_purged 是 gtid_executed 的子集。
gtid_next
會話級變量,指示如何產生下一個GTID。可能的取值如下:
- AUTOMATIC: 自動生成下一個 GTID,實現上是分配一個當前實例上尚未執行過的序號最小的 GTID。
- ANONYMOUS: 設置后執行事務不會產生GTID。
- 顯式指定的GTID: 可以指定任意形式合法的 GTID 值,但不能是當前 gtid_executed 中的已經包含的 GTID,否則下次執行事務時會報錯。
mysql5.6主從環境的搭建和5.5沒有什么區別,唯一需要注意: 開啟GTID需要在my.cnf配置文件中啟用這三個參數(每個節點上都添加)
#GTID gtid_mode = on #開啟gtid功能 enforce_gtid_consistency = 1 #表示開啟gtid的一些安全限制,也可以將1寫成on log_slave_updates = 1 #注意1表示打開該功能,也可以將1寫成on
上面任意一個參數任意一個參數不開啟則都會報錯:
2017-08-09 02:33:57 6512 [ERROR] --gtid-mode=ON or UPGRADE_STEP_1 or UPGRADE_STEP_2 requires --log-bin and --log-slave-updates 2017-08-09 02:33:57 6512 [ERROR] Aborting 2017-08-09 02:39:58 9860 [ERROR] --gtid-mode=ON or UPGRADE_STEP_1 requires --enforce-gtid-consistency 2017-08-09 02:39:58 9860 [ERROR] Aborting
這里特意說下"log_slave_updates"這個參數選項,通常slave服務器從master服務器接收到的更新不記入slave的二進制日志。該參數選項告訴slave從服務器將其SQL線程執行的更新記入到slave服務器自己的二進制日志。為了使該選項生效,還必須啟動binlog二進制日志功能!!比如:
A01和A02為主主復制,A01和B01為主從復制,在測試的過程中發現了以下問題: - A01和A02的主主復制是沒有問題的(從A01寫入數據能同步到A02,從A02寫入數據能夠同步到A01); - 主從同步的時候,當從A01寫入的時候,數據可以寫入到B01; - 當從A02寫入的時候,數據就不能寫入到B01; 這個問題產生的原因:log_slave_updates參數的狀態為NO
創建mysql三個實例(3306、3307、3308),啟動之后,執行change時需要注意
各個實例的uuid:
3306: mysql> select @@server_uuid; +--------------------------------------+ | @@server_uuid | +--------------------------------------+ | 4e659069-3cd8-11e5-9a49-001c4270714e | +--------------------------------------+ 3307: mysql> select @@server_uuid; +--------------------------------------+ | @@server_uuid | +--------------------------------------+ | 041d0e65-3cde-11e5-9a6e-001c4270714e | +--------------------------------------+ 3308: mysql> select @@server_uuid; +--------------------------------------+ | @@server_uuid | +--------------------------------------+ | 081ccacf-3ce4-11e5-9a95-001c4270714e | +--------------------------------------+
使用5.6之前的主從change:
mysql> change master to master_host='127.0.0.1',master_user='rep',master_password='rep',master_log_file='mysql-bin3306.000001',master_log_pos=151
報錯:
ERROR 1776 (HY000): Parameters MASTER_LOG_FILE, MASTER_LOG_POS, RELAY_LOG_FILE and RELAY_LOG_POS cannot be set when MASTER_AUTO_POSITION is active.
當使用 MASTER_AUTO_POSITION 參數的時候,MASTER_LOG_FILE,MASTER_LOG_POS參數不能使用。
使用5.6之后的主從change:
mysql> change master to master_host='127.0.0.1',master_user='rep',master_password='rep',master_port=3306,master_auto_position=1;
在執行上面的命令的時候會報錯2個warnings,主要的原因是復制賬號安全的問題。
從總體上看來,由於要支持GTID,所以不需要手工確定主服務器的MASTER_LOG_FILE及MASTER_LOG_POS。要是不需要GTID則需要指定FILE和POS。在2個從上執行上面命令,到此主從環境搭建完成。GTID的主從完成之后可以通過show processlist查看:
mysql> show processlist\G;
*************************** 1. row ***************************
Id: 38
User: rep
Host: localhost:52321
db: NULL
Command: Binlog Dump GTID #通過GTID復制
Time: 48
State: Master has sent all binlog to slave; waiting for binlog to be updated
Info: NULL
Rows_sent: 0
Rows_examined: 0
2) 測試復制的故障轉移
server1(3306)掛了,服務器起不來了。需要把其中的一個從設置為主,另一個設置為其的從庫:
server2(3307):
Master_Log_File: mysql-bin3306.000002
Read_Master_Log_Pos: 4156773
Exec_Master_Log_Pos: 4156773
server3(3308):
Master_Log_File: mysql-bin3306.000001
Read_Master_Log_Pos: 83795320
Exec_Master_Log_Pos: 83795320
相比之下server2完成的事務要比server3更接近或則等於server1,現在需要把server3設置為server2的從庫。
在MySQL5.6之前,這里的計算會很麻煩,要計算之前主庫的log_pos和當前要設置成主庫的log_pos,很有可能出錯。所以出現了一些高可用性的工具如MHA,MMM等解決問題。
在MySQL5.6之后,很簡單的解決了這個難題。因為同一事務的GTID在所有節點上的值一致,那么根據server3當前停止點的GTID就能定位到server2上的GTID,所以直接在server3上執行change即可:
mysql> stop slave; Query OK, 0 rows affected (0.02 sec) #千萬不要執行 reset master,否則會從最先的GTID上開始執行。 mysql> change master to master_host='127.0.0.1',master_user='rep',master_password='rep',master_port=3307,master_auto_position=1; #指定到另一個比較接近主的從上。 Query OK, 0 rows affected, 2 warnings (0.02 sec) mysql> start slave; #成功的切換到新主 Query OK, 0 rows affected (0.03 sec)
主從結構已經變更,server2是Master,server3是Slave。因為不需要計算pos的值,所以通過GTID很簡單的解決了這個問題。
3) 跳過復制錯誤:gtid_next、gtid_purged
① 從服務器跳過一個錯誤的事務
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 127.0.0.1
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin3306.000001
Read_Master_Log_Pos: 38260944
Relay_Log_File: mysqld-relay-bin3307.000002
Relay_Log_Pos: 369
Relay_Master_Log_File: mysql-bin3306.000001
Slave_IO_Running: Yes
Slave_SQL_Running: No
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 1008
Last_Error: Error 'Can't drop database 'mablevi'; database doesn't exist' on query. Default database: 'mablevi'. Query: 'drop database mablevi'
Skip_Counter: 0
Exec_Master_Log_Pos: 151
Relay_Log_Space: 38261371
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: NULL
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 1008
Last_SQL_Error: Error 'Can't drop database 'mablevi'; database doesn't exist' on query. Default database: 'mablevi'. Query: 'drop database mablevi'
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1
Master_UUID: 4e659069-3cd8-11e5-9a49-001c4270714e
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0 #通過在change的時候指定,如:change master to master_delay=600,延遲10分鍾同步。
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State:
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp: 150810 23:38:39
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-48
Executed_Gtid_Set:
Auto_Position: 1
在MySQL5.6之前,只需要執行:
mysql> set global sql_slave_skip_counter=1;
跳過一個錯誤的事務,就可以繼續進行復制了。但在MySQL5.6之后則不行:
mysql> set global sql_slave_skip_counter=1; ERROR 1858 (HY000): sql_slave_skip_counter can not be set when the server is running with @@GLOBAL.GTID_MODE = ON. Instead, for each transaction that you want to skip, generate an empty transaction with the same GTID as the transaction
分析:因為是通過GTID來進行復制的,也需要跳過這個事務從而繼續復制,這個事務可以到主上的binlog里面查看:因為不知道找哪個GTID上出錯,所以也不知道如何跳過哪個GTID。但在show slave status里的信息里可以找到在執行Master里的POS:151
Exec_Master_Log_Pos: 151
的時候報錯,所以通過mysqlbinlog找到了GTID:
# at 151 #150810 22:57:45 server id 1 end_log_pos 199 CRC32 0x5e14d88f GTID [commit=yes] SET @@SESSION.GTID_NEXT= '4e659069-3cd8-11e5-9a49-001c4270714e:1'/*!*/;
找到這個GTID之后執行:必須按照下面順序執行
mysql> stop slave;
Query OK, 0 rows affected (0.01 sec)
mysql> set session gtid_next='4e659069-3cd8-11e5-9a49-001c4270714e:1'; #在session里設置gtid_next,即跳過這個GTID
Query OK, 0 rows affected (0.01 sec)
mysql> begin; #開啟一個事務
Query OK, 0 rows affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
mysql> SET SESSION GTID_NEXT = AUTOMATIC; #把gtid_next設置回來
Query OK, 0 rows affected (0.00 sec)
mysql> start slave; #開啟復制
Query OK, 0 rows affected (0.01 sec)
查看復制狀態:
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 127.0.0.1
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin3306.000001
Read_Master_Log_Pos: 38260944
Relay_Log_File: mysqld-relay-bin3307.000003
Relay_Log_Pos: 716
Relay_Master_Log_File: mysql-bin3306.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: 38260944
Relay_Log_Space: 38261936
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: 1
Master_UUID: 4e659069-3cd8-11e5-9a49-001c4270714e
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 the slave I/O thread to update it
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-48
Executed_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-48
Auto_Position: 1
在此成功跳過了錯誤,同步繼續。可以通過這個辦法來處理復制失敗的問題,這里還有個例子(從服務器中跳過一條語句/事務):
mysql > stop slave;
Query OK, 0 ROWS affected (0.05 sec)
mysql > CHANGE master TO MASTER_DELAY=600;
Query OK, 0 ROWS affected (0.27 sec)
mysql > START slave;
Query OK, 0 ROWS affected, 1 warning (0.06 sec)
master 原本是正常的, 然后意外地執行了 truncate table:
mysql > INSERT INTO t SET title='c';
Query OK, 1 ROW affected (0.03 sec)
mysql > INSERT INTO t SET title='d';
Query OK, 1 ROW affected (0.05 sec)
mysql > SHOW master STATUS \G
*************************** 1. ROW ***************************
File: black-bin.000001
POSITION: 2817
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:1-10
1 ROW IN SET (0.00 sec)
mysql > TRUNCATE TABLE t;
Query OK, 0 ROWS affected (0.15 sec)
mysql > SHOW master STATUS \G
*************************** 1. ROW ***************************
File: black-bin.000001
POSITION: 2948
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:1-11
1 ROW IN SET (0.00 sec)
slave有延遲, 雖然已經獲取到了gtid及對應的events, 但是並未執行:
mysql > SHOW slave STATUS \G
*************************** 1. ROW ***************************
Slave_IO_State: Waiting FOR master TO send event
.......
.......
SQL_Delay: 600
SQL_Remaining_Delay: 565
Slave_SQL_Running_State: Waiting until MASTER_DELAY seconds after master executed event
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:9-11
Executed_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:1-8
Auto_Position: 1
1 ROW IN SET (0.00 sec)
要想辦法在slave中跳過 GTID:0c005b76-d3c7-11e2-a27d-274c063b18c4:11, 也就是那條truncate table語句 。
辦法就是設置GTID_NEXT,然后提交一個空的事務。
mysql > stop slave;
Query OK, 0 ROWS affected (0.03 sec)
mysql > SET session gtid_next='0c005b76-d3c7-11e2-a27d-274c063b18c4:11';
Query OK, 0 ROWS affected (0.00 sec)
mysql > BEGIN; commit;
Query OK, 0 ROWS affected (0.00 sec)
Query OK, 0 ROWS affected (0.01 sec)
mysql >SET SESSION GTID_NEXT = AUTOMATIC;
Query OK, 0 ROWS affected (0.00 sec)
mysql > START slave;
Query OK, 0 ROWS affected, 1 warning (0.07 sec)
查看復制狀態
mysql > SHOW slave STATUS \G
*************************** 1. ROW ***************************
Slave_IO_State: Waiting FOR master TO send event
.......
.......
Retrieved_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:9-11
Executed_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:1-11
Auto_Position: 1
1 ROW IN SET (0.00 sec)
mysql > SELECT * FROM t;
+----+-------+
| id | title |
+----+-------+
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | d |
+----+-------+
4 ROWS IN SET (0.00 sec)
成功跳過 truncate table, 當然此時主從的數據已經不一致了。
注意:通過GTID的復制都是沒有指定MASTER_LOG_FILE和MASTER_LOG_POS的,所以通過GTID復制都是從最先開始的事務開始,除非在自己的binlog里面有執行過之前的記錄,才會繼續后面的執行。
② 要是事務日志被purge,再進行change
mysql> show master logs;
+----------------------+-----------+
| Log_name | File_size |
+----------------------+-----------+
| mysql-bin3306.000001 | 38260944 |
+----------------------+-----------+
1 row in set (0.00 sec)
mysql> flush logs;
Query OK, 0 rows affected (0.03 sec)
mysql> show tables;
+---------------+
| Tables_in_mmm |
+---------------+
| patent_family |
| t1 |
| t2 |
+---------------+
3 rows in set (0.01 sec)
mysql> create table t3(id int)engine = tokudb;
Query OK, 0 rows affected (0.02 sec)
mysql> insert into t3 values(3),(4);
Query OK, 2 rows affected (0.05 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> flush logs;
Query OK, 0 rows affected (0.02 sec)
mysql> create table ttt(id int)engine = tokudb;
Query OK, 0 rows affected (0.02 sec)
mysql> insert into ttt values(1),(2),(3),(4),(5);
Query OK, 5 rows affected (0.03 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> show master logs;
+----------------------+-----------+
| Log_name | File_size |
+----------------------+-----------+
| mysql-bin3306.000001 | 38260995 |
| mysql-bin3306.000002 | 656 |
| mysql-bin3306.000003 | 619 |
+----------------------+-----------+
3 rows in set (0.00 sec)
mysql> purge binary logs to 'mysql-bin3306.000003'; #日志被purge
Query OK, 0 rows affected (0.02 sec)
mysql> show master logs; #日志被purge之后等下的binlog
+----------------------+-----------+
| Log_name | File_size |
+----------------------+-----------+
| mysql-bin3306.000003 | 619 |
+----------------------+--------
3308登陸之后執行:
mysql> change master to master_host='127.0.0.1',master_user='rep',master_password='rep',master_port=3306,master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.04 sec)
mysql> start slave;
Query OK, 0 rows affected (0.02 sec)
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 127.0.0.1
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File:
Read_Master_Log_Pos: 4
Relay_Log_File: mysqld-relay-bin3308.000001
Relay_Log_Pos: 4
Relay_Master_Log_File:
Slave_IO_Running: No
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: 0
Relay_Log_Space: 151
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: 1236
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1
Master_UUID: 4e659069-3cd8-11e5-9a49-001c4270714e
Master_Info_File: /var/lib/mysql3/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp: 150811 00:02:50
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 1
報錯:
Last_IO_Errno: 1236
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'
這里需要解決的是:Slave如何跳過purge的部分,而不是在最先開始的事務執行。
在主上執行,查看被purge的GTID: mysql> show global variables like 'gtid_purged'; +---------------+-------------------------------------------+ | Variable_name | Value | +---------------+-------------------------------------------+ | gtid_purged | 4e659069-3cd8-11e5-9a49-001c4270714e:1-50 | +---------------+-------------------------------------------+ 1 row in set (0.00 sec) 在從上執行,跳過這個GTID: mysql> stop slave; Query OK, 0 rows affected (0.00 sec) mysql> set global gtid_purged = '4e659069-3cd8-11e5-9a49-001c4270714e:1-50'; Query OK, 0 rows affected (0.02 sec) mysql> reset master; Query OK, 0 rows affected (0.04 sec) mysql> start slave; Query OK, 0 rows affected (0.01 sec) 要是出現: ERROR 1840 (HY000): @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty. 則需要執行: mysql> reset master;
到這從的同步就正常了。
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 127.0.0.1
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin3306.000003
Read_Master_Log_Pos: 619
Relay_Log_File: mysqld-relay-bin3308.000002
Relay_Log_Pos: 797
Relay_Master_Log_File: mysql-bin3306.000003
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: 619
Relay_Log_Space: 1006
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: 1
Master_UUID: 4e659069-3cd8-11e5-9a49-001c4270714e
Master_Info_File: /var/lib/mysql3/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:51-52
Executed_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-52
Auto_Position: 1
1 row in set (0.00 sec)
mysql> use mmm
Database changed
mysql> show tables;
+---------------+
| Tables_in_mmm |
+---------------+
| ttt |
+---------------+
1 row in set (0.00 sec)
③ 通過另一個從庫恢復從庫數據
比如一台從庫誤操作,數據丟失了,可以通過另一個從庫來進行恢復:
slave2(3308):
mysql> use mmm
Database changed
mysql> show tables;
+---------------+
| Tables_in_mmm |
+---------------+
| patent_family |
| t |
| tt |
+---------------+
3 rows in set (0.00 sec)
mysql> truncate table tt; #誤操作,把記錄刪除了
Query OK, 0 rows affected (0.02 sec)
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 127.0.0.1
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin3306.000001
Read_Master_Log_Pos: 38260553
Relay_Log_File: mysqld-relay-bin3308.000002
Relay_Log_Pos: 38260771
Relay_Master_Log_File: mysql-bin3306.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: 38260553
Relay_Log_Space: 38260980
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: 1
Master_UUID: 4e659069-3cd8-11e5-9a49-001c4270714e
Master_Info_File: /var/lib/mysql3/master.info
SQL_Delay: 0 #延遲同步
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-46
Executed_Gtid_Set: 081ccacf-3ce4-11e5-9a95-001c4270714e:1, #多出了一個GTID(本身實例執行的事務)
4e659069-3cd8-11e5-9a49-001c4270714e:1-46
Auto_Position: 1
數據被誤刪除之后,最好停止復制:stop slave;
恢復數據從slave1(3307)上備份數據,並還原到slave2(3308)中。
備份:
mysqldump -uzjy -p123456 -h127.0.0.1 -P3307 --default-character-set=utf8 --set-gtid-purged=ON -B mmm > mmm1.sql
在還原到slave2的時候需要在slave2上執行:reset master; 不然會報錯:
ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.
還原:
root@zjy:~# mysql -uzjy -p123456 -h127.0.0.1 -P3308 --default-character-set=utf8 < mmm.sql
開啟同步:
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.03 sec)
這時候你會發現誤刪除的數據已經被還原,並且復制也正常。因為根據GTID的原理,通過slave1的備份直接可以和Master進行同步。
這里備份注意的一點是:在備份開啟GTID的實例里,需要指定 --set-gtid-purged參數,否則會報warning:
Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions, even those that changed suppressed parts of the database. If you don't want to restore GTIDs, pass --set-gtid-purged=OFF. To make a complete dump, pass --all-databases --triggers --routines --events
備份文件里面會出現:
SET @@GLOBAL.GTID_PURGED='4e659069-3cd8-11e5-9a49-001c4270714e:1-483';
還原的時候會要求先在實例上reset master,不然會報錯:
Warning: Using a password on the command line interface can be insecure. ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.
指定--set-gtid-purged=ON參數,出現GTID_PURGED,直接還原的時候執行,從庫不需要其他操作就可以直接change到主。
順便總結一下:GTID跳過復制錯誤的方法
1)對於跳過一個錯誤,找到無法執行事務的編號,比如是2a09ee6e-645d-11e7-a96c-000c2953a1cb:1-10 mysql> stop slave; mysql> set gtid_next='2a09ee6e-645d-11e7-a96c-000c2953a1cb:1-10'; mysql> begin; mysql> commit; mysql> set gtid_next='AUTOMATIC'; mysql> start slave; 2)上面方法只能跳過一個事務,那么對於一批如何跳過? 在主庫執行"show master status",看主庫執行到了哪里,比如:2a09ee6e-645d-11e7-a96c-000c2953a1cb:1-33,那么操作如下: mysql> stop slave; mysql> reset master; mysql> set global gtid_purged='2a09ee6e-645d-11e7-a96c-000c2953a1cb:1-33'; mysql> start slave;
五、運維場景中GTID的運用
====== 使用GTID搭建Replication ======
- 從0開始搭建
step 1: 讓所有server處於同一個點 mysql> SET @@global.read_only = ON; step 2: 關閉所有MySQL # mysqladmin -uusername -p shutdown step 3: 重啟所有MySQL,並開啟GTID # mysqld --gtid-mode=ON --log-bin --enforce-gtid-consistency & 當然,在my.cnf文件中配置好最佳! step 4: 在從數據庫上通過change master語句進行復制 mysql> change master to master_host=host,master_port=port,master_user=user,master_password=password,master_auto_position=1; mysql> start slave; step 5: 讓master可讀可寫 mysql> SET @@global.read_only = OFF;
- 從備份中恢復&搭建
step 1: 備份 mysqldump xx; #獲取並且記錄gtid_purged值 or 冷備份; #獲取並且記錄gtid_executed值,這個就相當於mysqldump中得到的gtid_purged step 2: 在新服務器上reset master,導入備份 mysql> reset master; #清空gtid信息 導入備份; #如果是邏輯導入,請設置sql_log_bin=off mysql> set global gtid_purged=xx; step 3: 在從數據庫上通過change master語句進行復制 mysql> change master to master_host=host,master_port=port,master_user=user,master_password=password,master_auto_position=1; mysql> start slave;
====== 如何從classic replication 升級成 GTID replication ======
- offline 方式升級 (線下升級)
offline 的方式升級最簡單: - 全部關閉mysql - 在my.cnf文件中配置好GTID - 重啟mysql - 登錄mysql,執行"change master to MASTER_AUTO_POSITION=1;"
- online 方式升級 (線上升級)
先介紹幾個重要GTID_MODE的參數: GTID_MODE = OFF 不產生Normal_GTID,只接受來自master的ANONYMOUS_GTID GTID_MODE = OFF_PERMISSIVE 不產生Normal_GTID,可以接受來自master的ANONYMOUS_GTID & Normal_GTID GTID_MODE = ON_PERMISSIVE 產生Normal_GTID,可以接受來自master的ANONYMOUS_GTID & Normal_GTID GTID_MODE = ON 產生Normal_GTID,只接受來自master的Normal_GTID 歸納總結: 1)當master產生Normal_GTID的時候,如果slave的gtid_mode(OFF)不能接受Normal_GTID,那么就會報錯 2)當master產生ANONYMOUS_GTID的時候,如果slave的gtid_mode(ON)不能接受ANONYMOUS_GTID,那么就會報錯 3)設置auto_position的條件: 當master的gtid_mode=ON時,slave可以為OFF_PERMISSIVE,ON_PERMISSIVE,ON。 除此之外,都不能設置auto_position = on ============================================ 下面開始說下如何online 升級為GTID模式? step 1: 每台server執行 檢查錯誤日志,直到沒有錯誤出現,才能進行下一步 mysql> SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = WARN; step 2: 每台server執行 mysql> SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = ON; step 3: 每台server執行 不用關心一組復制集群的server的執行順序,只需要保證每個Server都執行了,才能進行下一步 mysql> SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE; step 4: 每台server執行 不用關心一組復制集群的server的執行順序,只需要保證每個Server都執行了,才能進行下一步 mysql> SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE; step 5: 在每台server上執行,如果ONGOING_ANONYMOUS_TRANSACTION_COUNT=0就可以 不需要一直為0,只要出現過0一次,就ok mysql> SHOW STATUS LIKE 'ONGOING_ANONYMOUS_TRANSACTION_COUNT'; step 6: 確保所有anonymous事務傳遞到slave上了 #master上執行 mysql> SHOW MASTER STATUS; #每個slave上執行 mysql> SELECT MASTER_POS_WAIT(file, position); 或者,等一段時間,只要不是大的延遲,一般都沒問題 step 7: 每台Server上執行 mysql> SET @@GLOBAL.GTID_MODE = ON; step 8: 在每台server上將my.cnf中添加好gtid配置 gtid_mode=on enforce-gtid-consistency=1 log_bin=mysql-bin log-slave-updates=1 step 9: 在從機上通過change master語句進行復制 mysql> STOP SLAVE; mysql> CHANGE MASTER TO MASTER_AUTO_POSITION = 1; mysql> START SLAVE;
====== GTID failover (故障轉移) ======
- MySQL crash (Mysql 崩潰)
配置好loss-less semi-sync replication,可以更可靠的保證數據零丟失!下面說的都是mysql crash 后,起不來的情況:
binlog 在master還有日志沒有傳遞到slave (解決措施如下)
1. 選取最新的slave,change master to maseter_auto_position同步好 2. mysqlbinlog 將沒傳遞過來的binlog在新master上replay 3. 打開新master的surper_read_only=off;
binlog 已經傳遞到slave (解決措施如下)
1. 選取最新的slave,change master to maseter_auto_position同步好 2. 打開新master的surper_read_only=off;
- OS crash (操作系統崩潰)
1. 選取最新的slave,change master to maseter_auto_position同步好 2. 打開新master的surper_read_only=off;
以上操作,在傳統模式復制下,需要通過MHA來實現,但MHA還是比較復雜。現在有了GTID模式的情況下,實現起來就非常簡單,非常方便了。
====== GTID 運維和錯誤處理 ======
使用GTID后,對原來傳統的運維有不同之處了,需要調整過來;使用Row模式且復制配置正確的情況下,基本上很少發現有復制出錯的情況;slave 設置 "super_read_only=on"
- 錯誤場景: Errant transaction
出現這種問題基本有兩種情況 - 復制參數沒有配置正確,當slave crash后,會出現重復鍵問題; - DBA操作不正確,不小心在slave上執行了事務; 對於第一個重復鍵問題的解決措施: 1) 傳統模式 (需要skip transation) SQL> SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; SQL> START SLAVE; 2) GTID模式 SQL> SET GTID_NEXT='b9b4712a-df64-11e3-b391-60672090eb04:7'; --設置需要跳過的gtid event SQL> BEGIN;COMMIT; SQL> SET GTID_NEXT='AUTOMATIC'; SQL> START SLAVE; 對於第二種不小心多執行了事務 這種情況就比較難了,這樣已經導致了數據不一致,大多數情況,建議slave重做 如何避免? 則需要在slave上設置 "super_read_only=on"
- 特別注意: 當發生inject empty transction后,有可能會丟失事務
這里說下inject empty transction的隱患: - 當slave上inject empty transction,說明有一個master的事務被忽略了(這里假設是 $uuid:100) - 事務丟失一:如果此時此刻master掛了,這個slave被選舉為新master,那么其他的slave如果還沒有執行到$uuid:100,就會丟失掉$uuid:100這個事務。 - 事務丟失二:如果從備份中重新搭建一個slave,需要重新執行之前的所有事務,而此時,master掛了, 又回到了事務丟失一的場景。
- 如何重置gtid_executed,gtid_purged
設置gtid_executed mysql> reset master #目前只能這么操作 設置gtid_purged - 當gtid_executed 非空的時候,不能設置gtid_purged - 當gtid_executed 為空的時候(即剛搭建好mysql), 可以直接SET @@GLOBAL.GTID_PURGED='0ad6eae9-2d66-11e6-864f-ecf4bbf1f42c:1-3';
- 如果auto.cnf 被刪掉了,對於GTID的復制會有什么影響?
如果被刪掉,重啟后,server-uuid 會變
- 手動設置"set @@gtid_purged = xx:yy", mysql會去主動修改binlog的頭么?
不會去主動修改!
- GTID和復制過濾規則之間如何協同工作?MySQL,test還能愉快的過濾掉嗎?
GTID和復制過濾規則之間如何協同工作?MySQL,test還能愉快的過濾掉嗎?
六、基於GTID模式的主從復制環境部署記錄 (Mysql 5.6 +GTID復制)
mysql主數據庫: 172.16.60.205 (master)
mysql從數據庫: 172.16.60.206 (slave)
mysql5.6.39 安裝部署,參考:https://www.cnblogs.com/kevingrace/p/6109679.html
mysql5.7+GTID復制的配置和5.6的配置基本一致~
============================================
主數據庫172.16.60.205的操作
my.cnf文件里GTID復制的配置內容如下:
[root@mysql-master ~]# vim /usr/local/mysql/my.cnf
.........
#GTID:
server_id = 205
gtid_mode = on
enforce_gtid_consistency = on #強制gtid一直性,用於保證啟動gitd后事務的安全;
#binlog
log_bin = master-bin
log-slave-updates = 1 #在從服務器進入主服務器傳入過來的修改日志所使用,在Mysql5.7之前主從架構上使用gtid模式的話,必須使用此選項,在Mysql5.7取消了,會增加系統負載。
binlog_format = row #推薦采用此模式
sync-master-info = 1 #同步master_info,任何事物提交以后都必須要把事務提交以后的二進制日志事件的位置對應的文件名稱,記錄到master_info中,下次啟動自動讀取,保證數據無丟失
sync_binlog = 1 #最好加上這一行。表示binlog進行FSYNC刷盤,同時dump線程會在sync階段后進行binlog傳輸
#relay log
skip_slave_start = 1
配置完成之后,別忘了重啟Mysql
[root@mysql-master ~]# /etc/init.d/mysql restart
Shutting down MySQL.. [ OK ]
Starting MySQL.. [ OK ]
查看一下master狀態, 發現多了一項"Executed_Gtid_Set "
mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000006 | 151 | | | |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
mysql> show global variables like '%uuid%';
+---------------+--------------------------------------+
| Variable_name | Value |
+---------------+--------------------------------------+
| server_uuid | b3df746a-1487-11e9-a8ba-0050568843f8 |
+---------------+--------------------------------------+
1 row in set (0.00 sec)
mysql> show global variables like '%gtid%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| binlog_gtid_simple_recovery | OFF |
| enforce_gtid_consistency | ON |
| gtid_executed | |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | |
| simplified_binlog_gtid_recovery | OFF |
+---------------------------------+-------+
7 rows in set (0.00 sec)
主庫執行從庫復制授權
mysql> grant replication slave,replication client on *.* to slave@'172.16.60.206' identified by "slave@123";
Query OK, 0 rows affected (0.01 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> show grants for slave@'172.16.60.206';
+--------------------------------------------------------------------------------------------------------------------------------------------------+
| Grants for slave@172.16.60.206 |
+--------------------------------------------------------------------------------------------------------------------------------------------------+
| GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'172.16.60.206' IDENTIFIED BY PASSWORD '*4F0FF134CC4C1A2872D972373A6AA86CA0A81872' |
+--------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
這里需要注意一下:
啟動配置之前,同樣需要對從服務器進行初始化。對從服務器初始化的方法基本和基於日志點是相同的,只不過在啟動了GTID模式后,在備份中所記錄的就不是備份時的二進制日志文件名和偏移量了,
而是記錄的是備份時最后的GTID值。
需要先在主數據庫機器上把目標庫備份一下,假設這里目標庫是kevin(為了測試效果,下面手動創建)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.00 sec)
mysql> CREATE DATABASE kevin CHARACTER SET utf8 COLLATE utf8_general_ci;
Query OK, 1 row affected (0.01 sec)
mysql> use kevin;
Database changed
mysql> create table if not exists haha (id int(10) PRIMARY KEY AUTO_INCREMENT,name varchar(50) NOT NULL);
Query OK, 0 rows affected (0.27 sec)
mysql> insert into kevin.haha values(1,"congcong"),(2,"huihui"),(3,"grace");
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from kevin.haha;
+----+----------+
| id | name |
+----+----------+
| 1 | congcong |
| 2 | huihui |
| 3 | grace |
+----+----------+
3 rows in set (0.00 sec)
把kevin庫備份出來
[root@mysql-master ~]# mysqldump --single-transaction --master-data=2 --triggers --routines --database kevin -uroot -p123456 > /root/kevin.sql
備份完成之后,查看一下sql文件內容。
[root@mysql-master ~]# cat /root/kevin.sql
-- MySQL dump 10.13 Distrib 5.6.39, for Linux (x86_64)
--
-- Host: localhost Database: kevin
-- ------------------------------------------------------
-- Server version 5.6.39-log
...............
...............
--
-- GTID state at the beginning of the backup
--
SET @@GLOBAL.GTID_PURGED='b3df746a-1487-11e9-a8ba-0050568843f8:1-5';
--
...............
...............
然后把備份的/root/kevin.sql文件拷貝到從數據庫服務器上
[root@mysql-master ~]# rsync -e "ssh -p22" -avpgolr /root/kevin.sql root@172.16.60.206:/root/
============================================
從數據庫172.16.60.206的操作
my.cnf文件里GTID復制的配置內容如下:
與主服務器配置大概一致,除了server_id不一致外,從服務器還可以在配置文件里面添加:"read_only=on" ,
使從服務器只能進行讀取操作,此參數對超級用戶無效,並且不會影響從服務器的復制;
[root@mysql-slave ~]# vim /usr/local/mysql/my.cnf
..........
#GTID:
server_id = 206
gtid_mode = on
enforce_gtid_consistency = on
#binlog
log_bin = master-bin
log-slave-updates = 1
binlog_format = row
sync-master-info = 1
sync_binlog = 1
#relay log
skip_slave_start = 1
read_only = on
配置完成之后,別忘了重啟Mysql
[root@mysql-slave ~]# /etc/init.d/mysql restart
Shutting down MySQL.. [ OK ]
Starting MySQL.. [ OK ]
接着將主數據庫目標庫的備份數據kevin.sql導入到從數據庫里
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.00 sec)
mysql> source /root/kevin.sql;
mysql> select * from kevin.haha;
+----+----------+
| id | name |
+----+----------+
| 1 | congcong |
| 2 | huihui |
| 3 | grace |
+----+----------+
3 rows in set (0.00 sec)
在從數據庫里,使用change master 配置主從復制
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> change master to master_host='172.16.60.205',master_user='slave',master_password='slave@123',master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.50 sec)
mysql> start slave;
Query OK, 0 rows affected (0.05 sec)
mysql> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.16.60.205
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-bin.000006
Read_Master_Log_Pos: 1270
Relay_Log_File: mysql-relay-bin.000002
Relay_Log_Pos: 411
Relay_Master_Log_File: master-bin.000006
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
..............
..............
Retrieved_Gtid_Set:
Executed_Gtid_Set: b3df746a-1487-11e9-a8ba-0050568843f8:1-5 #這是master主數據庫的GTID
Auto_Position: 1
然后回到主數據庫中查看master狀態
mysql> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID |
+-----------+------+------+-----------+--------------------------------------+
| 206 | | 3306 | 205 | b6589756-1487-11e9-a8bb-005056ac509b |
+-----------+------+------+-----------+--------------------------------------+
1 row in set (0.00 sec)
通過上面一系列配置,則mysql基於GTID的主從復制環境就部署好了。
下面開始驗證:
在172.16.60.205的主數據庫里插入新數據
mysql> insert into kevin.haha values(10,"heifei"),(11,"huoqiu"),(12,"chengxihu");
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from kevin.haha;
+----+-----------+
| id | name |
+----+-----------+
| 1 | congcong |
| 2 | huihui |
| 3 | grace |
| 10 | heifei |
| 11 | huoqiu |
| 12 | chengxihu |
+----+-----------+
6 rows in set (0.00 sec)
到172.16.60.206的從數據庫里查看,發現已經同步過來了
mysql> select * from kevin.haha;
+----+-----------+
| id | name |
+----+-----------+
| 1 | congcong |
| 2 | huihui |
| 3 | grace |
| 10 | heifei |
| 11 | huoqiu |
| 12 | chengxihu |
+----+-----------+
6 rows in set (0.00 sec)
如果上面slave再使用"change master to..."進行同步復制操作時報錯:Error 'Can't create database 'kevin'; database exists' on query. Default database: 'kevin'. Query: 'CREATE DATABASE kevin CHARACTER SET utf8 COLLATE utf8_general_ci', 則解決辦法就是把slave從庫里導入的kevin庫刪除,然后再接着執行同步復制操作:stop slave; change master to ...; start slave 即可!
重做GTID主從復制關系 (遷移到新的slave從庫或變更slave從庫)
由於master主數據庫上當前GTID_EXECUTED參數已經有值,而從master主庫直接備份出來的dump文件中包含了SET @@GLOBAL.GTID_PURGED的操作,所以在新的slave從數據庫導入dump備份文件時,會報錯: ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty. (這個報錯在遷移數據庫的時候很有可能會碰過)
有兩種方法解決上面的問題(可以使用其中任意一個方法,也可以兩種方法一起使用):
方法一: 執行命令"reset master",這個操作可以將當前slave庫的GTID_EXECUTED值置空;
方法二: 在dump導出master數據時,添加--set-gtid-purged=off參數,避免將master上的gtid信息導出,然后再導入到slave庫;
在添加--set-gtid-purged=off參數前的dump導出文件信息如下(包含了SET @@GLOBAL.GTID_PURGED的操作):

在添加--set-gtid-purged=off參數后的dump導出文件信息如下:

如上是在172.16.60.205 master主庫和 172.16.60.206 slave從庫之間做的GTID復制關系, 假設現在172.16.60.206 slave節點有問題,需要將數據遷移到另一個slave節點(比如172.16.60.207)上, 則遷移后需要重新配置GTID主從復制關系 !操作記錄如下:
1)在172.16.60.205主數據庫上的操作
mysql > reset master;
mysql> grant replication slave,replication client on *.* to slave@'172.16.60.207' identified by "slave@123";
mysql> flush privileges;
[root@mysql-master ~]# mysqldump -uroot -p'123456' -B -A -F --set-gtid-purged=OFF --master-data=2 --single-transaction --events |gzip >/root/205_$(date +%F).sql.gz
/root/205_2019-01-10.sql.gz
[root@mysql-master ~]# ll /root/205_*
-rw-r--r-- 1 root root 181334 Jan 10 14:26 /root/205_2019-01-10.sql.gz
[root@mysql-master ~]# rsync -e "ssh -p22" -avpgolr /root/205_2019-01-10.sql.gz root@172.16.60.207:/root/
2) 在新的slave節點172.16.60.207從數據庫上的操作
[root@mysql-slave2 ~]# vim /usr/local/mysql/my.cnf
..........
#GTID:
server_id = 207
gtid_mode = on
enforce_gtid_consistency = on
#binlog
log_bin = master-bin
log-slave-updates = 1
binlog_format = row
sync-master-info = 1
sync_binlog = 1
#relay log
skip_slave_start = 1
read_only = on
配置完成之后,別忘了重啟Mysql
[root@mysql-slave2 ~]# /etc/init.d/mysql restart
Shutting down MySQL.. [ OK ]
Starting MySQL.. [ OK ]
接着將主數據庫拷貝過來的備份數據導入到從數據庫中
[root@mysql-slave2 ~]# gzip -d 205_2019-01-10.sql.gz
[root@mysql-slave2 ~]# ls 205_2019-01-10.sql
205_2019-01-10.sql
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.00 sec)
mysql> source /root/205_2019-01-10.sql;
mysql> select * from kevin.haha;
+----+-----------+
| id | name |
+----+-----------+
| 1 | congcong |
| 2 | huihui |
| 3 | grace |
| 10 | heifei |
| 11 | huoqiu |
| 12 | chengxihu |
+----+-----------+
6 rows in set (0.00 sec)
在從數據庫里,使用change master 配置主從復制
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> change master to master_host='172.16.60.205',master_user='slave',master_password='slave@123',master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.50 sec)
mysql> start slave;
Query OK, 0 rows affected (0.05 sec)
mysql> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.16.60.205
Master_User: slave
Master_Port: 3306
..............
..............
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
..............
..............
Retrieved_Gtid_Set: 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-2
Executed_Gtid_Set: 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-2,
d743d65c-14b8-11e9-a9fb-005056ac05b5:1-126
Auto_Position: 1
1 row in set (0.00 sec)
通過上面可知,新添加的slave節點172.16.60.207已經和主數據庫172.16.60.205配置好了GTID主從復制關系了。
接着回到master數據庫查看
mysql> show master status;
+-------------------+----------+--------------+------------------+------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+------------------------------------------+
| master-bin.000003 | 745 | | | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-4 |
+-------------------+----------+--------------+------------------+------------------------------------------+
1 row in set (0.00 sec)
mysql> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID |
+-----------+------+------+-----------+--------------------------------------+
| 206 | | 3306 | 205 | 26ca2900-14f0-11e9-ab63-005056ac509b |
| 207 | | 3306 | 205 | 1e14b008-14f0-11e9-ab63-005056ac05b5 |
+-----------+------+------+-----------+--------------------------------------+
2 rows in set (0.00 sec)
由上面結果可知,新節點172.16.60.207已經成為了172.16.60.205主庫的slave,即有了主從同步關系!
在master主數據庫插入新數據
mysql> insert into kevin.haha values(20,"lanzhou"),(21,"zhongguo");
Query OK, 2 rows affected (0.03 sec)
Records: 2 Duplicates: 0 Warnings: 0
然后到新的slave從庫172.16.60.207上查看
mysql> select * from kevin.haha;
+----+-----------+
| id | name |
+----+-----------+
| 1 | congcong |
| 2 | huihui |
| 3 | grace |
| 10 | heifei |
| 11 | huoqiu |
| 12 | chengxihu |
| 20 | lanzhou |
| 21 | zhongguo |
+----+-----------+
8 rows in set (0.00 sec)
但是到之前的slave從庫172.16.60.206上查看,發現沒有成功同步到master主庫在上面插入的數據庫
mysql> select * from kevin.haha;
+----+-----------+
| id | name |
+----+-----------+
| 1 | congcong |
| 2 | huihui |
| 3 | grace |
| 10 | heifei |
| 11 | huoqiu |
| 12 | chengxihu |
+----+-----------+
6 rows in set (0.00 sec)
查看172.16.60.206機器上查看slave同步狀態
mysql> show slave status \G;
..........
..........
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
..........
Retrieved_Gtid_Set: 59a1b34c-14f0-11e9-ab65-0050568843f8:6
Executed_Gtid_Set: 59a1b34c-14f0-11e9-ab65-0050568843f8:1-6
Auto_Position: 1
發現172.16.60.206 從庫的slave同步狀態是正常的! 因為IO和SQL都是YES!
那么為什么會同步不到master插入的新數據呢?
原因是:因為此時172.16.60.206從庫的gtid和master主庫的gtid不一樣了!
mysql> show global variables like 'gtid_%';
+---------------+------------------------------------------+
| Variable_name | Value |
+---------------+------------------------------------------+
| gtid_executed | 59a1b34c-14f0-11e9-ab65-0050568843f8:1-6 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | 59a1b34c-14f0-11e9-ab65-0050568843f8:1-5 |
+---------------+------------------------------------------+
4 rows in set (0.00 sec)
而在172.16.60.205主庫和新從庫172.16.60.207上查看的gtid,發現這兩個節點的gtid是一樣的,所以它們兩個數據能保持一致性!
但是172.16.60.206的gtid和它們兩個的gtid不一樣,所以172.16.60.206數據不能和master保持一致!
在172.16.60.205主庫節點上查看gtid
mysql> show global variables like 'gtid_%';
+---------------+------------------------------------------+
| Variable_name | Value |
+---------------+------------------------------------------+
| gtid_executed | 59a1b34c-14f0-11e9-ab65-0050568843f8:1-3 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | |
+---------------+------------------------------------------+
4 rows in set (0.00 sec)
在172.16.60.207從庫節點上查看gtid
mysql> show global variables like 'gtid_%';
+---------------+--------------------------------------------------------------------------------------+
| Variable_name | Value |
+---------------+--------------------------------------------------------------------------------------+
| gtid_executed | 1e14b008-14f0-11e9-ab63-005056ac05b5:1-123,
59a1b34c-14f0-11e9-ab65-0050568843f8:1-3 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | |
+---------------+--------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)
===============================================================================================================
總結:
a) 通過以上操作方式后,新節點會成為master主庫的slave從庫,但是可能會導致之前的slave節點的gtid跟master不一樣而破壞數據一致性。
b) 上面操作后,通過"show slave hosts;"查看,可能只有172.16.60.207這一個slave,之前的172.16.60.206節點的slave同步直接出現問題而導致主從復制失效。
c) 后面發現在后續添加172.16.60.208節點后(注意下面master主庫的操作),172.16.60.206的gtid又自動恢復到和master的gtid一樣了,即恢復了數據一致性的主從復制關系。
通過上面操作結果可知,采用"reset master" 以及添加"--set-gtid-purged=off"參數進行mysqldump備份,並添加新的slave節點的方式后,可能會導致之前的slave節點的主從同步失效(通過"show global variables like 'gtid_%';"命令查看之前的206從庫的gtid和master的gtid不一樣!)。比較推薦采用下面的方法添加新的slave,添加成功后,之前的slave的主從關系仍然保留有效,可實現"一主多從"的GTID主從復制。
一主多從的GTID主從復制
上面說到的是mysql基於GTID的一主一從模式的復制,現在需要再加一個slave從節點做成一主兩從的模式。比如追加一個新的slave從節點172.16.60.208,也作為master主節點172.16.60.205的slave從節點,即由之前的一主一從調整為一主兩從!
1)在master節點172.16.60.205上的操作
備份master主節點數據
mysql> grant replication slave,replication client on *.* to slave@'172.16.60.208' identified by "slave@123";
Query OK, 0 rows affected (0.06 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.04 sec)
mysql> FLUSH TABLE WITH READ LOCK;
Query OK, 0 rows affected (0.06 sec)
備份master
[root@mysql-master ~]# mysqldump -u root -p'123456' --lock-all-tables --master-data=2 --flush-logs --all-databases --triggers --routines --events > 205_slave.sql
[root@mysql-master ~]# ls 205_slave.sql
205_slave.sql
將master的備份文件拷貝給新的slave節點172.16.60.208
[root@mysql-master ~]# rsync -e "ssh -p22" -avpgolr 205_slave.sql root@172.16.60.208:/root/
記錄當前的gtid
mysql> show global variables like 'gtid_%';
+---------------+------------------------------------------+
| Variable_name | Value |
+---------------+------------------------------------------+
| gtid_executed | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-7 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | |
+---------------+------------------------------------------+
4 rows in set (0.00 sec)
2) 在新添加的slave節點172.16.60.208上的操作
[root@mysql-slave3 ~]# vim /usr/local/mysql/my.cnf
..........
#GTID:
server_id = 208
gtid_mode = on
enforce_gtid_consistency = on
#binlog
log_bin = master-bin
log-slave-updates = 1
binlog_format = row
sync-master-info = 1
sync_binlog = 1
#relay log
skip_slave_start = 1
read_only = on
配置完成之后,別忘了重啟Mysql
[root@mysql-slave3 ~]# /etc/init.d/mysql restart
Shutting down MySQL.. [ OK ]
Starting MySQL... [ OK ]
恢復全備
[root@mysql-slave3 ~]# ls 205_slave.sql
205_slave.sql
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.00 sec)
mysql> source /root/205_slave.sql;
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| kevin |
| mysql |
| performance_schema |
| test |
+--------------------+
5 rows in set (0.00 sec)
mysql> select * from kevin.haha;
+----+-----------+
| id | name |
+----+-----------+
| 1 | congcong |
| 2 | huihui |
| 3 | grace |
| 10 | heifei |
| 11 | huoqiu |
| 12 | chengxihu |
| 20 | lanzhou |
| 21 | zhongguo |
+----+-----------+
8 rows in set (0.00 sec)
先檢查一下新的slave節點上當前的gtid:
mysql> show global variables like 'gtid_%';
+---------------+------------------------------------------+
| Variable_name | Value |
+---------------+------------------------------------------+
| gtid_executed | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-7 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-7 |
+---------------+------------------------------------------+
4 rows in set (0.00 sec)
由於新的slave庫是從master主庫恢復過來的,gtid_purged現在自動就有了值1-11,並不需要手動的執行"reset master; set global gtid_purged = 'xxxxx';",
(只有在@@global.gtid_executed為空的情況下,才可以動態設置@@global.gtid_purged, 可以通過RESET MASTER的方式來清空@@global.gtid_executed)
在新的slave節點上直接開啟復制就行了
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> change master to master_host='172.16.60.205',master_user='slave',master_password='slave@123',master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.36 sec)
mysql> start slave;
Query OK, 0 rows affected (0.03 sec)
mysql> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.16.60.205
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-bin.000007
Read_Master_Log_Pos: 191
Relay_Log_File: mysql-relay-bin.000002
Relay_Log_Pos: 363
Relay_Master_Log_File: master-bin.000007
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...........
...........
Retrieved_Gtid_Set:
Executed_Gtid_Set: 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-7
Auto_Position: 1
1 row in set (0.00 sec)
ERROR:
No query specified
接着回到master數據庫查看
mysql> show master status;
+-------------------+----------+--------------+------------------+------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+------------------------------------------+
| master-bin.000007 | 191 | | | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-7 |
+-------------------+----------+--------------+------------------+------------------------------------------+
1 row in set (0.00 sec)
mysql> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID |
+-----------+------+------+-----------+--------------------------------------+
| 207 | | 3306 | 205 | d743d65c-14b8-11e9-a9fb-005056ac05b5 |
| 208 | | 3306 | 205 | 9b499047-14ca-11e9-aa6e-005056ac5b56 |
+-----------+------+------+-----------+--------------------------------------+
2 rows in set (0.00 sec)
可以發現,master主庫的從庫現在已經有兩個slave從節點了,新添加的172.16.60.208的slave從節點已經加進去了!
在master主數據庫插入新數據
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into kevin.haha values(30,"bobo"),(31,"huahua");
Query OK, 2 rows affected (0.04 sec)
Records: 2 Duplicates: 0 Warnings: 0
查看兩個slave從節點,發現master上新插入的數據已經同步到兩個slave從節點數據庫里了
mysql> select * from kevin.haha;
+----+-----------+
| id | name |
+----+-----------+
| 1 | congcong |
| 2 | huihui |
| 3 | grace |
| 10 | heifei |
| 11 | huoqiu |
| 12 | chengxihu |
| 20 | lanzhou |
| 21 | zhongguo |
| 30 | bobo |
| 31 | huahua |
+----+-----------+
10 rows in set (0.00 sec)
到此,新slave節點已經成功加入到master中了,一主兩從架構也部署完成了。
另外,再追加更多slave節點,做成一主多從架構,部署方法和上面一樣。
注意上面的172.16.60.206 slave節點問題
在上面"重新GTID主從復制"的操作中, 新節點172.16.60.207作為新的slave從庫后,之前的slave從庫172.16.60.206的同步關系失效了!一是通過"show global variables like 'gtid_%';"命令查看gtid和master的gtid不一樣導致數據不能保持同步!也有可能出現下面的報錯(通過"show slave status \G;"命令查看):Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'could not find next log; the first event '' at 4, the last event read from './master-bin.000002' at 2952, the last byte read from './master-bin.000002' at 2952.'
這個時候如果想要重新將172.16.60.206節點添加為master主庫的slave節點,即恢復和master節點的主從復制關系,則操作方法和上面差不多,記錄如下:
1)在172.16.60.205的master主數據庫上的操作
mysql> FLUSH TABLE WITH READ LOCK;
Query OK, 0 rows affected (0.00 sec)
[root@mysql-master ~]# mysqldump -u root -p'123456' --lock-all-tables --master-data=2 --flush-logs --all-databases --triggers --routines --events > 206_slave.sql
[root@mysql-master ~]# ls 206_slave.sql
206_slave.sql
[root@mysql-master ~]# rsync -e "ssh -p22" -avpgolr 206_slave.sql root@172.16.60.206:/root/
查看此時master上的GTID
mysql> show global variables like 'gtid_%';
+---------------+-------------------------------------------+
| Variable_name | Value |
+---------------+-------------------------------------------+
| gtid_executed | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-18 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | |
+---------------+-------------------------------------------+
4 rows in set (0.00 sec)
同時可以在其他兩個slave節點(172.16.60.207/208)同樣執行"show global variables like 'gtid_%';"
發現這兩個slave節點的GTID和master的GTID是一樣的!
2)在172.16.60.206的slave數據庫上的操作
[root@mysql-slave ~]# ls /root/206_slave.sql
/root/206_slave.sql
查看此時該slave節點上的GTID
mysql> show global variables like 'gtid_%';
+---------------+-------------------------------------------------------------------------------------+
| Variable_name | Value |
+---------------+-------------------------------------------------------------------------------------+
| gtid_executed | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-12,
77624378-14b9-11e9-a9ff-005056ac509b:1-4 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | |
+---------------+-------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)
發現此時172.16.60.206這個slave節點的GTID和master節點以及其他兩個slave節點的GTID不一樣!
所以172.16.60.206不能和172.16.60.205保持主從復制關系了(即在172.16.60.206數據庫上執行"show slave status \G;"會有上面的報錯)
現在將從172.16.60.205 master主數據庫上備份過來的數據導入到172.16.60.206 slave數據庫中
mysql> source /root/206_slave.sql;
接着再次重啟slave
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected (0.06 sec)
然后再次查看slave同步狀態
mysql> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.16.60.205
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-bin.000009
Read_Master_Log_Pos: 191
Relay_Log_File: mysql-relay-bin.000006
Relay_Log_Pos: 403
Relay_Master_Log_File: master-bin.000009
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
.........
.........
Retrieved_Gtid_Set: 71fffa5a-14b9-11e9-a9ff-0050568843f8:13-18
Executed_Gtid_Set: 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-18,
77624378-14b9-11e9-a9ff-005056ac509b:1-4
Auto_Position: 1
1 row in set (0.00 sec)
ERROR:
No query specified
發現172.16.60.206 slave節點已經和172.16.60.205 master節點恢復了主從復制關系。
即IO和SQL的狀態都為YES!
再次看看172.16.60.206 slave節點的GTID,發現和master節點以及其他兩個slave節點的GTID一樣了。
mysql> show global variables like 'gtid_%';
+---------------+-------------------------------------------------------------------------------------+
| Variable_name | Value |
+---------------+-------------------------------------------------------------------------------------+
| gtid_executed | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-18,
77624378-14b9-11e9-a9ff-005056ac509b:1-4 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | |
+---------------+-------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)
再次查看172.16.60.205 master主數據庫上
mysql> show global variables like 'gtid_%';
+---------------+-------------------------------------------+
| Variable_name | Value |
+---------------+-------------------------------------------+
| gtid_executed | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-18 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | |
+---------------+-------------------------------------------+
4 rows in set (0.00 sec)
mysql> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID |
+-----------+------+------+-----------+--------------------------------------+
| 207 | | 3306 | 205 | d743d65c-14b8-11e9-a9fb-005056ac05b5 |
| 206 | | 3306 | 205 | 77624378-14b9-11e9-a9ff-005056ac509b |
| 208 | | 3306 | 205 | 9b499047-14ca-11e9-aa6e-005056ac5b56 |
+-----------+------+------+-----------+--------------------------------------+
3 rows in set (0.00 sec)
通過上面結果可看出,172.16.60.206已經恢復了和172.16.60.205 master節點的主從復制關系了。
即172.16.60.205 master節點有三個slave節點,
現在在172.16.60.205 master節點插入新數據
mysql> insert into kevin.haha values(40,"shanghai"),(41,"beijing");
Query OK, 2 rows affected (0.03 sec)
Records: 2 Duplicates: 0 Warnings: 0
在其他三個slave節點查看,發現新數據都正常復制過去了
mysql> select * from kevin.haha;
+----+-----------+
| id | name |
+----+-----------+
| 1 | congcong |
| 2 | huihui |
| 3 | grace |
| 10 | heifei |
| 11 | huoqiu |
| 12 | chengxihu |
| 20 | lanzhou |
| 21 | zhongguo |
| 30 | bobo |
| 31 | huahua |
| 40 | shanghai |
| 41 | beijing |
+----+-----------+
12 rows in set (0.00 sec)
溫馨提示:上面這種操作也是在slave從庫出現"數據同步失敗"或"slave同步故障“時進行重做GTID主從復制的一種有效有段!!!
GTID主從復制 故障轉移 (failover)
現在172.16.60.205為master主庫,分別有三個slave從庫:
mysql> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID |
+-----------+------+------+-----------+--------------------------------------+
| 207 | | 3306 | 205 | 1e14b008-14f0-11e9-ab63-005056ac05b5 |
| 206 | | 3306 | 205 | 26ca2900-14f0-11e9-ab63-005056ac509b |
| 208 | | 3306 | 205 | 2147a0ce-14f0-11e9-ab63-005056ac5b56 |
+-----------+------+------+-----------+--------------------------------------+
3 rows in set (0.00 sec)
如果現在172.16.60.205主庫發生故障,比如mysql宕了
[root@mysql-master ~]# /etc/init.d/mysql stop
Shutting down MySQL.... [ OK ]
[root@mysql-master ~]# lsof -i:3306
然后在三個slave節點上通過"show slave status \G;"查看同步狀態,會出現"Slave_IO_Running: Connecting"
即此時的主從復制關系失效了!
現在要做的就是:選取最新的slave作為master,比如選擇172.16.60.208節點作為master主庫。
操作如下:
172.16.60.208節點上打開讀寫功能,即surper_read_only=off
[root@mysql-slave3 ~]# vim /usr/local/mysql/my.cnf
........
#read_only = on
[root@mysql-slave3 ~]# /etc/init.d/mysql restart
Shutting down MySQL.. [ OK ]
Starting MySQL.. [ OK ]
mysql> show variables like '%read_only%';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| innodb_read_only | OFF |
| read_only | OFF |
| tx_read_only | OFF |
+------------------+-------+
3 rows in set (0.00 sec)
mysql> grant replication slave,replication client on *.* to slave@'172.16.60.206' identified by "slave@123";
Query OK, 0 rows affected (0.15 sec)
mysql> grant replication slave,replication client on *.* to slave@'172.16.60.207' identified by "slave@123";
Query OK, 0 rows affected (0.04 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.04 sec)
查看gtid
mysql> show global variables like 'gtid_%';
+---------------+-------------------------------------------+
| Variable_name | Value |
+---------------+-------------------------------------------+
| gtid_executed | 59a1b34c-14f0-11e9-ab65-0050568843f8:1-12 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | 59a1b34c-14f0-11e9-ab65-0050568843f8:1-9 |
+---------------+-------------------------------------------+
4 rows in set (0.00 sec)
然后在172.16.60.206/207兩個slave節點上執行下面命令,即以172.16.60.208為master的同步復制關系:
mysql> stop slave;
Query OK, 0 rows affected (0.17 sec)
mysql> change master to master_host='172.16.60.208',master_user='slave',master_password='slave@123',master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.18 sec)
mysql> start slave;
Query OK, 0 rows affected (0.05 sec)
mysql> show slave status \G;
...............
...............
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...............
...............
Retrieved_Gtid_Set: 2147a0ce-14f0-11e9-ab63-005056ac5b56:1-3
Executed_Gtid_Set: 2147a0ce-14f0-11e9-ab63-005056ac5b56:1-3,
59a1b34c-14f0-11e9-ab65-0050568843f8:1-12
Auto_Position: 1
分別查看172.16.60.206/207兩個slave節點的gtid
mysql> show global variables like 'gtid_%';
+---------------+-------------------------------------------------------------------------------------+
| Variable_name | Value |
+---------------+-------------------------------------------------------------------------------------+
| gtid_executed | 2147a0ce-14f0-11e9-ab63-005056ac5b56:1-3,
59a1b34c-14f0-11e9-ab65-0050568843f8:1-12 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | 59a1b34c-14f0-11e9-ab65-0050568843f8:1-5 |
+---------------+-------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)
mysql> show global variables like 'gtid_%';
+---------------+-------------------------------------------------------------------------------------+
| Variable_name | Value |
+---------------+-------------------------------------------------------------------------------------+
| gtid_executed | 2147a0ce-14f0-11e9-ab63-005056ac5b56:1-3,
59a1b34c-14f0-11e9-ab65-0050568843f8:1-12 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | 59a1b34c-14f0-11e9-ab65-0050568843f8:1-5 |
+---------------+-------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)
由上面可看出,172.16.60.206/207兩個slave節點的gtid和172.16.60.208節點的gtid是一樣的,因為他們的數據會保持一致性同步!
在172.16.60.208節點上查看,發現172.16.60.206/207已經成為了它的兩個slave從庫!
mysql> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID |
+-----------+------+------+-----------+--------------------------------------+
| 206 | | 3306 | 208 | 26ca2900-14f0-11e9-ab63-005056ac509b |
| 207 | | 3306 | 208 | 1e14b008-14f0-11e9-ab63-005056ac05b5 |
+-----------+------+------+-----------+--------------------------------------+
2 rows in set (0.00 sec)
由此可見,當之前的master主庫172.16.60.205發生故障后,選取其中的一個slave從庫172.16.60.208為新的master主庫,
然后其余的slave從庫以這個選出來的節點作為主庫!
在172.16.60.208主庫上插入新數據
mysql> insert into kevin.haha values(200,"haoshen"),(201,"haoren");
Query OK, 2 rows affected (0.15 sec)
Records: 2 Duplicates: 0 Warnings: 0
然后在172.16.60.206/207從庫節點上查看,發現新數據已經同步過來了!
mysql> select * from kevin.haha;
+-----+-----------+
| id | name |
+-----+-----------+
| 1 | congcong |
| 2 | huihui |
| 3 | grace |
| 10 | heifei |
| 11 | huoqiu |
| 12 | chengxihu |
| 20 | lanzhou |
| 21 | zhongguo |
| 30 | bobo |
| 31 | huahua |
| 40 | shanghai |
| 41 | beijing |
| 200 | haoshen |
| 201 | haoren |
+-----+-----------+
14 rows in set (0.00 sec)
特別注意:
1) 同一組主從復制節點的GTID一定要保持一致!(通過"show global variables like 'gtid_%';"命令查看),否則slave從庫的數據就不會和master主庫數據保持一致!
2) Mysql基於GTID還可以做主主同步, 即雙方相互授予同步復制權限給對方, 並且設置讀寫權限 (#read_only=on, 即注釋掉只讀配置, 這個只是限制非super用戶, 對於具有super權限的用戶來說限制不來), 然后雙方相互執"stop slave", "change master to......", "start slave"同步操作即可實現主主同步.
3) 生產環境中, 可以做多主多從, 比如"兩主三從", 兩主通過keepalived對外提供統一的出口ip, 負責寫操作; 三個從節點負責讀操作, 並通過LVS進行讀操作的負載均衡, (從節點跟主節點的vip做主從同步);
4) 主從可以通過腳本進行自動切換. 下面是測試中使用的一個主從自動切換的腳本:
下面腳本中:
1) 172.16.60.211是主節點, 主節點的my.cnf文件中提前配置好"# read_only=on" (先注釋掉, 為了配置自動切換的腳本 );
2) 172.16.60.212是從節點; 從節點也要提前給主節點授予同步復制的權限 (因為主節點故障恢復后, 會自動變為新的從節點, 需要進行主從同步操作)
3) 主從節點各自安裝和配置keepalived;
3) 172.16.60.94 是VIP地址;
腳本內容如下:
172.16.60.211的主節點操作如下
[root@mysql-master01 ~]# mkdir -p /home/mysql
[root@mysql-master01 ~]# touch /home/mysql/remove_slave.log
[root@mysql-master01 ~]# vim /home/mysql/remove_slave.sh
#!/bin/bash
user=root
password=123456
log=/home/mysql/remove_slave.log
/usr/bin/mysql -u$user -p$password -e "show databases" >/dev/null 2>&1
a=$?
/usr/sbin/ip addr|grep 172.16.60.94
b=$?
if [ $a -eq 0 -a $b -eq 0 ];then
\cp -f /etc/my.cnf /etc/my_monit.cnf
/bin/sed -i 's/^'read_only'/'#read_only'/g' /etc/my.cnf
diff /etc/my.cnf /etc/my_monit.cnf
c=$?
if [ $c -ne 0 ]; then
echo -e "\n$(date) \n172.16.60.211 機器之前是mysql從節點,但是現在變成了mysql主節點" >> $log
systemctl restart mysqld
mysql -u$user -p$password -e "stop slave;" >/dev/null 2>&1
else
echo -e "\n$(date) \n172.16.60.211 機器現在是mysql主節點" >> $log
fi
else
\cp -f /etc/my.cnf /etc/my_monit.cnf
/bin/sed -i 's/^'#read_only'/'read_only'/g' /etc/my.cnf
diff /etc/my.cnf /etc/my_monit.cnf
d=$?
if [ $d -ne 0 ]; then
echo -e "\n$(date) \n172.16.60.211 機器之前是mysql主節點,但是現在變成了mysql從節點" >> $log
systemctl restart mysqld
mysql -u$user -p$password -e "stop slave;" >/dev/null 2>&1
mysql -u$user -p$password -e " change master to master_host='172.16.60.212',master_user='slave',master_password='slave@123',master_auto_position=1;" >/dev/null 2>&1
mysql -u$user -p$password -e "start slave;" >/dev/null 2>&1
else
echo -e "\n$(date) \n172.16.60.211 機器現在是mysql從節點" >> $log
fi
fi
===================================================================
172.16.60.212的從節點操作如下:
[root@mysql-master01 ~]# mkdir -p /home/mysql
[root@mysql-master01 ~]# touch /home/mysql/remove_slave.log
[root@mysql-master01 ~]# vim /home/mysql/remove_slave.sh
#!/bin/bash
user=root
password=123456
log=/home/mysql/remove_slave.log
/usr/bin/mysql -u$user -p$password -e "show databases" >/dev/null 2>&1
a=$?
/usr/sbin/ip addr|grep 172.16.60.94
b=$?
if [ $a -eq 0 -a $b -eq 0 ];then
\cp -f /etc/my.cnf /etc/my_monit.cnf
/bin/sed -i 's/^'read_only'/'#read_only'/g' /etc/my.cnf
diff /etc/my.cnf /etc/my_monit.cnf
c=$?
if [ $c -ne 0 ]; then
echo -e "\n$(date) \n172.16.60.212 機器之前是mysql從節點,但是現在變成了mysql主節點" >> $log
systemctl restart mysqld
mysql -u$user -p$password -e "stop slave;" >/dev/null 2>&1
else
echo -e "\n$(date) \n172.16.60.212 機器現在是mysql主節點" >> $log
fi
else
\cp -f /etc/my.cnf /etc/my_monit.cnf
/bin/sed -i 's/^'#read_only'/'read_only'/g' /etc/my.cnf
diff /etc/my.cnf /etc/my_monit.cnf
d=$?
if [ $d -ne 0 ]; then
echo -e "\n$(date) \n172.16.60.212 機器之前是mysql主節點,但是現在變成了mysql從節點" >> $log
systemctl restart mysqld
mysql -u$user -p$password -e "stop slave;" >/dev/null 2>&1
mysql -u$user -p$password -e " change master to master_host='172.16.60.211',master_user='slave',master_password='slave@123',master_auto_position=1;" >/dev/null 2>&1
mysql -u$user -p$password -e "start slave;" >/dev/null 2>&1
else
echo -e "\n$(date) \n172.16.60.212 機器現在是mysql從節點" >> $log
fi
fi
