MySQL之七---Mysql實現數據庫主從複製、主主複製、級聯複製、半同步複製及複製監控

MySQL複製

(1)擴展方式: Scale Up ,Scale Outhtml

(2)MySQL的擴展mysql

 讀寫分離
 複製:每一個節點都有相同的數據集
 向外擴展
 二進制日誌
 單向

(3)複製的功用:linux

 數據分佈
 負載均衡讀
 備份
 高可用和故障切換
 MySQL升級測試

一主多從  

 

主從複製介紹

兩臺或兩臺以上實例,經過binlog實現最終數據同步關係;sql

主從複製前提(搭建過程)

 a.至少兩臺MySQL實例,server_id,server_uuid不一樣;
 b.主庫要開binlog
 c.專用的複製用戶和權限
 d.預同步主庫數據到從庫
 e.告訴從庫鏈接\同步起點
 f.啓動複製線程

主從複製搭建(Classic replication)

配置主庫數據庫

  1. 安裝 mysql 8.0.20 二進制包vim

  2. 配置二進制文件路徑,server_id緩存

 cat > /etc/my.cnf <<EOF
 [mysqld]
 user=mysql
 basedir=/usr/local/mysql
 datadir=/data/3306/data
 port=3306
 socket=/tmp/mysql.sock
 server_id=10
 log_bin=/data/3306/data/binlog
 plugin-load-add=mysql_clone.so
 clone=FORCE_PLUS_PERMANENT
 [client]
 socket=/tmp/mysql.sock
 EOF
  1. 重啓MySQL安全

 systemctl restart mysqld
  1. 驗證二進制日誌,clone插件是否開啓,server_id,server_uuid是否和從庫不一樣bash

 select @@log_bin;
 select @@log_bin_basename;
 select @@server_id;
 select @@server_uuid;
 SELECT PLUGIN_NAME, PLUGIN_STATUS
 FROM INFORMATION_SCHEMA.PLUGINS
 WHERE PLUGIN_NAME LIKE 'clone';
  1. 建立複製專用用戶並受權服務器

 create user repl@'10.0.0.%' identified with mysql_native_password by  '123';
 grant replication slave on *.* to repl@'10.0.0.%';
  1. 建立給予端用戶並受權

 CREATE USER 'donor_clone_user'@'%' IDENTIFIED BY '123';
 GRANT BACKUP_ADMIN on *.* to 'donor_clone_user'@'%';
  1. 查看主狀態

 show master status;

配置從庫

  1. 安裝 mysql 8.0.20 二進制包

  2. 配置server_id和主庫不一樣

 cat > /etc/my.cnf <<EOF
 [mysqld]
 user=mysql
 basedir=/usr/local/mysql
 datadir=/data/3306/data
 port=3306
 socket=/tmp/mysql.sock
 server_id=20
 log_bin=/data/3306/data/binlog
 plugin-load-add=mysql_clone.so
 clone=FORCE_PLUS_PERMANENT
 [client]
 socket=/tmp/mysql.sock
 EOF
  1. 重啓MySQL

 systemctl restart mysqld
  1. 驗證server_id,server_uuid是否和從庫不一樣,clone插件是否開啓

 select @@server_id;
 select @@server_uuid;
 SELECT PLUGIN_NAME, PLUGIN_STATUS
 FROM INFORMATION_SCHEMA.PLUGINS
 WHERE PLUGIN_NAME LIKE 'clone';
  1. 建立接受端用戶並受權

 CREATE USER 'recipient_clone_user'@'%' IDENTIFIED BY '123';
 GRANT CLONE_ADMIN on *.* to 'recipient_clone_user'@'%';
  1. 設置主庫IP:端口加入給予主機列表

SET GLOBAL clone_valid_donor_list='10.0.0.51:3306';
  1. 使用克隆用戶鏈接新數據庫

 mysql -urecipient_clone_user -p1 -h10.0.0.61
  1. 執行遠程克隆

 CLONE INSTANCE FROM 'donor_clone_user'@'10.0.0.51':3306 IDENTIFIED BY '123';
  1. 克隆完成,新數據庫自動重啓

  2. 使用root用戶鏈接新數據庫

 mysql -uroot -p123
  1. 查看克隆狀態信息

 mysql> select * from performance_schema.clone_status\G
 *************************** 1. row ***************************
              ID: 1
             PID: 0
           STATE: Completed
      BEGIN_TIME: 2020-11-18 10:22:39.531
        END_TIME: 2020-11-18 10:22:46.824
          SOURCE: 10.0.0.51:3306
     DESTINATION: LOCAL INSTANCE
        ERROR_NO: 0
   ERROR_MESSAGE: 
     BINLOG_FILE: binlog.000021
 BINLOG_POSITION: 276
   GTID_EXECUTED: 1aa38bc6-1cbc-11eb-a6b8-000c29caebef:1-9,
 c985eb8e-2896-11eb-a6af-000c29caebef:1-3,
 d1d0b198-2899-11eb-babe-000c29caebef:1-4
 1 row in set (0.01 sec)
  1. 告訴從庫鏈接信息,從什麼位置點開始自動複製(help change master to

 CHANGE MASTER TO
   MASTER_HOST='10.0.0.51',
   MASTER_USER='repl',
   MASTER_PASSWORD='123',
   MASTER_PORT=3306,
   MASTER_LOG_FILE='binlog.000021',
   MASTER_LOG_POS=276,
   MASTER_CONNECT_RETRY=10;

注意:MASTER_LOG_FILEMASTER_LOG_POS必須和主庫中show master status;查到的一致

  1. 啓動複製線程

 start slave;
  1. 查看從狀態

 show slave status \G

主從複製原理

主從複製線程:

 # 主庫:  
   binlog 二進制日誌
 # 從庫 
   relaylog:中繼日誌,從庫用來臨時存儲接收到的binlog
   master.info:主庫相關信息(ip port user password  已經獲取的binlog 位置點)
   relay-log.info:存儲SQL線程回放過的日誌
   三線程四文件(主庫一個文件,從庫三個文件。主庫一個線程,從庫兩個線程)

主節點:

 dump Thread:爲每一個Slave的I/O Thread啓動一個dump線程,用於向其發送binary log events

從節點:

 I/O Thread:向Master請求二進制日誌事件,並保存於中繼日誌中
 SQL Thread:從中繼日誌中讀取日誌事件,在本地完成重放

主從複製特色:

 異步複製
 主從數據不一致比較常見

複製架構:

 Master/Slave, Master/Master, 環狀複製
 一主多從
 從服務器還能夠再有從服務器
 一從多主:適用於多個不一樣數據庫
 主主

複製須要考慮二進制日誌事件記錄格式

 STATEMENT(5.0以前)
 ROW(5.1以後,推薦)
 MIXED

 

 

 

主從複製(Classic Replication)原理描述:異步複製

  1. 從庫執行 change master to ... 時,將主庫鏈接信息和binlog位置信息寫入master.info文件或者slave_master_info表中

  2. 從庫執行 start slave 時,從庫啓動IO線程和SQL線程

  3. IO線程讀取master.info,獲取主庫信息鏈接主庫

  4. 主庫會生成一個DUMP線程(自動監控binlog變化),來響應從庫

  5. IO線程根據master.info記錄的binlog文件名和position號,請求主庫DUMP最新日誌

  6. DUMP線程檢查主庫的binlog日誌,若是有新的,傳送給從從庫的IO線程,主庫不關心投遞的結果(異步)。

  7. IO線程將收到的日誌存儲到了TCP/IP 緩存

  8. IO線程將緩存中的數據,存儲到relay-log日誌文件,更新master.info文件或者slave_master_info表的binlog 文件名和postion,IO線程工做完成

  9. SQL線程讀取relay-log.info文件或者slave_relay_log_info表,獲取到上次執行到的db02-relay-bin的位置,做爲起點,回放db02-relay-bin

  10. SQL線程回放完成以後,會更新relay-log.info文件。

  11. 回放過的db02-relay-binrelay_log_purge線程會按期刪除這些日誌。

注意:主庫一旦有新的日誌生成,dump 會發送「信號」給從庫 ,IO線程再去請求

主從配置過程:參看官網

https://mariadb.com/kb/en/library/setting-up-replication/ https://dev.mysql.com/doc/refman/5.5/en/replication-configuration.html

常見報錯場景:

  • 通訊故障:

    • 外部網絡問題(防火牆,網絡不通,...)

    • 鏈接信息問題(ip\port\user\passwd)

      • 用戶錯誤

      • 密碼錯誤

       -- 報錯信息:
       
      Slave_IO_Running: Connecting
       Last_IO_Errno: 1045
       Last_IO_Error: error connecting to master 'repl1@10.0.0.51:3306' - retry-time: 10 retries: 2 message: Access denied for user 'repl1'@'10.0.0.61' (using password: YES)
       -- 鏈接測試:
      
       [root@db01 ~]# mysql -urepl  -p123333  -h 10.0.0.51 -P 3306
       mysql: [Warning] Using a password on the command line interface can be insecure.
       ERROR 1045 (28000): Access denied for user 'repl'@'10.0.0.61' (using password: YES)
      

       -- 處理方法:
       stop slave;
       reset slave all;
       change master to ... ;
       start slave;
       show slave status \G
      
      • 地址錯誤

       Slave_IO_Running: Connecting
       Last_IO_Errno: 0
       Last_IO_Error:
      
      • 端口錯誤

       -- 報錯信息:
       Slave_IO_Running: Connecting
       Last_IO_Errno: 2003
       Last_IO_Error: error connecting to master 'repl@10.0.0.51:3307' - retry-time: 10 retries: 1 message: Can't connect to MySQL server on '10.0.0.51' (111)
       -- 鏈接測試:
      
       [root@db01 opt]# mysql -urepl  -p123333  -h 10.0.0.51 -P 3307
       mysql: [Warning] Using a password on the command line interface can be insecure.
       ERROR 2003 (HY000): Can't connect to MySQL server on '10.0.0.51' (111)
      
      • 禁止域名解析:skip_name_resolve

    • 達到最大鏈接數上限

     -- 報錯信息:
     Last_IO_Errno: 1040
     Last_IO_Error: error reconnecting to master 'repl@10.0.0.51:3307' - retry-time: 10  retries: 7
    
     -- 鏈接測試:
     [root@db01 ~]# mysql -urepl -p123 -h 10.0.0.51 -P 3307 
     mysql: [Warning] Using a password on the command line interface can be insecure.
     ERROR 1040 (HY000): Too many connections
     -- 處理方法:
     set global max_connections=1024;
  • 請求二進制日誌故障:

    • 主庫二進制日誌文件名錯誤或缺失

     Slave_IO_Running: No
     Last_IO_Errno: 13114
     Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 
    'Could not find first log file name in binary log index file'
    • 主庫二進制日誌文件位置點錯誤

     Slave_IO_Running: No
     Last_IO_Errno: 13114
     Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 
    'binlog truncated in the middle of event; consider out of disk space on master; the first event 'binlog.000021' at 156, the last event read from '/data/3306/data/binlog.000021' at 125,
    the last byte read from '/data/3306/data/binlog.000021' at 276.'

    注意: 在主從複製中,禁止主庫reset master;。能夠選擇 expire 進行按期清理主庫二進制日誌

  • server_id重複

 Last_IO_Errno: 13117
 Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server ids; 
these ids must be different for replication to work (or the --replicate-same-server-id 
option must be used on slave but this does not always make sense; please check the manual before using it).
 
  • server_uuid重複

 Last_IO_Errno: 1593
 Last_IO_Error: Fatal error: 
The slave I/O thread stops because master and slave have equal MySQL server UUIDs; 
these UUIDs must be different for replication to work.

SQL 線程

正常狀態:

 Slave_SQL_Running: Yes
 Last_SQL_Errno: 0
 Last_SQL_Error: 

故障狀態:

 Slave_SQL_Running: NO
 Last_SQL_Errno: 故障代碼
 Last_SQL_Error: 故障信息

故障緣由分析:

SQL線程功能:回放relay-log.info,執行裏面的SQL語句。

故障現象

  • relay-log損壞,斷節,找不到

  • 接收到的SQL沒法執行

    • 要建立的對象,已經存在

    • 要刪除或修改的對象不存在

    • 約束衝突,DML語句不符合表定義及約束

    • 版本差別,參數設定不一樣,好比:數據類型的差別,SQL_MODE影響

故障緣由

  • chang master to ... 指定的binlog位置點不對

  • 從庫被寫入

  • 業務繁忙時,從庫宕機了

  • 主從切換時,沒有正確操做(鎖定原主庫+binlog寫入)

  • 雙主結構,沒有正確使用


 Last_SQL_Error: Error 'Can't create database 'db';
 database exists' on query. 
Default database: 'db'. Query: 'create database db'

解決方案:

  1. 以主庫爲準

    1. 衝突操做回退回去

    2. 從庫跳過錯誤

      1. pt-checksum/pt-sync

      2. 從庫跳過指定錯誤代碼

       vim /etc/my.cnf
       [mysqld]
       slave-skip-errors = 1032,1062,1007
       常見錯誤代碼:
       1007: 對象已存在
       1032: 沒法執行DML
       1062: 主鍵衝突,或約束衝突
      1. 將同步指針向下移動一個,若是屢次不一樣步,能夠重複操做。

       stop slave;
       set global sql_slave_skip_counter=1;
       start slave;
    3. 刪除從庫中有衝突的數據,有風險

    4. 最安全的作法就是從新構建主從

  2. 從庫配置只讀

 show variables like '%read_only%';
 select @@read_only;
 select @@super_read_only;

 -- 普通用戶只讀
 set @@read_only=1;
 -- 管理員用戶只讀
 set @@super_read_only=1;
  1. 雙主結構,屏蔽多寫

  2. 加中間件,讀寫分離。

主從延時故障分析和處理

主從延時:主庫作的操做,從庫好久才作。

主從延時帶來的延伸問題:

  • 讀寫分離架構,依賴主從環境。主庫做爲寫節點,從庫做爲讀節點。要是太高,致使讀的不及時。

  • 高可用架構,依賴主從環境。主庫宕機,故障切換時,可能會丟失較多數據。


監控

時間差,主從延時的秒數(非人爲)

 Seconds_Behind_Master: 0

主庫日誌執行位置點

 Master_Log_File: mysql-bin.000005
 Read_Master_Log_Pos: 444

從庫日誌執行位置點

 Relay_Log_File: db01-relay-bin.000002
 Relay_Log_Pos: 485

對比主從日誌執行位置點,能夠找到故障操做點,計算延時日誌量


外在緣由

  • 主從硬件差別

  • 主從版本差別

  • 網絡問題:延時、阻塞、攻擊

  • 資源耗盡

    • 大事務(儘可能切割)大事務拆成多個小事務,能夠有效的減小主從延時。5.7 並行事務

    • 全表掃描

    • 存儲過程

    • DDL阻塞

    • ...

  • 其餘緣由

    • 過分追求安全:從庫關閉「雙一」

    • 鎖衝突:RR隔離級別,鎖衝突嚴重;調整爲RC隔離級別,保證索引主從一致


主庫緣由

產生場景:

  1. 主庫併發大量事務

  2. 從庫個數多

binlog_dump 線程以事件爲單元,串行傳輸二進制日誌給從庫IO,串行阻塞後續的事務(5.6 5.5),致使主從延時。


解決方案:

  • 5.6 版本:開啓GTID,實現GC(group commit)機制,將多個事務redo log的刷盤動做合併,減小磁盤順序寫,提升性能。

     

     

     5.7 版本:不開啓GTID,也會自動維護匿名的GTID,也能實現GC,建議開啓GTID

從庫緣由

產生場景:

主庫併發大量事務,從庫默認只有一個SQL線程,串行回放relay-log中的事務,阻塞後續的事務運行,致使主從延時。


解決方案:

  1. 5.6 版本:開啓GTID,加入SQL多線程的特性,可是隻能針對不一樣庫(database)下的事務進行併發回放。

  2. 5.7 版本:開始GTID,加入MTS(enhanced multi-threaded slave)技術,基於logical_clock(邏輯時鐘)機制,binlog加入了seq_no機制,真正實現了基於事務級別的併發回放。


過濾複製

產生情景:

需求:master 有4個庫A,B,C ,D,如今須要將其中2個庫B,C單獨拆分出來。

作法:單獨搭建一個只有B,C庫的實例,而後只複製master的B,C庫,過濾掉A,D庫。


主庫控制

 show master status;
 # 使用白名單或黑名單控制二進制日誌是否記錄,不經常使用
 Binlog_Do_DB        # 白名單,出現的記錄
 Binlog_Ignore_DB    # 黑名單,出現的不記錄

從庫控制

 show slave status\G
 # 在SQL線程回放流程中,加入過濾功能:庫,表,通配符表的白名單和黑名單
 # 白名單:只執行白名單中列出的庫或者表的中繼日誌
 # 黑名單:不執行黑名單中列出的庫或者表的中繼日誌
 Replicate_Do_DB
 Replicate_Ignore_DB
 Replicate_Do_Table
 Replicate_Ignore_Table
 Replicate_Wild_Do_Table
 Replicate_Wild_Ignore_Table

在線配置:

stop slave SQL_THREAD;
 change replication filter Replicate_Do_Table=(test.t1,test.t2);
 start slave sql_thread;

永久配置:

 vim /etc/my.cnf
 [mysqld]
 replicate_do_table=test.t1
 replicate_do_table=test.t2

更改複製過濾器語句


Database-Level Replication 流程圖

注意1:庫級別的規則,只針對binlog_format='STATEMENT or MIXED‘ 注意2:binlog_format=‘ROW’,不受庫級別規則限制,只受表級別規則限制。


 

 

總結

注意: 如下總結和測試,前提都是binlog-format='MIXED'


  • DB level:

    • binlog-format=statement時,過濾以use DB爲主(不容許跨庫)

    • binlog-format=row時:過濾不以use DB爲主(容許跨庫)

  • binlog-format=statement or row,table level 的判斷都是不以use DB爲主(能夠跨庫的)

  • 總的流程走向:

    • 先判斷 DB-level,若是 DB-level 判斷完成後須要 exit,則退出。

    • 若是 DB-level 判斷完成後,沒有 exit,則再判斷Table-level。

  • DB-level:

    • 若是有 replicate-do-db,則判斷 replicate-do-db,將不會走到 replicate-ignore-db 這層。

      若是判斷 replicate-do-db 符合條件,則判斷 table-level。 若是不符合,則exit。

    • 若是沒有 replicate-do-db,可是有 replicate-ignore-db 。

      若是判斷符合replicate-ignore-db規則,則exit。不符合,則走到 table-level 層繼續判斷。

  • Table-level:

    • 判斷邏輯順序自上而下爲:replicate-do-table -> replicate-ignore-table -> replicate-wild-do-table -> replicate-wild-ignore-table

    • 從第一個階段(replicate-do-table)開始,若是符合replicate-do-table判斷規則,則exit。

      若是不符合,則跳到下一層(replicate-ignore-table)。

      以此類推,直到最後一層(replicate-wild-ignore-table)都不符合,則最後判斷是否有(replicate-do-table or replicate-wild-do-table),若是有,則 ignore & exit。若是沒有,則execute & exit


說明:如下測試,均以statement格式爲例。 rows模式參見原理一樣能夠證實。

  • 設置replicate_do_DB=A,B

 結論:A和B都沒有在slave上執行。由於mysql將'A,B'做爲一個庫名。

只有庫級別的規則

  • do-db

 replicate_do_DB=A
 replicate_do_DB=B
  • ignoare-db

 replicate_ignore_DB=A
 replicate_ignore_DB=B
  • do-db & ignore-db

 replicate_do_DB=A
 replicate_do_DB=B
 replicate-ignore-db=mysql
 replicate-ignore-db=test

只有表級別的規則

  • do-table

  • ignore-table

  • wild-do-table

  • wild-ignore-table

  • do-table & ignore-table

  • do-table & wild-ignore-table

  • wild-do-table & wild-ignore-table

庫和表級別的規則混用

  • do-DB & do-table

 replicate_do_DB=A
 replicate_do_DB=B
 replicate-do-table=table1
 replicate-do-table=table2
  • do-DB & wild-do-table

 replicate_do_DB=A
 replicate_do_DB=B
 replicate-wild-do-table=mysql.%
 replicate-wild-do-table=test.%
  • do-DB & ignore-table

 replicate_do_DB=A
 replicate_do_DB=B
 replicate-ignore-table=table1
 replicate-ignore-table=table2
  • do-DB & wild-ignore-table

 replicate_do_DB=A
 replicate_do_DB=B
 replicate-wild-ignore-table=mysql.%
 replicate-wild-ignore-table=test.%
  • 最多見場景: db-db & do-ignore-db & wild-do-table & wild-ignore-table

 常見場景:將master上的A,B庫 拆分到 新的一組機器上。
 特色:
     1) slave 不復制 master 的 mysql,test 庫
     2) slave 只複製 master 的 A,B 庫全部操做
 
 replicate-ignore-db=mysql
 replicate-ignore-db=test
 replicate-wild-ignore-table=mysql.%
 replicate-wild-ignore-table=test.%
 replicate_do_DB=A
 replicate_do_DB=B
 replicate-wild-do-table=A.%
 replicate-wild-do-table=B.%

 誤區:
     1) 若是個人 default database 不是A或者B,那麼接下來的操做就不會被slave 執行,而後悲劇就產生了。
     master> use C;insert into A.id values(1);
     2)因此,以上cnf配置,只適合 default database 是 A,B 的狀況。
 
 若是要完成這種需求,應該這樣配置[前提:開發沒有權限登錄到mysql,test庫]:
 
 replicate-ignore-db=mysql
 replicate-ignore-db=test
 replicate-wild-ignore-table=mysql.%
 replicate-wild-ignore-table=test.%
 replicate-wild-do-table=A.%
 replicate-wild-do-table=B.%
  • 實戰: wild-do-table & ignore-table & wild-ignore-table

需求: 將老服務器上的某個庫,遷移到新機器上

 old_master[庫: A , B , mysql] ---->(同步) new_maser[A]

驗證單庫(A)複製的正確性: 規則=> slave 只複製A庫,不復制B庫

 Replicate_Wild_Do_Table: A.%
 Replicate_Ignore_DB: mysql
 Replicate_Wild_Ignore_Table: mysql.%

 a)use A/B; insert A.a select B.b from B ;  
--err:同步報錯,slave沒有B庫的內容
 b) use A/B; insert A.a select B.b from A,B where A.b=B.b;   
--err:同步報錯,slave沒有B庫的內容
 c) use mysql; insert into A.a values('a'); 
--err: 同步不報錯,可是老master的binlog沒有在slave執行,由於Replicate_Ignore_DB: mysql,Replicate_Wild_Ignore_Table: mysql.%
 d) use 空庫; insert into A.a values('a');  --ok: 能夠同步複製下來
 e) use B;   insert into A.a values('a');  --ok: 能夠同步複製下來

 


延時從庫

產生情景:

需求:主從複製很是擅長解決物理損壞,可是沒辦法處理邏輯損壞,例如主庫有個誤刪除寫入的操做,正常狀況下從庫也會同步這個錯誤,怎麼能避免這個狀況?

作法:創建延時從庫,delay(延時)從節點同步數據。能夠處理邏輯損壞,但只能作備用庫。

原理:對SQL線程回放流程,進行延時設置。

建議:通常企業建議3-6小時,具體看公司運維人員對於故障的反應時間


參數配置

查看延時時間

 show slave status\G
 # 延時時間,單位秒
 SQL_Delay: 0
 # 延時剩餘時間,單位秒
 SQL_Remaining_Delay: NULL

查看中繼日誌

 show relaylog events in 'db01-relay-bin.000002';
 

在線配置:

 stop slave SQL_THREAD;
 change master to master_delay = 300;
 start slave sql_thread;

故障恢復思路一

故障場景:一主一從,從庫延時5分鐘,主庫誤刪1個庫

故障模擬:主庫操做

 create database relay charset utf8;
 use relay;
 create table t1 (id int);
 insert into t1 values(1);
 commit;
 drop database relay;

故障恢復操做:

  1. 5分鐘以內,偵測到誤刪除操做

  2. 從庫中止SQL線程:

     stop slave SQL_THREAD;
    
  3. 從庫查找截取relaylog的起點和終點

    • 起點:中止SQL線程時,relay最後應用的位置

       mysql> show slave status\G
       ... ...
       Relay_Log_File: db02-relay-bin.000002
       Relay_Log_Pos: 321
       ... ...
      
    • 終點:誤刪除以前的Position(GTID)

       mysql> show relaylog events in 'db02-relay-bin.000002';
       | Log_name             | Pos  | Event_type     | Server_id | End_log_pos | Info                                               |
       ... ...
       | m01-relay-bin.000002 |  988 | Anonymous_Gtid |         1 |        1020 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'               |
       | db01-relay-bin.000002 | 1065 | Query          |         1 |        1127 | drop database relay /* xid=81 */   
                      |
  4. 從庫截取relaylog

     mysqlbinlog --start-position=321 --stop-position=988 /data/3306/data/db02-relay-bin.000002 > /tmp/relay.sql
    
  5. 從庫確認截取文件

     tail -10 /tmp/relay.sql
    
  6. 從庫恢復截取的日誌

     source /tmp/relay.sql
    
  7. 從庫身份解除,替代主庫工做

     stop slave;
     reset slave all;
    
  8. 業務改用從庫


故障恢復思路二

  1. 5分鐘以內,偵測到誤刪除操做

  2. 從庫中止SQL線程:

     stop slave SQL_THREAD;
    
  3. 關閉延遲從庫

     CHANGE MASTER TO MASTER_DELAY = 0;
    
  4. 從庫查詢誤刪除以前的Position(GTID)

     mysql> show slave status\G
     ... ...
     Relay_Log_File: db02-relay-bin.000002
     ... ...
     mysql> show relaylog events in 'db02-relay-bin.000002';
     | Log_name             | Pos  | Event_type     | Server_id | End_log_pos | Info                                               |
     ... ...
     | m01-relay-bin.000002 |  988 | Anonymous_Gtid |         1 |        1020 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'               |
     | db01-relay-bin.000002 | 1065 | Query          |         1 |        1127 | drop database relay /* xid=81 */     
                  |
  5. 從庫SQL線程自動回放,直到DROP操做以前。

    • binlog方式UNTIL

     START SLAVE SQL_THREAD UNTIL RELAY_LOG_FILE = 'db01-relay-bin.000002', RELAY_LOG_POS = 988 ;
    
    • GTID方式UNTIL

     START SLAVE UNTIL SQL_BEFORE_GTIDS = "1aa38bc6-1cbc-11eb-a6b8-000c29caebef:4";
    
  6. 從庫身份解除,替代主庫工做

     stop slave;
     reset slave all;
    
  7. 業務改用從庫


半同步複製

從 MYSQL 5.5 開始,支持半同步複製(Semi synchronous Replication),必定程度上保證提交的事務已經傳給了至少一個備庫。解決主從數據不一致問題,提供通常一致性。可以使用多從庫提升ACK接收率。

以前版本的MySQL Replication都是異步(asynchronous)的,主庫在執行完一些事務後,是不會管備庫的進度的。若是備庫不幸落後,而更不幸的是主庫此時又出現Crash(例如宕機),這時備庫中的數據就是不完整的。若是主庫發生故障,此時咱們沒法使用備庫來繼續提供數據一致的服務了。

5.5 出現概念,可是不建議使用,性能太差 5.6 出現 group commit 組提交功能,來提高開啓半同步複製的性能 5.7 更加完善了,在 group commit 基礎上出現了MGR 5.7 加強半同步複製的新特性:after commitafter sync


半同步複製工做原理的變化

  1. 主庫執行新的事務,commit時阻塞

  2. 更新 show master status 信息,觸發一個信號給 binlog dump

  3. binlog dump 通知從庫日誌更新了

  4. 從庫IO線程請求新的二進制日誌事件

  5. 主庫經過binlog dump線程,傳送新的二進制日誌事件,給從庫IO線程

  6. 從庫IO線程接收到binlog,當日志寫入到磁盤上的relaylog文件時,給主庫ACK_receiver線程響應

  7. ACK_receiver 線程觸發一個事件,告訴主庫commit能夠成功了

  8. 若是ACK_receiver 等待,達到了預設的超時時間尚未收到響應,半同步複製會切換爲原始的異步複製


半同步複製配置

配置主庫

在線配置:

 # 查看是否有動態支持
 show global variables like 'have_dynamic_loading';

 # 安裝自帶插件
 INSTALL PLUGIN rpl_semi_sync_master SONAME'semisync_master.so';

 # 啓動插件
 SET GLOBAL rpl_semi_sync_master_enabled = 1;

 # 設置超時時間
 SET GLOBAL rpl_semi_sync_master_timeout = 1000;

永久配置:

 vim /etc/my.cnf
 [mysqld]
 rpl_semi_sync_master_enabled=1
 rpl_semi_sync_master_timeout=1000

查看運行狀態

 show status like 'Rpl_semi_sync_master_status';

配置從庫

在線配置:

 # 安裝自帶插件
 INSTALL PLUGIN rpl_semi_sync_master SONAME'semisync_master.so';
 # 啓動插件
 SET GLOBAL rpl_semi_sync_master_enabled = 1;

 # 重啓io線程使其生效
 STOP SLAVE IO_THREAD;
 START SLAVE IO_THREAD;

永久配置:

 vim /etc/my.cnf
 [mysqld]
 rpl_semi_sync_master_enabled=1

查看運行狀態

 show status like 'Rpl_semi_sync_slave_status';

其餘優化參數

 rpl_semi_sync_master_enabled                =ON
 rpl_semi_sync_master_timeout                =1000
 rpl_semi_sync_master_trace_level            =32
 rpl_semi_sync_master_wait_for_slave_count   =1
 rpl_semi_sync_master_wait_no_slave          =ON
 rpl_semi_sync_master_wait_point             =AFTER_SYNC
 rpl_semi_sync_slave_enabled                 =ON
 rpl_semi_sync_slave_trace_level             =32
 ​
 binlog_group_commit_sync_delay              =1
 binlog_group_commit_sync_no_delay_count     =1000

GTID 複製

GTID(Global Transaction ID)是對於一個已提交事務的惟一編號,而且是一個全局(主從複製)惟一的編號。

 GTID =server_uuid : transaction_id
 7E11FA47-31CA-19E1-9E56-C43AA21293967:29

注意:mysqldump備份開啓GTID的數據庫,不能加--set-gtid-purged=OFF選項。

SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;

SET @@SESSION.SQL_LOG_BIN= 0;

總結:

gtid事務和 Position都增長了;

加了--set-gtid-purged=OFF時,在會記錄binlog日誌,若是不加,不記錄binlog日誌。


GTID核心參數

 [mysqld]
 gtid-mode=on                        --啓用gtid類型,不然就是普通的複製架構
 enforce-gtid-consistency=true       --強制GTID的一致性
 log-slave-updates=1                 --slave更新是否記入日誌
 

GTID 複製一主兩從搭建

配置主庫(db01)

  1. 安裝 mysql 8.0.20 二進制包

 tar xf mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz
 ln -s /opt/mysql-8.0.20-linux-glibc2.12-x86_64 /usr/local/mysql
 yum remove mariadb-libs -y
 useradd -M -r mysql
 mkdir -p /data/3306/data && chown -R mysql. /data/
 echo export PATH=\$PATH:/usr/local/mysql/bin/ >> /etc/profile && . /etc/profile
  1. 配置文件

 cat > /etc/my.cnf <<EOF
 [mysqld]
 user=mysql
 basedir=/usr/local/mysql
 datadir=/data/3306/data
 port=3306
 socket=/tmp/mysql.sock
 server_id=51
 log_bin=/data/3306/mysql-bin
 secure-file-priv=/tmp
 binlog_format=row
 gtid-mode=on
 enforce-gtid-consistency=true
 log-slave-updates=1
 [client]
 socket=/tmp/mysql.sock
 [mysql]
 prompt=db01 [\\d]>
 EOF
 
  1. 初始化數據,加入systemctl服務管理,啓動並開機自啓

 mysqld --initialize-insecure --user=mysql --basedir=/usr/local/mysql --datadir=/data/3306/data
 cp /usr/local/mysql/support-files/mysql.server  /etc/init.d/mysqld
 systemctl enable mysqld
 systemctl start mysqld
  1. 建立複製專用用戶並受權

 create user repl@'10.0.0.%' identified with mysql_native_password by  '123';
 grant replication slave on *.* to repl@'10.0.0.%';
  1. 查看主狀態

 show master status;

配置從庫(db02 db03)

  1. 安裝 mysql 8.0.20 二進制包

  2. 配置文件

 cat > /etc/my.cnf <<EOF
 [mysqld]
 user=mysql
 basedir=/usr/local/mysql
 datadir=/data/3306/data
 port=3306
 socket=/tmp/mysql.sock
 server_id=52
 log_bin=/data/3306/mysql-bin
 secure-file-priv=/tmp
 binlog_format=row
 gtid-mode=on
 enforce-gtid-consistency=true
 log-slave-updates=1
 [client]
 socket=/tmp/mysql.sock
 [mysql]
 prompt=db02 [\\d]>
 EOF

 cat > /etc/my.cnf <<EOF
 [mysqld]
 user=mysql
 basedir=/usr/local/mysql
 datadir=/data/3306/data
 port=3306
 socket=/tmp/mysql.sock
 server_id=53
 log_bin=/data/3306/mysql-bin
 secure-file-priv=/tmp
 binlog_format=row
 gtid-mode=on
 enforce-gtid-consistency=true
 log-slave-updates=1
 [client]
 socket=/tmp/mysql.sock
 [mysql]
 prompt=db03 [\\d]>
 EOF

 

  1. 初始化數據,加入systemctl服務管理,啓動並開機自啓

  2. 配置主庫鏈接信息(help change master to

 CHANGE MASTER TO
   MASTER_HOST='10.0.0.51',
   MASTER_USER='repl',
   MASTER_PASSWORD='123',
   MASTER_AUTO_POSITION=1;
  1. 啓動複製線程

 start slave;
  1. 查看從狀態

 show slave status \G

GTID 從庫誤寫入操做處理

查看監控信息:

 Last_SQL_Error: Error 'Can't create database 'oldboy'; database exists' on query. 
Default database: 'oldboy'. Query: 'create database oldboy'
 ​
 Retrieved_Gtid_Set: 71bfa52e-4aae-11e9-ab8c-000c293b577e:1-3
 Executed_Gtid_Set:  71bfa52e-4aae-11e9-ab8c-000c293b577e:1-2,

跳過報錯事務(GTID),注入空事務:

 stop slave;
 set gtid_next='71bfa52e-4aae-11e9-ab8c-000c293b577e:3';
 begin;commit;
 set gtid_next='AUTOMATIC';

GTID 複製和普通複製的區別

 CHANGE MASTER TO
 MASTER_HOST='10.0.0.51',
 MASTER_USER='repl',
 MASTER_PASSWORD='123',
 MASTER_PORT=3306,
 MASTER_LOG_FILE='binlog.000001',
 MASTER_LOG_POS=444,
 MASTER_CONNECT_RETRY=10;
 ​
 CHANGE MASTER TO
 MASTER_HOST='10.0.0.51',
 MASTER_USER='repl',
 MASTER_PASSWORD='123',
 MASTER_AUTO_POSITION=1;
  1. 在主從複製環境中,主庫發生過的事務,在全局都是由惟一GTID記錄的,更方便Failover

  2. 額外功能參數(3個)

  3. change master to ... 時,不須要binlog文件名和position號,啓用自動便可MASTER_AUTO_POSITION=1;

  4. 在複製過程當中,從庫再也不依賴master.info文件,而是直接讀取最後一個relaylog的GTID號

  5. mysqldump備份時,默認包含事務操做的GTID,以SET @@GLOBAL.GTID_PURGED='8c49d7ec-7e78-11e8-9638-000c29ca725d:1';形式告訴從庫,個人備份中已經有以上事務,你就不用運行了,直接從下一個GTID開始請求binlog就行。

多源複製

MySQL 5.7 以前只能支持一主一從,一主多從或者多主多從的複製。若是想實現多主一從,只能使用mariadb,可是mariadb又與官方的mysql版本不兼容。

MySQL 5.7 開始支持多主一從也就是多源複製(multi-source)。簡單的說,多源複製就是將多個主庫同步到一個從庫,從而增長從的利用率,節省了機器。

 

 

應用場景:

  1. 數據分析部門會須要各個業務部門的部分數據作數據分析,這個時候就可使用到多源複製把各個主數據庫的數據複製到統一的數據庫中。報表系統

  2. 在從服務器進行數據的彙總,若是咱們的主服務器進行了分庫分表的操做,爲了實現後期的一些數據的統計功能,每每要把數據彙總在一塊兒在進行統計。OLAP(在線分析處理)

  3. 在從服務器對全部主服務器的數據進行備份。


 [mysqld]
 slow_query_log=ON                 -- 啓用慢查詢
 slow_query_log_file=/data/3306/data/db01-slow.log  -- 慢查詢日誌保存路徑
 long_query_time=0.1               -- 慢查詢記錄執行超過0.1秒的查詢
 log_queries_not_using_indexes     -- 記錄預期將檢索全部行的查詢
 master_info_repository=TABLE      -- 存儲 master_info 到表中,更安全
 relay_log_info_repository=TABLE   -- 存儲 relay_log_info 到表中,更安全
 [mysql]
 prompt=db01 [\\d]>                -- mysql命令行提示符

GTID 兩主一從 多源複製

  1. 修改配置文件

 cat > /etc/my.cnf <<EOF
 [mysqld]
 user=mysql
 basedir=/usr/local/mysql
 datadir=/data/3306/data
 port=3306
 socket=/tmp/mysql.sock
 server_id=1
 log_bin=/data/binlog/mysql-bin
 secure-file-priv=/tmp
 binlog_format=row
 gtid-mode=on
 enforce-gtid-consistency=true
 log-slave-updates=1
 innodb_flush_method=O_DIRECT
 slow_query_log=ON
 slow_query_log_file=/data/3306/data/db01-slow.log
 long_query_time=0.1
 log_queries_not_using_indexes
 master_info_repository=TABLE
 relay_log_info_repository=TABLE
 [client]
 socket=/tmp/mysql.sock
 [mysql]
 prompt=db01 [\\d]>
 EOF

 cat > /etc/my.cnf <<EOF
 [mysqld]
 user=mysql
 basedir=/usr/local/mysql
 datadir=/data/3306/data
 port=3306
 socket=/tmp/mysql.sock
 server_id=2
 log_bin=/data/binlog/mysql-bin
 secure-file-priv=/tmp
 binlog_format=row
 gtid-mode=on
 enforce-gtid-consistency=true
 log-slave-updates=1
 innodb_flush_method=O_DIRECT
 slow_query_log=ON
 slow_query_log_file=/data/3306/data/db01-slow.log
 long_query_time=0.1
 log_queries_not_using_indexes
 master_info_repository=TABLE
 relay_log_info_repository=TABLE
 [client]
 socket=/tmp/mysql.sock
 [mysql]
 prompt=db02 [\\d]>
 EOF

 cat > /etc/my.cnf <<EOF
 [mysqld]
 user=mysql
 basedir=/usr/local/mysql
 datadir=/data/3306/data
 port=3306
 socket=/tmp/mysql.sock
 server_id=3
 log_bin=/data/binlog/mysql-bin
 secure-file-priv=/tmp
 binlog_format=row
 gtid-mode=on
 enforce-gtid-consistency=true
 log-slave-updates=1
 innodb_flush_method=O_DIRECT
 slow_query_log=ON
 slow_query_log_file=/data/3306/data/db01-slow.log
 long_query_time=0.1
 log_queries_not_using_indexes
 master_info_repository=TABLE
 relay_log_info_repository=TABLE
 [client]
 socket=/tmp/mysql.sock
 [mysql]
 prompt=db03 [\\d]>
 EOF

 

  1. 重啓mysql服務

 systemctl restart mysql
  1. 清除原來主從關係(db02 db03)

 stop slave;
 reset slave all;
  1. 多源複製從庫配置主庫信息(db03)並啓動

 CHANGE MASTER TO MASTER_HOST='10.0.0.51',MASTER_USER='repl', 
MASTER_PASSWORD='1', MASTER_AUTO_POSITION=1 FOR CHANNEL 'Master_1'; CHANGE MASTER TO MASTER_HOST='10.0.0.52',MASTER_USER='repl',
MASTER_PASSWORD='1', MASTER_AUTO_POSITION=1 FOR CHANNEL 'Master_2'; start slave for CHANNEL 'Master_1'; start slave for CHANNEL 'Master_2';
  1. 多源複製從庫監控

 -- 查看單一信道的複製的詳細狀態
 SHOW SLAVE STATUS FOR CHANNEL 'Master_1'\G
 SHOW SLAVE STATUS FOR CHANNEL 'Master_2'\G

 -- 查看視圖中複製配置,狀態
use performance_schema;
 show tables like '%repl%';
 select * from performance_schema.replication_connection_configuration\G
 SELECT * FROM performance_schema.replication_connection_status WHERE CHANNEL_NAME='master_1'\G

 -- 查看全部複製信道的複製狀態概況
 select * from performance_schema.replication_applier_status_by_worker;
  1. 多源複製配置過濾

 CHANGE REPLICATION FILTER REPLICATE_WILD_DO_TABLE = ('db1.%') FOR CHANNEL "master_1";
 CHANGE REPLICATION FILTER REPLICATE_WILD_DO_TABLE = ('db2.%') FOR CHANNEL "master_2";

 


檢查測試

 -- 在主庫(10.0.0.51)實例建立一些數據。
 create database master1;
 use master1;
 CREATE TABLE `test1` (`id` int(11) DEFAULT NULL,`count` int(11) DEFAULT NULL);
 insert into test1 values(1,1);



-- 在主庫(10.0.0.52)實例建立一些數據。

 create database master2;
 use master2;
 CREATE TABLE `test2` (`id` int(11) DEFAULT NULL,`count` int(11) DEFAULT NULL);
 insert into test2 values(1,1);
 
 -- 在從庫(10.0.0.53)實例檢查數據是否成功複製。
 select * from master1.test1;
 select * from master2.test2;

主主複製

主主複製:互爲主從 (1)容易產生的問題:數據不一致;所以慎用 (2)考慮要點:自動增加id

配置一個節點使用奇數id

 auto_increment_offset=1 開始點
 auto_increment_increment=2 增加幅度

另外一個節點使用偶數id

 auto_increment_offset=2
 auto_increment_increment=2

主主複製的配置步驟:

 (1) 各節點使用一個唯一server_id
 (2) 都啓動binary log和relay log
 (3) 建立擁有複製權限的用戶帳號
 (4) 定義自動增加id字段的數值範圍各爲奇偶
 (5) 均把對方指定爲主節點,並啓動複製線程

實驗:主主複製

主1:db01配置

 vim /etc/my.cnf
 [mysqld]
 server-id=1
 binlog_format=ROW
 plugin-load-add=mysql_clone.so
 clone=FORCE_PLUS_PERMANENT
 auto_increment_offset=1
 auto_increment_increment=2

重啓db01機器mysql服務器

 systemctl reatart mysqld
 mysql> select @@log_bin;
 mysql> select @@log_bin_basename;
 mysql> create user repl@'10.0.0.%' identified with mysql_native_password by  '123';
 mysql> grant replication slave on *.* to repl@'10.0.0.%';
 建立遠程clone用戶
 # 捐贈者(source)受權
 mysql> reset master;
 create user test_s@'%' identified by '123';
 grant backup_admin on *.* to test_s@'%';
 mysql > show databases;
 mysql > CHANGE MASTER TO
 mysql > start slave;  開啓slave
 mysql > show slave status\G
 ​
 mysql> create table  t1(id int auto_increment primary key,name char(10));  建立表t1
 Query OK, 0 rows affected (0.03 sec) 
 mysql> insert t1(name)value('a');  插入a信息
 Query OK, 1 row affected (0.01 sec)
 mysql> insert t1(name)value('b');  插入b信息
 Query OK, 1 row affected (0.00 sec)
 mysql> select * from t1;
 +----+------+
 | id | name |
 +----+------+
 |  1 | a    |
 |  3 | b    |
 +----+------+

主2:db02配置

 vim /etc/my.cnf
 [mysqld]
 server-id=2
 binlog_format=ROW
 auto_increment_offset=2
 auto_increment_increment=2
 plugin-load-add=mysql_clone.so
 clone=FORCE_PLUS_PERMANENT

重啓

 systemctl restart mysqld

 SELECT PLUGIN_NAME, PLUGIN_STATUS
 FROM INFORMATION_SCHEMA.PLUGINS
 WHERE PLUGIN_NAME LIKE 'clone';
 # 接受者(target)受權
 mysql> reset master;
 create user test_t@'%' identified by '123';
 grant clone_admin on *.* to test_t@'%';

  遠程clone(目標端)
 # 開始克隆
 SET GLOBAL clone_valid_donor_list='10.0.0.51:3306';
 mysql -utest_t -p123 -h10.0.0.52  -P3306
 CLONE INSTANCE FROM test_s@'10.0.0.51':3306 IDENTIFIED BY '123';

 ==========================================================
 f. 告訴從庫鏈接信息,從什麼位置點開始自動複製 change master to
 mysql> select * from performance_schema.clone_status\G
 mysql> CHANGE MASTER TO
        MASTER_HOST='10.0.0.51',
        MASTER_USER='repl',
        MASTER_PASSWORD='123',
        MASTER_PORT=3306,
        MASTER_LOG_FILE='binlog.000001',
        MASTER_LOG_POS=156,
        MASTER_CONNECT_RETRY=10;
 g. 啓動專用複製線程 start slave;
 mysql> start slave ;
 mysql> show slave status \G;
 Slave_IO_Running: Yes
 Slave_SQL_Running: Yes
 mysql > show databases;

 查看二進制日誌狀況
 mysql > show master logs;
 插入表
 mysql > insert t1(name)value('a');  在B主機上插入a信息
 Query OK, 1 row affected (0.01 sec)
 mysql > insert t1(name)value('b');  在B主機上插入b信息
 Query OK, 1 row affected (0.00 sec)
 mysql > select * from t1;  查看此時未出現衝突狀況,可是ID順序會比較亂
 +----+------+
 | id | name |
 +----+------+
 |  1 | a    |
 |  3 | b    |
 |  4 | a    |
 |  6 | b    |
 +----+------+

級聯複製

 主-中間主(change master to)-從1(change  master to中間主)-從2(change  master to中間主)-從3(change  master to中間主)

主從從複製

 一主多從
 主 ----從1(-change master to主)-從2-change master to主   
相關文章
相關標籤/搜索