MySQL並行複製探索!

寫在前面:
對於線上運行主從複製架構的環境而言,相信有很多人和筆者一樣,都或多或少的遇到過主從延遲的問題。之前筆者寫過一篇文章 主從複製延遲原因剖析 來講解主從複製延遲的原因,可光是知道原因還不行,怎麼解決這個主從延遲的問題纔是重頭戲!筆者,帶着這個疑問,在網上也是查閱了諸多資料,然後去其糟粕,根據自己的理解和查閱的資料整理成了本文 MySQL並行複製探索!。事先申明,本文內容是筆者自己的理解,不代表權威性,僅供各位同行做個參考,自己呢,也做個記錄。本着實事求是的原則,對於網上的諸多資料,筆者自己也只是信5分,懷疑5分,就算是官方的資料,有的也有bug不是,只有自己動手實踐過了,才能相信,纔有發言權,其他的,一切都是虛的!


並行複製產生的背景:
因爲I/O thread和SQL thread是單線程工作的,而Master是可以多線程寫入的,所以主從難免造成延遲
基於此,在5.6,5.7,8.0版本都在SQL線程上實現了多線程,來提升slave的併發度


爲什麼不是I/O多線程?
I/O沒必要多線程,因爲I/O線程並不是瓶頸啊 (沒怎麼理解)


並行複製的目的:
讓Slave SQL線程儘可能以多線程工作,解決複製延遲的問題

並行複製實現的前提:
能夠進行並行複製,關鍵在於多事務之間是否有鎖衝突


MySQL5.6基於schema的並行複製:
應用場景:
比較適用於一個庫中有多個schema的場景


並行複製的原理:
MySQL5.6開啓並行複製功能後,SQL線程變成coordinator線程,由其判斷是否可以併發執行,這意味着一個worker線程可以處理一個數據庫的連續事務,而不用等待其它數據庫完成
如果可以並行執行,選擇worker線程執行二進制日誌
如果不可以並行執行,如:DDL或者跨schema操作,則等待所有的worker線程執行完成之後再執行當前日誌


摘自網上的一張圖片,供參考理解:

圖片.png



基於schema的並行複製帶來的問題:
因爲MySQL5.6並行複製只是基於schema,但對於單庫多表的複製場景是無法實現的,甚至性能可能還達不到原來的單線程複製,而在實際工作中單庫多表比多庫多表的場景更爲常見。
MySQL5.6基於schema級別的併發複製可以解決業務表放在不同的DATABASE下同步延遲的問題,但是在實際生產中大部分表還是放在同一個庫中的,這種情況即使設置slave_parallel_workers大於0,也無法進行併發。在高併發的情況下,依然會造成主從複製延遲

MySQL5.6並行複製開啓:(前提是配置好主從複製環境)

mysql> stop slave;

Query OK, 0 rows affected (0.03 sec)


mysql> set global slave_parallel_workers=8;

Query OK, 0 rows affected (0.05 sec)


mysql> start slave;

Query OK, 0 rows affected, 1 warning (0.07 sec)


參考文檔:

http://blog.itpub.net/23718752/viewspace-2135701/

https://www.cnblogs.com/elontian/p/9989007.html


MySQL5.6並行複製原理圖:


圖片.png


並行複製參數說明:

slave_parallel_workers:
Number of applier threads for executing replication transactions in parallel. A value of 0 disables slave multithreading. Not supported by MySQL Cluster


官方文檔:
https://dev.mysql.com/doc/refman/5.6/en/replication-options-reference.html


MySQL5.7並行複製原理:
基於組複製(group commit)實現

如何知道事務是否在同一組中?
在MySQL 5.7版本中,其設計方式是將組提交的信息存放在GTID中。那麼如果用戶沒有開啓GTID功能,即:將參數gtid_mode設置爲OFF呢?
MySQL 5.7引入了稱之爲Anonymous_Gtid(ANONYMOUS_GTID_LOG_EVENT)的二進制日誌event類型,組提交信息存放在 Anonymous_Gtid 中。


開啓GTID時,每一個操作語句(DML/DDL)執行前就會添加一個GTID事件,記錄當前全局事務ID;同時在MySQL 5.7版本中,組提交信息也存放在GTID事件中,有兩個關鍵字段last_committed,sequence_number就是用來標識組提交信息的。在InnoDB中有一個全局計數器(global counter),在每一次存儲引擎提交之前,計數器值就會增加。在事務進入prepare階段之前,全局計數器的當前值會被儲存在事務中,這個值稱爲此事務的commit-parent(也就是last_committed)。last_committed表示事務提交的時候,上次事務提交的編號,如果事務具有相同的last_committed,表示這些事務都在一組內,可以進行並行的回放。而sequence_number是順序增長的,每個事務對應一個序列號。


這意味着在MySQL 5.7版本中即使不開啓GTID,每個事務開始前也是會存在一個Anonymous_Gtid,而這個Anonymous_Gtid事件中就存在着組提交的信息。反之,如果開啓了GTID後,就不會存在這個Anonymous_Gtid了,從而組提交信息就記錄在非匿名GTID事件中。

MySQL如何將這些事務進行分組的?
一個組提交的事務都是可以並行回放,因爲這些事務都已進入到事務的prepare階段,則說明事務之間沒有任何衝突(否則就不可能提交)


MySQL5.7並行複製簡介:
1)MySQL 5.7纔可稱爲真正的並行複製,這其中最爲主要的原因就是slave服務器的回放與master是一致的,即master服務器上是怎麼並行執行的,那麼slave上就怎樣進行並行回放。不再有庫的並行複製限制,對於二進制日誌格式也無特殊的要求(基於庫的並行複製也沒有要求)
2)MySQL5.7並行複製支持表級
3)Enhanced Multi-threaded Slaves(MTS

MySQL5.7並行複製參數:
SHOW VARIABLES LIKE 'slave_parallel_%'
Variable_name       Value
slave_parallel_type DATABASE (變量slave-parallel-type可以有兩個值:DATABASE 默認值,基於庫的並行複製方式;LOGICAL_CLOCK:基於組提交的並行複製方式(基於表)
slave_parallel_workers      0

MySQL 5.7並行複製配置與調優:
# slave
slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=16
slave_preserve_commit_order=1
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON

參考文檔:
https://blog.51cto.com/sky66/1688047
https://www.imooc.com/learn/589
https://dev.mysql.com/doc/refman/5.7/en/replication-options-slave.html
http://www.ywnds.com/?p=3894

MySQL5.7在線開啓並行複製(多線程複製):
參考視頻:https://www.imooc.com/video/10921


在Slave服務器上停止所有鏈路的複製

stop slave
set global slave-parallel-type=LOGICAL_CLOCK
set global slave-parallel-workers=16
start slave
show processlist(看到16個SQL線程)

MySQL5.7應用事務順序和realy log記錄事務順序不一樣的問題:
MySQL 5.7後的MTS可以實現更小粒度的並行複製,但需要將slave_parallel_type設置爲LOGICAL_CLOCK,但僅僅設置爲LOGICAL_CLOCK也會存在問題,因爲此時在slave上應用事務的順序是無序的,和relay log中記錄的事務順序不一樣,這樣數據一致性是無法保證的,爲了保證事務是按照relay log中記錄的順序來回放,就需要開啓參數slave_preserve_commit_order

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章