這套方法論,徹底終結MySQL同步延遲問題

zping發表於2018-05-04

作者介紹

張秀雲網名飛鴻無痕,現任職於騰訊,負責騰訊金融資料庫的運維和優化工作。2007年開始從事運維方面的工作,經歷過網路管理員、Linux運維工程師、DBA、分散式儲存運維等多個IT職位。對Linux運維、MySQL資料庫、分散式儲存有豐富的經驗。簡書地址:

https://www.jianshu.com/u/9346dc2e9d3e

 

作為一名DBA,我們在工作中會經常遇到一些MySQL主從同步延遲的問題,這些同步慢的問題,其實原因非常多:可能是主從的網路問題導致的,可能是網路頻寬問題導致的,可能是大事務導致的,也可能是單執行緒複製導致的延遲。

 

近期筆者遇到了一個很典型的同步延遲問題,在此將分析過程寫出來,希望能夠為廣大DBA在排查同步延遲問題時提供比較系統的方法論。

 

一、背景

 

最近有一組DB出現比較大的延遲,這組DB是專門用來儲存監控資料的,每分鐘會使用Load Data的方式匯入大量的資料。為了節省空間,將原來使用壓縮表的InnoDB引擎轉換成了TokuDB引擎,使用的版本和引擎如下:

 

MySQL Version: 5.7

Storage Engine: TokuDB

 

轉換後,發現主從延遲逐漸增大,基本每天落後主機大概50個binlog左右,大概延遲7.5個小時左右的資料,主機每天大概產生160個binlog,binlog列表如下圖所示:

 

 

 

 

由於對該業務非常熟悉,因此很快就定位到造成主從同步延遲的原因,並很快就解決了延遲的問題。這裡不直接說解決辦法,而是想描述一套完整的解決主從延遲問題的思考方式,和大家一起來系統的做一些思考。

 

帶著問題去思考延遲的根本原因和解決辦法,這也許會更有意義。授人以魚,不如授人以漁。接下來我們就一起開腦洞吧。

 

二、思考

 

首先,既然產生了主從延遲,就說明在從機上的消費速度趕不上主機binlog產生的速度。我們先來思考一下可能的原因,並根據現場的蛛絲馬跡去驗證猜想的正確性。其實所謂的問題排查,就是提出可能問題猜想,然後不斷去證明的過程。不同的是,每個人的經驗不同,排查的質量也不盡頭相同,僅此而已。

 

1網路

 

網路可能導致主從延遲的問題,比如主機或者從機的頻寬打滿、主從之間網路延遲很大,有可能會導致主上的binlog沒有全量傳輸到從機,造成延遲。

 

筆者的那組DB的IO執行緒已經將對應的binlog近乎實時地拉取到了從機DB上,基本排除網路導致的延遲,還可以結合網路質量相關監控來進一步確認是網路的問題。

 

2機器效能

 

  • 從機使用了爛機器?

 

之前有遇到過有的業務從機使用了很爛的機器,導致的主從延遲。比如主機使用SSD,而從機還是使用的SATA。從機用爛機器的觀念需要改改,隨著DB自動切換的需求越來越高,尤其是筆者所在的金融行業,從機至少不要比主機配置差。

 

  • 從機高負載?

 

有很多業務會在從機上做統計,把從機伺服器搞成高負載,從而造成從機延遲很大的情況,這種使用top命令即可快速發現。

 

  • 從機磁碟有問題?

 

磁碟、Raid卡、排程策略有問題的情況下,有時會出現單個IO延遲很高的情況,比如Raid卡電池充放電時,在沒有設定強行write back的情況下得會將write back模式修改為write through。

 

使用iostat命令檢視DB資料盤的IO情況,是否是單個IO的執行時間很長、塊大小和磁碟佇列情況等,可以比較一下DB盤的IO排程規則以及塊大小的設定等。

 

使用iostat檢視IO執行情況:

 

 

 

從IO情況看也沒什麼問題,單個IO延遲很小,IOPS很低,寫頻寬也不大。排程規則(cat /sys/block/fioa/queue/scheduler)和塊大小等和主機設定是一樣的,排除掉磁碟的問題。

 

從執行指標看,機器負載很低,機器效能也可以排除。

 

 

3大事務

 

 

  • 是否經常會有大事務?

 

這個可能DBA們會遇到比較多,比如在RBR模式下,執行帶有大量的Delete操作,或者在MBR模式下刪除時新增了不確定語句(類似limit)或一個表的Alter操作等,都會導致延遲情況的發生。

 

這種可通過檢視Processlist相關資訊,以及使用mysqlbinlog檢視binlog中的SQL就能快速進行確認。這個設想也被排除。

 

4

 

鎖衝突問題也可能導致從機的SQL執行緒執行慢,比如從機上有一些select  ....  for update的SQL,或者使用了MyISAM引擎等。此類問題,可以通過抓去Processlist以及檢視information_schema下面和鎖以及事務相關的表來檢視。

 

經過排查也並未發現鎖的問題。

 

5引數

 

引數部分使用如果是InnoDB引擎,可以根據自己的使用環境調整innodb_flush_log_at_trx_commit、sync_binlog引數來提升複製速度,那組DB使用的TokuDB,則可以優化tokudb_commit_sync、tokudb_fsync_log_period、sync_binlog等引數來做調整。這些引數調整後,複製的延遲情況會有一些作用。

 

備註:這種調整可能會影響資料的安全性,需要結合業務來考慮。

 

 

6多執行緒

 

 

多執行緒問題可能是DBA們遇到最多的問題,之前在5.1和5.5版本,MySQL的單執行緒複製瓶頸就廣受詬病。從5.6開始MySQL正式支援多執行緒複製。

 

很容易想到,如果是單執行緒同步的話,單個執行緒存在寫入瓶頸,導致主從延遲。那就先調整為多執行緒試試效果。

 

可以通過Show Processlist檢視是否有多個同步執行緒,也可以檢視引數的方式檢視是否使用多執行緒(show variables like '%slave_parallel%')

 

 

當你看到是上圖這種結果時,恭喜你,你使用的是單執行緒。可使用下面那行命令改造成多執行緒複製:

STOP SLAVE SQL_THREAD;

SET GLOBAL 

slave_parallel_type='LOGICAL_CLOCK';

SET GLOBAL 

slave_parallel_workers=8;

START SLAVE SQL_THREAD;

 

改造後如下圖所示:

 

 

 

我的環境如上圖所示,本來就已經是多執行緒複製了,因此問題的根源也不在是否開啟多執行緒複製上。但當我使用Show Processlist檢視複製狀態時,大多數情況下發現只有1個SQL執行緒在執行,如下圖所示:

 

 

 

通過上面的圖可發現,基本都是一個執行緒在執行,那麼可初步判定是多執行緒的威力沒有得到很好的發揮,為了更有力地說明問題,想辦法統計出來每個同步執行緒使用的比率。統計方法如下:

 

1、將線上從機相關統計開啟(出於效能考慮預設是關閉的),開啟方法如下:

UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME LIKE 'events_transactions%';

 

UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES'WHERE NAME = 'transaction';

 

2、建立一個檢視各同步執行緒使用量的檢視,程式碼如下:

USE test;

 

CREATE VIEW rep_thread_count AS SELECT a.THREAD_ID AS THREAD_ID,a.COUNT_STAR AS COUNT_STAR FROMperformance_schema.events_transactions_summary_by_thread_by_event_name a WHERE a.THREAD_ID in (SELECT b.THREAD_ID FROM performance_schema.replication_applier_status_by_worker b);

 

3、一段時間後統計各個同步執行緒使用比率,SQL如下:

SELECT SUM(COUNT_STAR) FROMrep_thread_count INTO @total;

 

SELECT 100*(COUNT_STAR/@total) AS thread_usage FROMrep_thread_count;

 

結果如下:

 

 

 

從上面的結果可以看出,絕大多數情況下,都是一個執行緒在跑,在監控這種存在大量資料匯入的場景下肯定容易出現瓶頸。如果能提高各個執行緒併發執行的能力,也許能很好地改善同步延遲的情況,那如何解決呢?

 

 

7組提交

 

 

我們不妨從多執行緒同步的原理來思考,在5.7中,多執行緒複製的功能有很很大的改善,支援LOGICAL_CLOCK的方式,在這種方式下,併發執行的多個事務只要能在同一時刻commit,就說明執行緒之間沒有鎖衝突,那麼Master就可以將這一組的事務標記並在slave機器上安全的進行併發執行。

 

因此,可以儘可能地使所有執行緒能在同一時刻提交,這樣就能很大程度上提升從機的執行的並行度,從而減少從機的延遲。

 

有了這個猜想後,很自然想到了人為控制儘可能多地使所有執行緒在同一時刻提交,其實官方已經給我們提供了類似的引數,引數如下:

binlog_group_commit_sync_delay

 

備註:這個引數會對延遲SQL的響應,對延遲非常敏感的環境需要特別注意,單位是微秒。

 

引數說明見:

https://dev.mysql.com/doc/refman/5.7/en/replication-options-binary-log.html#sysvar_binlog_group_commit_sync_delay

 

binlog_group_commit_sync_no_delay_count

 

備註:這個引數取到了一定的保護作用,在達到binlog_group_commit_sync_no_delay_count設定的值的時候,不管是否達到了binlog_group_commit_sync_delay設定定的閥值,都立即進行提交。

 

引數說明見:

https://dev.mysql.com/doc/refman/5.7/en/replication-options-binary-log.html#sysvar_binlog_group_commit_sync_no_delay_count

 

由於是監控的DB,主要是load資料,然後進行展示,1秒左右的匯入延遲對業務沒什麼影響,因此將兩個引數調整為:

SET GLOBAL binlog_group_commit_sync_delay = 1000000;

SET GLOBAL binlog_group_commit_sync_no_delay_count = 20;

 

備註:這兩個引數請根據業務特性進行調整,以免造成線上故障。

 

為了防止匯入SQL堆積,設定SET GLOBAL binlog_group_commit_sync_no_delay_count為20,在達到20個事務時不管是否達到了1秒都進行提交,來減少對業務的影響。

 

設定完這兩個引數後,發現併發複製瞬間提升了好多,很多時候8個執行緒都能跑滿。於是將執行緒調整到16個。執行一段事件後,再次統計各個同步執行緒的使用比率,發現併發度提升了非常多,新的比率如下圖所示:

 

 

 

通過show slave status檢視,發現從機延遲越來越小,目前已經完全追上,並穩定執行了一週。

 

 

三、總結

 

 

最後簡單總結一下,在遇到主從延遲的問題時,可從以下幾個地方開腦洞,尋找蛛絲馬跡,找到問題的根源,對症下藥才能藥到病除,排查範圍包括但不限於如下幾方面:

  • 網路方面

  • 效能方面

  • 配置方面(引數優化)

  • 大事務

  • 多執行緒複製

  • 組提交

 

通過上面對整個問題排查的梳理,希望能夠幫助廣大DBA在遇到類似複製延遲的問題時徹底終結問題。

 

相關文章