MySQL(三)MySQL-5.7.20 主從複製實戰(半同步複製、過濾複製、GTID模式)
技術標籤:資料庫&訊息佇列資料庫mysql
MySQL-5.7.20二進位制主從複製實戰(半同步複製、過濾複製、GTID模式)
文章目錄
一、半同步複製
半同步複製的原理
半同步複製時,為了保證主庫上的每一個Binlog事務都能夠被可靠的複製到從庫上,主庫在每次事務成功提交時,並不及時反饋給前端應用使用者,而是等待其中的一個從庫也接收到Binlog事務併成功寫入中繼日誌後,出庫才返回commit操作成功給客戶端。半同步複製保證了事務成功提交後,至少有兩份日誌記錄,一份在主庫的Binlog日誌上,另一份在至少一個從庫的中繼日誌Relay log上,從而更近一步保證了資料的完整性。
半同步複製先決條件
前文已經有二進位制多例項主從複製的文件,本文件不再從新開啟主從複製,如果沒有開啟請點選:二進位制主從複製
在做半同步複製前請保證開啟了主從同步
半同步複製實戰
載入sync外掛
[mark_d]注意:主庫與從庫載入的外掛不是同一個!!![/mark_d]
[[email protected] ~]# mysql -S /opstands/mysql-3307/mysql.sock -e "install plugin rpl_semi_sync_master soname 'semisync_master.so';"
[[email protected] ~]# mysql -S /opstands/mysql-3308/mysql.sock -e "install plugin rpl_semi_sync_slave soname 'semisync_slave.so';"
檢視外掛
[[email protected] ~]# mysql -S /opstands/mysql-3307/mysql.sock -e "show plugins" |grep rpl_semi_sync
rpl_semi_sync_master ACTIVE REPLICATION semisync_master.so GPL
[[email protected] ~]# mysql -S /opstands/mysql-3308/mysql.sock -e "show plugins" |grep rpl_semi_sync
rpl_semi_sync_slave ACTIVE REPLICATION semisync_slave.so GPL
啟動半同步
注意: 外掛名稱不一樣
[[email protected] ~]# mysql -S /opstands/mysql-3307/mysql.sock -e "set global rpl_semi_sync_master_enabled = 1;"
[[email protected] ~]# mysql -S /opstands/mysql-3308/mysql.sock -e "set global rpl_semi_sync_slave_enabled= 1 ;"
重啟從庫IO執行緒
[[email protected] ~]# mysql -S /opstands/mysql-3308/mysql.sock -e "stop slave io_thread;"
[[email protected] ~]# mysql -S /opstands/mysql-3308/mysql.sock -e "start slave io_thread;"
檢視是否執行
[root@mysql-manager ~]# mysql -S /opstands/mysql-3307/mysql.sock -e "show status like 'Rpl_semi_sync_master_status';"
+-----------------------------+-------+
| Variable_name | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_status | ON |
+-----------------------------+-------+
[root@mysql-manager ~]# mysql -S /opstands/mysql-3308/mysql.sock -e "show status like 'Rpl_semi_sync_slave_status';"
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON |
+----------------------------+-------+
二、過濾複製
複製的過濾主要有2種方式
- 在主伺服器在把事件從進二制日誌中過濾掉,相關的引數是:binlog_do_db和binlog_ignore_db。
- 在從伺服器上把事件從中繼日誌中過濾掉,相關的引數是replicate_*。
- 複製只能擴充套件讀取,不能擴充套件寫入,對資料進行分割槽可以進行擴充套件寫入。
複製的優化:
在mysql複製環境中,有8個引數可以讓我們控制,需要複製或需要忽略不進行復制的DB或table。
下面二項需要在Master上設定:
- Binlog_Do_DB:設定哪些資料庫需要記錄Binlog
- Binlog_Ignore_DB:設定哪裡資料庫不需要記錄Binlog
- 優點是Master端的Binlog記錄所帶來的Io量減少,網路IO減少,還會讓slave端的IO執行緒,SQL執行緒減少,從而大幅提高複製效能,
- 缺點是mysql判斷是否需要複製某個事件不是根據產生該事件的查詢所在的DB,而是根據執行查詢時刻所在的預設資料庫(也就是登入時指定的庫名或執行”use database”中指定的DB),只有當前預設DB和配置中所設定的DB完全吻合時IO執行緒才會將該事件讀取給slave的IO執行緒.所以,如果在預設DB和設定須要複製的DB不一樣的情況下改變了須要複製的DB中某個Table中的資料,該事件是不會被複制到Slave中去的,這樣就會造成Slave端的資料和Master的資料不一致.同樣,在預設的資料庫下更改了不須要複製的資料庫中的資料,則會被複制到slave端,當slave端並沒有該資料庫時,則會造成複製出錯而停止。
下面六項需要在slave上設定:
- Replicate_Do_DB:設定需要複製的資料庫,多個DB用逗號分隔
- Replicate_Ignore_DB:設定可以忽略的資料庫.
- Replicate_Do_Table:設定需要複製的Table
- Replicate_Ignore_Table:設定可以忽略的Table
- Replicate_Wild_Do_Table:功能同Replicate_Do_Table,但可以帶萬用字元來進行設定。
- Replicate_Wild_Ignore_Table:功能同Replicate_Do_Table,功能同Replicate_Ignore_Table,可以帶萬用字元。
- 優點是在slave端設定複製過濾機制,可以保證不會出現因為預設的資料庫問題而造成Slave和Master資料不一致或複製出錯的問題.
- 缺點是效能方面比在Master端差一些.原因在於:不管是否須要複製,事件都會被IO執行緒讀取到Slave端,這樣不僅增加了網路IO量,也給Slave端的IO執行緒增加了Relay Log的寫入量。
主從過濾的注意事項:
- 使用replicate_do_db和replicate_ignore_db時有一個隱患,跨庫更新時會出錯。
- 如在Master(主)伺服器上設定 replicate_do_db=test(my.conf中設定)
主從複製過濾複製先決條件
前文已經有二進位制多例項主從複製的文件,本文件不再從新開啟主從複製,如果沒有開啟請點選:二進位制主從複製
在做過濾複製前請保證開啟了主從同步
主從複製過濾複製實戰
新增配置檔案白名單引數
[[email protected] ~]# echo 'replicate_do_db=olda' >> /opstands/mysql-3308/my.cnf
# -----------------------------------------------------
# replicate_ignore_db是黑名單,用法和白名單一樣
重啟3308例項
[[email protected] ~]# systemctl restart mysqld-3308.service
檢視過濾複製的資訊
[[email protected] ~]# mysql -S /opstands/mysql-3308/mysql.sock -e "show slave status\G" |egrep 'Replicate_Do_DB:|Replicate_Ignore_DB:'
Replicate_Do_DB: olda
Replicate_Ignore_DB:
現在主從複製只會同步olda庫的資料
三、GTID模式
GTID優勢
- 更簡單的實現 failover,不用以前那樣在需要找 log_file 和 log_Pos。
- 更簡單的搭建主從複製。
- 複製叢集有一個統一的方式識別複製位置,給叢集管理帶來了便利。
- 正常情況下,GTID 是連續沒有空洞的,因此主從庫出現數據衝突時,可以用新增空事物的方式進行跳過。
GTID的限制
- 在一個事務裡面混合使用引擎,如 Innodb(支援事務)、MyISAM(不支援事務), 造成多個 GTIDs 和同一個事務相關聯出錯
- CREATE TABLE……SELECT 不能使用,該語句產生的兩個 event 在某一情況 會使用同一個 GTID(同一個 GTID 在 slave 只能被使用一次)
1th event:建立表語句 create table
2th event:插入資料語句 insert - CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE 不能在事務內使用 (啟用了–enforce-gtid-consistency 引數)。
GTID的工作原理
1、master更新資料時,會在事務前產生GTID,一同記錄到binlog日誌中。
2、slave端的i/o 執行緒將變更的binlog,寫入到本地的relay log中。
3、sql執行緒從relay log中獲取GTID,然後對比slave端的binlog是否有記錄。
4、如果有記錄,說明該GTID的事務已經執行,slave會忽略。
5、如果沒有記錄,slave就會從relay log中執行該GTID的事務,並記錄到binlog。
6、在解析過程中會判斷是否有主鍵,如果沒有就用二級索引,如果沒有就用全部掃描。
- server_uuid是MySQL Server的只讀變數,儲存在資料目錄下的auto.cnf中,可直接通過cat命令檢視。MySQL第一次啟動時候建立auto.cnf檔案,並生成server_uuid(MySQL使用機器網絡卡,當前時間,隨機數等拼接成一個128bit的uuid,可認為在全宇宙都是唯一的,在未來一百年,使用同樣的演算法生成的uuid是不會衝突的)。之後MySQL再啟動時不會重複生成uuid,而是使用auto.cnf中的uuid。
- 在同一個叢集內,每個MySQL例項的server_uuid必須唯一,否則同步時,會造成IO執行緒不停的中斷,重連。在通過備份恢復資料時,一定要將var目錄中的auto.cnf刪掉,讓MySQL啟動時自己生成uuid
- GTID中還有一部分是transaction_id,同一個server_uuid下的transaction_id一般是遞增的。如果一個事務是通過使用者執行緒執行,那麼MySQL在生成的GTID時,會使用它自己的server_uuid,然後再遞增一個transaction_id作為該事務的GTID。當然,如果事務是通過SQL執行緒回放relay-log時產生,那麼GTID就直接使用binlog裡的了。在MySQL 5.6中不用擔心binlog裡沒有GTID,因為如果從庫開啟了GTID模式,主庫也必須開啟,否則IO執行緒在建立連線的時候就中斷了。5.6的GTID對MySQL的叢集環境要求是非常嚴格的,要麼主從全部開啟GTID模式,要麼全部關閉GTID模式。
- 使用server_uuid:transaction_id共同組成一個GTID的好處是,由於server_uuid唯一,即使一個叢集內多個節點同時有寫入,也不會造成GTID衝突。
GTID的使用
- MySQL通過全域性變數gtid_mode控制開啟/關閉GTID模式。但是gtid_mode是隻讀的,可新增到配置檔案中,然後重啟mysqld來開啟GTID模式。
GTID原理
- 我們知道,在未開啟GTID模式的情況下,從庫用(File_name和File_pos)二元組標識執行到的位置。START SLAVE時,從庫會先向主庫傳送一個BINLOG_DUMP命令,在BINLOG_DUMP命令中指定File_name和File_pos,主庫就從這個位置開始傳送binlog。
- 在開啟GTID模式的情況下,如果指定MASTER_AUTO_POSITION=1。START SLAVE時,從庫會計算Retrieved_Gtid_Set和Executed_Gtid_Set的並集(通過SHOW SLAVE STATUS可以檢視),然後把這個GTID並集傳送給主庫。主庫會使用從庫請求的GTID集合和自己的gtid_executed比較,把從庫GTID集合裡缺失的事務全都發送給從庫。如果從庫缺失的GTID,已經被主庫pruge了呢?從庫報1236錯誤,IO執行緒中斷。
- 通過GTID找到點兒的原理還是比較奇怪的,它過於強調主從binlog中GTID集合的一致性,弱化了Binlog執行的順序性。
pos 與 GTID 有什麼區別?
- 兩者都是日誌檔案裡事件的一個標誌,如果將整個 mysql 叢集看作一個整體,pos就是區域性的,GTID就是全域性的.
- 一主兩從,在 master,slave1,slave2 日誌檔案裡的 pos,都各不相同,就是一個 event,在 master 的日誌裡,pos 可能是 700,而在 slave1,slave2 裡,pos 可能就是 300,400 了,因為眾多 slave 也可能不是同時加入叢集的,不是從同一個位置進行同步.
- 而 GTID,在 master,slave1,slave2 各自的日誌檔案裡,同一個 event 的 GTID 值都是一樣的.
GTID模式主從複製先決條件
前文已經有二進位制多例項安裝的文件,本文件不再從新安裝,如果沒有安裝請點選:二進位制多例項安裝
[[email protected] ~]# mkdir -p /opstands/mysql-5.7.20/binlog
GTID模式主從複製實戰
本文將使用MySQL-3306例項為主節點,MySQL3309例項為從節點。
開啟binlog日誌與GTID
[[email protected] ~]# sed -i '7a log_bin=/opstands/mysql-5.7.20/binlog/mysql-bin' /etc/my.cnf
[[email protected] ~]# sed -i '8a binlog_format=row' /etc/my.cnf
[[email protected] ~]# sed -i '9a sync_binlog=1' /etc/my.cnf
[[email protected] ~]# sed -i '10a gtid_mode=ON' /etc/my.cnf
[[email protected] ~]# sed -i '11a enforce_gtid_consistency' /etc/my.cnf
[[email protected] ~]# cat >> /opstands/mysql-3309/my.cnf <<EOF
gtid_mode=ON
enforce_gtid_consistency
EOF
授權
[[email protected] ~]# chown -R mysql.mysql /opstands/mysql-*
重啟3306與3309例項
[[email protected] ~]# systemctl restart mysqld.service
[[email protected] ~]# systemctl restart mysqld-3309.service
檢視是否開啟GTID
[root@mysql-manager ~]# mysql -uroot -predhat -e "show variables like '%gtid_%';"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON | <------- 是否開啟GTID
| gtid_executed_compression_period | 1000 |
| gtid_mode | ON | <-------是否啟用GTID模組
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-----------+
[root@mysql-manager ~]# mysql -S /opstands/mysql-3309/mysql.sock -e "show variables like '%gtid_%';"
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON | <------- 是否開啟GTID
| gtid_executed_compression_period | 1000 |
| gtid_mode | ON | <-------是否啟用GTID模組
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-----------+
建立主從複製使用者
[[email protected] ~]# mysql -uroot -predhat -e "grant replication slave on *.* to [email protected]'%' identified by 'redhat';"
開啟GTID主從複製
# 進入3309例項資料庫內開啟GTID連線到3306例項
[root@mysql-manager ~]# mysql -S /opstands/mysql-3309/mysql.sock
mysql> CHANGE MASTER TO
-> MASTER_HOST='172.18.1.79',
-> MASTER_USER='rep',
-> MASTER_PASSWORD='redhat',
-> MASTER_PORT=3306,
-> MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected, 2 warnings (0.02 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
檢視主從複製狀態
[root@mysql-manager mysql-3309]# mysql -S /opstands/mysql-3309/mysql.sock -e "show slave status\G;" |egrep 'Slave_IO_Running:|Slave_SQL_Running:|Seconds_Behind_Master:'
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master: 0
測試GTID模式主從複製效果
可以看到當前兩個例項都沒有olda庫,接下來在3306庫建立olda庫,然後檢視3309庫是否有同步。
[root@mysql-manager ~]# mysql -uroot -predhat -e "show databases;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
[root@mysql-manager mysql-3309]# mysql -S /opstands/mysql-3309/mysql.sock -e "show databases;"
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
檢視結果
可以看到3309例項從庫也同步建立了olda庫
[root@mysql-manager ~]# mysql -uroot -predhat -e "create database olda charset utf8mb4;"
mysql: [Warning] Using a password on the command line interface can be insecure.
[root@mysql-manager ~]# mysql -uroot -predhat -e "show databases;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| olda |
| performance_schema |
| sys |
+--------------------+
[root@mysql-manager mysql-3309]# mysql -S /opstands/mysql-3309/mysql.sock -e "show databases;"
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| olda |
| performance_schema |
| sys |
+--------------------+
sys |
+--------------------+
[root@mysql-manager mysql-3309]# mysql -S /opstands/mysql-3309/mysql.sock -e "show databases;"
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| olda |
| performance_schema |
| sys |
+--------------------+