主從復制延遲推薦解決方案


主從復制延遲推薦解決方案

MySQL 的復制是主庫主動推送日志到從庫去的,是屬於“推”日志的方式來做同步,然后從庫的I/O線程等待主庫上的Binlog Dump線程發送
事件並更新到中繼日志Relay Log,SQL線程讀取中繼日志Relay Log並應用變更到數據庫。這個過程中是屬於異步操作,所以從庫上的數據和
主庫會存在一定的延遲,導致一定的性能問題。
如何提高復制的性能

現象描述

​ MySQL從庫上通過SHOW PROCESSLIST可以看到有且僅有一個SQL線程在解析中繼日志Relay Log並應用,例如:

mysql> show processlist \G;
*************************** 1. row ***************************
     Id: 5
   User: root
   Host: 192.168.211.1:63440
     db: ssm
Command: Sleep
   Time: 2185
  State: 
   Info: NULL
*************************** 2. row ***************************
     Id: 6
   User: root
   Host: 192.168.211.1:63488
     db: ssm
Command: Sleep
   Time: 2190
  State: 
   Info: NULL
*************************** 3. row ***************************
     Id: 15
   User: root
   Host: localhost
     db: NULL
Command: Query
   Time: 0
  State: init
   Info: show processlist
*************************** 4. row ***************************
     Id: 16
   User: system user
   Host: 
     db: NULL
Command: Connect
   Time: 2
  State: Waiting for master to send event
   Info: NULL
*************************** 5. row ***************************
     Id: 17
   User: system user
   Host: 
     db: NULL
Command: Connect
   Time: 2
  State: Slave has read all relay log; waiting for the slave I/O thread to update it
   Info: NULL

​ 那么寫入壓力特別大的場景下,考慮到主庫是多線程並發在寫入(應用服務器並發連接寫入),而從庫僅僅只有一個SQL線程在應用日志,就容易出現從庫追不上主庫的情況,可以在從庫上通過SHOW SLAVE STATUS來查看從庫落后主庫的時間:

mysql> show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.211.136
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000007
          Read_Master_Log_Pos: 1271
               Relay_Log_File: mysqld-relay-bin.000011
                Relay_Log_Pos: 283
        Relay_Master_Log_File: mysql-bin.000007
             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: 1271
              Relay_Log_Space: 620
              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: 136
                  Master_UUID: cb248a05-3538-11eb-8893-005056253f37
             Master_Info_File: /var/lib/mysql/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: 
            Executed_Gtid_Set: 
                Auto_Position: 0
1 row in set (0.00 sec)

​ 其中 Seconds_Behind_Master 顯示了預估從庫落后主庫的秒數,不是特別精准,只是一個預估值。

​ 從庫的數據落后主庫的問題,當然可以通過提高從庫配置的硬件來解決。但更推薦通過架構設計來解決這個問題,通過減少從庫需要做的寫入操作或者在從庫上實現多線程寫入操作都能夠解決。

2個解決方案

方案一

​ 通過拆分減少一個從庫上需要數據同步的表來解決。首先考慮配置一主多從的架構,然后在不同的從庫上,通過設置不同 replicate-do-db、replicate-do-table、replicate-ignore-db、replicate-ignore-table或replicate-wild-do-table參數,使得不同的從庫復制不同的庫/表,減少每個從庫上需要寫入的數據。
​ 例如,假設主庫為M1,從庫為S1、S2、S3,其中設置從庫S1僅需要復制databaseA,而從庫S2僅需要復制databaseB,從庫S3僅需要復制databaseC,那么每個從庫只需要執行自己需要復制的庫/表相關的SQL就可以了,如下圖所示。

​ 這時,由於主庫M1需要給S1、S2、S3三個從庫(或者更多從庫)都發送完整的Binlog日志,I/O 和網絡壓力較大,再改進一下架構:配置 MySQL 多級主從架構減輕主庫壓力,如下圖所示。

  1. 主庫M1首先給二級主庫M2推送完整的Binlog。
  2. 二級主庫M2打開log-slave-updates配置,保證主庫M1傳送過來的Binlog能夠被記錄在二級主庫M2的RelayLog和Binlog中;二級主庫M2選擇BLACKHOLE引擎作為表引擎,降低二級主庫上I/O的壓力。
  3. 為二級主庫M2配置3個從庫S1、S2、S3,三個從庫通過配置不同replicate-do-db等參數,讓S1、S2、S3復制不同的庫/表。

​ 通過多級主從的方式,提高從庫的復制性能,同時盡量降低對主庫的影響。

注意:BLACKHOLE引擎就是一個“黑洞”引擎,在創建表的時候,選擇BLACKHOLE引擎,那么寫入表的數據不會真實地寫入磁盤,僅僅記錄Binlog日志,極大降低了磁盤的I/O。

​ 方案一的優點在於能夠自由拆分從庫,方便地把熱點數據分散開來;缺點在於維護起來不夠簡潔,並且由於從庫S1、S2、S3上都沒有主庫完整的數據,在主庫M1出現意外宕機的情況,應用處理較為麻煩。需要提前和應用溝通好異常的處理解決方案。

方案二

​ MySQL 5.6提供了基於 Schema的多線程復制,允許從庫並行更新。例如,主庫上存在 2個Schema,即ssm和replication。

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| replication        |
| ssm                |
+--------------------+
5 rows in set (0.00 sec)

​ MySQL 5.6的從庫在同步主庫時,通過設置參數 slave_parallel_workers為 2,讓MySQL從庫在復制時啟動兩個SQL線程。參數設置前:

mysql> show variables like '%slave_parallel_workers%';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| slave_parallel_workers | 0     |
+------------------------+-------+
1 row in set (0.00 sec)

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.6.50    |
+-----------+
1 row in set (0.00 sec)
mysql> show processlist \G;
*************************** 1. row ***************************
     Id: 5
   User: root
   Host: 192.168.211.1:63440
     db: ssm
Command: Sleep
   Time: 3480
  State: 
   Info: NULL
*************************** 2. row ***************************
     Id: 6
   User: root
   Host: 192.168.211.1:63488
     db: ssm
Command: Sleep
   Time: 3485
  State: 
   Info: NULL
*************************** 3. row ***************************
     Id: 15
   User: root
   Host: localhost
     db: NULL
Command: Query
   Time: 0
  State: init
   Info: show processlist
*************************** 4. row ***************************
     Id: 16
   User: system user
   Host: 
     db: NULL
Command: Connect
   Time: 1297
  State: Waiting for master to send event
   Info: NULL
*************************** 5. row ***************************
     Id: 17
   User: system user
   Host: 
     db: NULL
Command: Connect
   Time: 1297
  State: Slave has read all relay log; waiting for the slave I/O thread to update it
   Info: NULL
5 rows in set (0.00 sec)

設置參數后如下:注意需要先stop slave,再start slave才有效果

mysql> set global slave_parallel_workers=2;
Query OK, 0 rows affected (0.00 sec)

mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)

mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> show processlist \G;
*************************** 1. row ***************************
     Id: 5
   User: root
   Host: 192.168.211.1:63440
     db: ssm
Command: Sleep
   Time: 3603
  State: 
   Info: NULL
*************************** 2. row ***************************
     Id: 6
   User: root
   Host: 192.168.211.1:63488
     db: ssm
Command: Sleep
   Time: 3608
  State: 
   Info: NULL
*************************** 3. row ***************************
     Id: 15
   User: root
   Host: localhost
     db: NULL
Command: Query
   Time: 0
  State: init
   Info: show processlist
*************************** 4. row ***************************
     Id: 18
   User: system user
   Host: 
     db: NULL
Command: Connect
   Time: 2
  State: Waiting for master to send event
   Info: NULL
*************************** 5. row ***************************
     Id: 19
   User: system user
   Host: 
     db: NULL
Command: Connect
   Time: 2
  State: Slave has read all relay log; waiting for the slave I/O thread to update it
   Info: NULL
*************************** 6. row ***************************
     Id: 20
   User: system user
   Host: 
     db: NULL
Command: Connect
   Time: 2
  State: Waiting for an event from Coordinator
   Info: NULL
*************************** 7. row ***************************
     Id: 21
   User: system user
   Host: 
     db: NULL
Command: Connect
   Time: 2
  State: Waiting for an event from Coordinator
   Info: NULL
7 rows in set (0.00 sec)

​ 通過設置slave_parallel_workers 參數,讓ssm和replication兩個Schema擁有自己獨立的SQL線程,這樣也大大提高了從庫的復制速度。

​ 復制是MySQL數據庫中經常使用的一個功能,它可以有效地保證主數據庫的數據安全,並減輕主數據庫的備份壓力,以及分擔主數據庫的一部分查詢壓力。

​ -------學自《深入淺出MySQL》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM