MySQL 主從複製延時常見場景及分析改善

一 序言mysql

在運維MySQL數據庫時,DBA會接收到比較多關於主備延時的報警:算法

check_ins_slave_lag (err_cnt:1)critical-slavelag on ins:3306=39438sql

相信slave延遲是MySQL DBA遇到的一個老生常談的問題了。咱們先來分析一下slave延遲帶來的風險:數據庫

  • 異常狀況下,主從HA沒法切換,HA 軟件須要檢查數據的一致性,延遲時,主備不一致
  • 備庫複製hang會致使備份失敗(flush tables with read lock會900s超時)
  • 以slave爲基準進行的備份,數據不是最新的,而是延遲

本文主要探討如何解決 ,如何規避slave延遲的問題,接下來咱們要分析一下致使備庫延遲的幾種緣由。緩存

二 slave延遲的場景以及解決方法多線程

1 無主鍵、無索引或索引區分度不高

有以下特徵:併發

a. show slave status 顯示position一直沒有變
b. show open tables 顯示某個表一直是 in_use 爲 1
c. show create table 查看錶結構能夠看到無主鍵,或者無任何索引,或者索引區分度不好。
app

解決方法:運維

a. 找到表區分度比較高的幾個字段, 可使用這個方法判斷:
select count(*) from xx;
select count(*) from (select distinct xx from xxx) t;
若是2個查詢count(*)的結果差很少,說明能夠對這些字段加索引
b. 備庫stop slave;
可能會執行比較久,由於須要回滾事務。
c. 備庫
set global slave_rows_search_algorithms='TABLE_SCAN,INDEX_SCAN,HASH_SCAN';
或者
set sql_log_bin=0;
alter table xx add key xx(xx);
d. 備庫start slave
若是是innodb,能夠經過show innodb status來查看 rows_inserted,updated,deleted,selected這幾個指標來判斷。
若是每秒修改的記錄數比較多,說明覆制正在以比較快的
速度執行。異步

其實針對無索引的表,能夠直接調整從庫上的參數slave_rows_search_algorithms。

2 主庫上有大事務,致使從庫延時

現象解析binlog發現相似於下圖的狀況看:

解決方法:

  1. 事前防範,與開發溝通,增長緩存,異步寫入數據庫,減小業務直接對db的大事務寫入。
  2. 事中補救,調整數據庫中io相關的參數好比innodb_flush_log_at_trx_commit和sync_binlog 或者打開並行複製功能。友情連接查詢

3 主庫寫入頻繁,從庫壓力跟不上致使延時

此類緣由的主要現象是數據庫的IUD操做很是多,slave因爲sql_thread單線程的緣由追不上主庫。

解決方法:

a 升級從庫的硬件配置,好比ssd,fio.
b 使用@丁奇的預熱工具-relay fetch
在備庫sql線程執行更新以前,預先將相應的數據加載到內存中,並不能提升sql_thread線程執行sql的能力,
也不能加快io_thread線程讀取日誌的速度。
c 使用多線程複製 阿里MySQL團隊實現的方案--基於行的並行複製。
該方案容許對同一張表進行修改的兩個事務並行執行,只要這兩個事務修改了表中的不一樣的行。
這個方案能夠達到事務間更高的併發度,可是侷限是必須使用 Row格式的binlog。
由於只有使用Row格式的binlog才能夠知道一個事務所修改的行的範圍,而使用Statement格式的binlog只能知道修改的表對象。

4 大量myisam表,在備份時致使slave延遲

因爲xtrabackup工具有份到最後會執行flash tables with read lock ,對數據庫進行鎖表以便進行一致性備份,而後對於myisam表鎖,會阻礙salve_sql_thread停滯運行進而致使hang。

該問題目前的比較好的解決方式是修改表結構爲innodb存儲引擎的表。

三 MySQL的改進

爲了解決複製延遲的問題,MySQL也在竭盡全力的解決主從複製的性能瓶頸,研發高效的複製算法。

1 基於組提交的並行複製

MySQL的複製機制大體原理是:slave經過io_thread 將主庫的binlog拉到從庫並寫入relay log,由SQL thread讀出來relay log並進行重放。當主庫寫入併發寫入壓力很大,也即N:1的情形,slave就可能會出現延遲。MySQL 5.6版本提供並行複製功能,slave複製相關的線程由io_thread,coordinator_thread,worker構成,其中:

  • coordinator_thread 負責讀取relay log,將讀取的binlog event以事務爲單位分發到各個 worker thread進行執行,並在必要時執行binlog event,好比是DDL或者跨庫事務的時候。
  • worker_thread:執行分配到的binlog event,各個線程之間互不影響,具體worker_thread的個數由slave_parallel_workers決定。

須要注意的是dbname與worker線程的綁定信息在一個hash表中進行維護,hash表以entry爲單位,entry中記錄當前entry所表明的數據庫名,有多少個事務相關的已被分發,執行這些事務的worker thread等信息。

分配線程是以數據庫名進行分發的,當一個實例中只有一個數據庫的時候,不會對性能有提升,相反,因爲增長額外的操做,性能還會有一點回退。

MySQL 5.7版本提供基於組提交的並行複製,經過設置以下參數來啓用並行複製。

slave_parallel_workers>0
global.slave_parallel_type='LOGICAL_CLOCK'

即主庫在ordered_commit中的第二階段,將同一批commit的 binlog打上一個相同的seqno標籤,同一時間戳的事務在備庫是能夠同時執行的,所以大大簡化了並行複製的邏輯,並打破了相同DB不能並行執行的限制。備庫在執行時,具備同一seqno的事務在備庫能夠並行的執行,互不干擾,也不須要綁定信息,後一批seqno的事務須要等待前一批相同seqno的事務執行完後才能夠執行。這樣的實現方式大大提升了slave應用relaylog的速度。

#默認是DATABASE模式的,須要調整或者在my.cnf中配置
mysql> show variables like 'slave_parallel%';
+++
| Variable_name | Value |
+++
| slave_parallel_type | DATABASE |
| slave_parallel_workers | 4 |
+++
2 rows in set (0.00 sec)
mysql> STOP SLAVE SQL_THREAD;
Query OK, 0 rows affected (0.00 sec)
mysql> set global slave_parallel_type='LOGICAL_CLOCK';
Query OK, 0 rows affected (0.00 sec)
mysql> START SLAVE SQL_THREAD;
Query OK, 0 rows affected (0.01 sec)

啓用並行複製以後查看processlist,系統多了四個線程Waiting for an event from Coordinator (手機用戶推薦橫屏查看)

mysql> show processlist;

| Id | User | Host | db | Command | Time | State | Info |

| 9 | root | localhost:40270 | NULL | Query | 0 | starting | show processlist |
| 10 | system user | | NULL | Connect | 1697 | Waiting for master to send event | NULL |
| 31 | system user | | NULL | Connect | 5 | Slave has read all relay log; waiting for more updates | NULL |
| 32 | system user | | NULL | Connect | 5 | Waiting for an event from Coordinator | NULL |
| 33 | system user | | NULL | Connect | 5 | Waiting for an event from Coordinator | NULL |
| 34 | system user | | NULL | Connect | 5 | Waiting for an event from Coordinator | NULL |
| 35 | system user | | NULL | Connect | 5 | Waiting for an event from Coordinator | NULL |

7 rows in set (0.00 sec)

核心參數:

  1. binlog_group_commit_sync_no_delay_count:一組裏面有多少事物才提交,單位 (ms)
  2. binlog_group_commit_sync_delay:等待多少時間後才進行組提交

2 基於寫集合的並行複製

其實從MySQL5.7.22就提供基於write set的複製優化策略。WriteSet並行複製的思想是:不一樣事務的不一樣記錄不重疊,則均可在從機上並行回放,能夠看到並行的力度從組提交細化爲記錄級。不想看官方文檔的話,你們能夠看看姜老師的文章:

速度提高5~10倍,基於WRITESET的MySQL並行複製

廢話很少說,直接上性能壓測圖:

四 總結

slave延遲的緣由能夠歸結爲slave apply binlog的速度跟不上主庫寫入的速度,如何解決複製延遲呢?其實也是如何提升MySQL寫速度的問題。從目前的硬件和軟件的發展來看,硬件存儲由以前的HDD機械硬盤發展到如今的SSD,PCI-E SSD,再到NVM Express(NVMe),IO性能一直在提高。MySQL的主從複製也從單線程複製到不一樣算法的並行複製(基於庫,事務,行),應用binlog的速度也愈來愈快。

本文概括從幾個常見的複製延遲場景,有可能還不完整,也歡迎你們留言討論。

五 拓展閱讀

[1] 一種MySQL主從同步加速方案-改進

[2] MySQL多線程同步MySQL-Transfer介紹(已經不在維護)

[3] MySQL並行複製演進及MySQL 8.0中基於WriteSet的優化

[4] 速度提高5~10倍,基於WRITESET的MySQL並行複製

[5] https://mysqlhighavailability.com/improving-the-parallel-applier-with-writeset-based-dependency-tracking/

相關文章
相關標籤/搜索