佳木斯湛栽影视文化发展公司

主頁(yè) > 知識(shí)庫(kù) > MySQL5.7并行復(fù)制原理及實(shí)現(xiàn)

MySQL5.7并行復(fù)制原理及實(shí)現(xiàn)

熱門(mén)標(biāo)簽:鐵路電話系統(tǒng) 地方門(mén)戶(hù)網(wǎng)站 服務(wù)外包 Linux服務(wù)器 AI電銷(xiāo) 網(wǎng)站排名優(yōu)化 百度競(jìng)價(jià)排名 呼叫中心市場(chǎng)需求

稍微了解過(guò)一點(diǎn)的數(shù)據(jù)的運(yùn)維就知道MySQL 5.5以及之前是單SQL線程回放,如果Master QPS稍微高點(diǎn),從上就有延遲了,5.6是基于庫(kù)的并行回放機(jī)制,只有當(dāng)多個(gè)庫(kù)的話才有復(fù)制才有優(yōu)勢(shì),而5.7是基于組的并行回放,同一組的事務(wù)可以并行重放從而解決延遲問(wèn)題。

MySQL 5.7并行復(fù)制時(shí)代

眾所周知,MySQL的復(fù)制延遲是一直被詬病的問(wèn)題之一,然而在Inside君之前的兩篇博客中(1,2)中都已經(jīng)提到了MySQL 5.7版本已經(jīng)支持“真正”的并行復(fù)制功能,官方稱(chēng)為為enhanced multi-threaded slave(簡(jiǎn)稱(chēng)MTS),因此復(fù)制延遲問(wèn)題已經(jīng)得到了極大的改進(jìn),甚至在Inside君所在的網(wǎng)易電商應(yīng)用中已經(jīng)完全消除了之前延遲長(zhǎng)達(dá)幾小時(shí)的問(wèn)題。然而,發(fā)現(xiàn)還是有很多小伙伴并不了解這個(gè)足以載入史冊(cè)的“偉大”的特性,故作分享??傊?,5.7版本后,復(fù)制延遲問(wèn)題永不存在。

MySQL 5.6并行復(fù)制架構(gòu)

誠(chéng)然,MySQL 5.6版本也支持所謂的并行復(fù)制,但是其并行只是基于schema的,也就是基于庫(kù)的。如果用戶(hù)的MySQL數(shù)據(jù)庫(kù)實(shí)例中存在多個(gè)schema,對(duì)于從機(jī)復(fù)制的速度的確可以有比較大的幫助。MySQL 5.6并行復(fù)制的架構(gòu)如下所示:

在上圖的紅色框框部分就是實(shí)現(xiàn)并行復(fù)制的關(guān)鍵所在。在MySQL 5.6版本之前,Slave服務(wù)器上有兩個(gè)線程I/O線程和SQL線程。I/O線程負(fù)責(zé)接收二進(jìn)制日志(更準(zhǔn)確的說(shuō)是二進(jìn)制日志的event),SQL線程進(jìn)行回放二進(jìn)制日志。如果在MySQL 5.6版本開(kāi)啟并行復(fù)制功能,那么SQL線程就變?yōu)榱薱oordinator線程,coordinator線程主要負(fù)責(zé)以前兩部分的內(nèi)容:

  • 若判斷可以并行執(zhí)行,那么選擇worker線程執(zhí)行事務(wù)的二進(jìn)制日志
  • 若判斷不可以并行執(zhí)行,如該操作是DDL,亦或者是事務(wù)跨schema操作,則等待所有的worker線程執(zhí)行完成之后,再執(zhí)行當(dāng)前的日志

這意味著coordinator線程并不是僅將日志發(fā)送給worker線程,自己也可以回放日志,但是所有可以并行的操作交付由worker線程完成。coordinator線程與worker是典型的生產(chǎn)者與消費(fèi)者模型。

上述機(jī)制實(shí)現(xiàn)了基于schema的并行復(fù)制存在兩個(gè)問(wèn)題,首先是crash safe功能不好做,因?yàn)榭赡苤髨?zhí)行的事務(wù)由于并行復(fù)制的關(guān)系先完成執(zhí)行,那么當(dāng)發(fā)生crash的時(shí)候,這部分的處理邏輯是比較復(fù)雜的。從代碼上看,5.6這里引入了Low-Water-Mark標(biāo)記來(lái)解決該問(wèn)題,從設(shè)計(jì)上看,其是希望借助于日志的冪等性來(lái)解決該問(wèn)題,不過(guò)5.6的二進(jìn)制日志回放還不能實(shí)現(xiàn)冪等性。另一個(gè)最為關(guān)鍵的問(wèn)題是這樣設(shè)計(jì)的并行復(fù)制效果并不高,如果用戶(hù)實(shí)例僅有一個(gè)庫(kù),那么就無(wú)法實(shí)現(xiàn)并行回放,甚至性能會(huì)比原來(lái)的單線程更差。而單庫(kù)多表是比多庫(kù)多表更為常見(jiàn)的一種情形。

MySQL 5.7基于組提交的并行復(fù)制

MySQL 5.7才可稱(chēng)為真正的并行復(fù)制,這其中最為主要的原因就是slave服務(wù)器的回放與主機(jī)是一致的即master服務(wù)器上是怎么并行執(zhí)行的slave上就怎樣進(jìn)行并行回放。

MySQL 5.7并行復(fù)制的思想簡(jiǎn)單易懂,一言以蔽之:一個(gè)組提交的事務(wù)都是可以并行回放,因?yàn)檫@些事務(wù)都已進(jìn)入到事務(wù)的prepare階段,則說(shuō)明事務(wù)之間沒(méi)有任何沖突(否則就不可能提交)。

為了兼容MySQL 5.6基于庫(kù)的并行復(fù)制,5.7引入了新的變量slave-parallel-type,其可以配置的值有:

  • DATABASE:默認(rèn)值,基于庫(kù)的并行復(fù)制方式
  • LOGICAL_CLOCK:基于組提交的并行復(fù)制方式

支持并行復(fù)制的GTID

如何知道事務(wù)是否在一組中,又是一個(gè)問(wèn)題,因?yàn)樵娴腗ySQL并沒(méi)有提供這樣的信息。在MySQL 5.7版本中,其設(shè)計(jì)方式是將組提交的信息存放在GTID中。那么如果用戶(hù)沒(méi)有開(kāi)啟GTID功能,即將參數(shù)gtid_mode設(shè)置為OFF呢?故MySQL 5.7又引入了稱(chēng)之為Anonymous_Gtid的二進(jìn)制日志event類(lèi)型,如:

mysql> SHOW BINLOG EVENTS in 'mysql-bin.000006';
 +------------------+-----+----------------+-----------+-------------+-----------------------------------------------+
 | Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
 +------------------+-----+----------------+-----------+-------------+-----------------------------------------------+
 | mysql-bin.000006 | 4 | Format_desc | 88 | 123 | Server ver: 5.7.7-rc-debug-log, Binlog ver: 4 |
 | mysql-bin.000006 | 123 | Previous_gtids | 88 | 194 | f11232f7-ff07-11e4-8fbb-00ff55e152c6:1-2 |
 | mysql-bin.000006 | 194 | Anonymous_Gtid | 88 | 259 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
 | mysql-bin.000006 | 259 | Query | 88 | 330 | BEGIN |
 | mysql-bin.000006 | 330 | Table_map | 88 | 373 | table_id: 108 (aaa.t) |
 | mysql-bin.000006 | 373 | Write_rows | 88 | 413 | table_id: 108 flags: STMT_END_F |
 .....

這意味著在MySQL 5.7版本中即使不開(kāi)啟GTID,每個(gè)事務(wù)開(kāi)始前也是會(huì)存在一個(gè)Anonymous_Gtid,而這GTID中就存在著組提交的信息。

LOGICAL_CLOCK

然而,通過(guò)上述的SHOW BINLOG EVENTS,我們并沒(méi)有發(fā)現(xiàn)有關(guān)組提交的任何信息。但是通過(guò)mysqlbinlog工具,用戶(hù)就能發(fā)現(xiàn)組提交的內(nèi)部信息:

# mysqlbinlog mysql-bin.0000006 | grep last_committed
#150520 14:23:11 server id 88 end_log_pos 259 CRC32 0x4ead9ad6 GTID last_committed=0 sequence_number=1
#150520 14:23:11 server id 88 end_log_pos 1483 CRC32 0xdf94bc85 GTID last_committed=0 sequence_number=2
#150520 14:23:11 server id 88 end_log_pos 2708 CRC32 0x0914697b GTID last_committed=0 sequence_number=3
#150520 14:23:11 server id 88 end_log_pos 3934 CRC32 0xd9cb4a43 GTID last_committed=0 sequence_number=4
#150520 14:23:11 server id 88 end_log_pos 5159 CRC32 0x06a6f531 GTID last_committed=0 sequence_number=5
#150520 14:23:11 server id 88 end_log_pos 6386 CRC32 0xd6cae930 GTID last_committed=0 sequence_number=6
#150520 14:23:11 server id 88 end_log_pos 7610 CRC32 0xa1ea531c GTID last_committed=6 sequence_number=7
...

可以發(fā)現(xiàn)較之原來(lái)的二進(jìn)制日志內(nèi)容多了last_committed和sequence_number,last_committed表示事務(wù)提交的時(shí)候,上次事務(wù)提交的編號(hào),如果事務(wù)具有相同的last_committed,表示這些事務(wù)都在一組內(nèi),可以進(jìn)行并行的回放。例如上述last_committed為0的事務(wù)有6個(gè),表示組提交時(shí)提交了6個(gè)事務(wù),而這6個(gè)事務(wù)在從機(jī)是可以進(jìn)行并行回放的。

上述的last_committed和sequence_number代表的就是所謂的LOGICAL_CLOCK。先來(lái)看源碼中對(duì)于LOGICAL_CLOCK的定義:

class Logical_clock
 {
 private:
 int64 state;
 /*
 Offset is subtracted from the actual "absolute time" value at
 logging a replication event. That is the event holds logical
 timestamps in the "relative" format. They are meaningful only in
 the context of the current binlog.
 The member is updated (incremented) per binary log rotation.
 */
 int64 offset;
 ......

state是一個(gè)自增的值,offset在每次二進(jìn)制日志發(fā)生rotate時(shí)更新,記錄發(fā)生rotate時(shí)的state值。其實(shí)state和offset記錄的是全局的計(jì)數(shù)值,而存在二進(jìn)制日志中的僅是當(dāng)前文件的相對(duì)值。使用LOGICAL_CLOCK的場(chǎng)景如下:

class MYSQL_BIN_LOG: public TC_LOG
 {
 ...
 public:
 /* Committed transactions timestamp */
 Logical_clock max_committed_transaction;
 /* "Prepared" transactions timestamp */
 Logical_clock transaction_counter;
 ...

可以看到在類(lèi)MYSQL_BIN_LOG中定義了兩個(gè)Logical_clock的變量:

  • max_c ommitted_transaction:記錄上次組提交時(shí)的logical_clock,代表上述mysqlbinlog中的last_committed
  • transaction_counter:記錄當(dāng)前組提交中各事務(wù)的logcial_clock,代表上述mysqlbinlog中的sequence_numbe

并行復(fù)制測(cè)試

下圖顯示了開(kāi)啟MTS后,slave服務(wù)器的QPS。測(cè)試的工具是sysbench的單表全update測(cè)試,測(cè)試結(jié)果顯示在16個(gè)線程下的性能最好,從機(jī)的QPS可以達(dá)到25000以上,進(jìn)一步增加并行執(zhí)行的線程至32并沒(méi)有帶來(lái)更高的提升。而原單線程回放的QPS僅在4000左右,可見(jiàn)MySQL 5.7 MTS帶來(lái)的性能提升,而由于測(cè)試的是單表,所以MySQL 5.6的MTS機(jī)制則完全無(wú)能為力了。

 

MySQL 5.7并行復(fù)制

并行復(fù)制配置與調(diào)優(yōu)

master_info_repository

開(kāi)啟MTS功能后,務(wù)必將參數(shù)master_info_repostitory設(shè)置為T(mén)ABLE,這樣性能可以有50%~80%的提升。這是因?yàn)椴⑿袕?fù)制開(kāi)啟后對(duì)于元master.info這個(gè)文件的更新將會(huì)大幅提升,資源的競(jìng)爭(zhēng)也會(huì)變大。在之前InnoSQL的版本中,添加了參數(shù)來(lái)控制刷新master.info這個(gè)文件的頻率,甚至可以不刷新這個(gè)文件。因?yàn)樗⑿逻@個(gè)文件是沒(méi)有必要的,即根據(jù)master-info.log這個(gè)文件恢復(fù)本身就是不可靠的。在MySQL 5.7中,Inside君推薦將master_info_repository設(shè)置為T(mén)ABLE,來(lái)減小這部分的開(kāi)銷(xiāo)。

slave_parallel_workers

若將slave_parallel_workers設(shè)置為0,則MySQL 5.7退化為原單線程復(fù)制,但將slave_parallel_workers設(shè)置為1,則SQL線程功能轉(zhuǎn)化為coordinator線程,但是只有1個(gè)worker線程進(jìn)行回放,也是單線程復(fù)制。然而,這兩種性能卻又有一些的區(qū)別,因?yàn)槎嗔艘淮蝐oordinator線程的轉(zhuǎn)發(fā),因此slave_parallel_workers=1的性能反而比0還要差,在Inside君的測(cè)試下還有20%左右的性能下降,如下圖所示:

​​​​​MySQL 5.7 并行復(fù)制​​​​​

這里其中引入了另一個(gè)問(wèn)題,如果主機(jī)上的負(fù)載不大,那么組提交的效率就不高,很有可能發(fā)生每組提交的事務(wù)數(shù)量?jī)H有1個(gè),那么在從機(jī)的回放時(shí),雖然開(kāi)啟了并行復(fù)制,但會(huì)出現(xiàn)性能反而比原先的單線程還要差的現(xiàn)象,即延遲反而增大了。聰明的小伙伴們,有想過(guò)對(duì)這個(gè)進(jìn)行優(yōu)化嗎?

Enhanced Multi-Threaded Slave配置

說(shuō)了這么多,要開(kāi)啟enhanced multi-threaded slave其實(shí)很簡(jiǎn)單,只需根據(jù)如下設(shè)置:

# slave
slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=16
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON

并行復(fù)制監(jiān)控

復(fù)制的監(jiān)控依舊可以通過(guò)SHOW SLAVE STATUS\G,但是MySQL 5.7在performance_schema架構(gòu)下多了以下這些元數(shù)據(jù)表,用戶(hù)可以更細(xì)力度的進(jìn)行監(jiān)控:

mysql> show tables like 'replication%';
 +---------------------------------------------+
 | Tables_in_performance_schema (replication%) |
 +---------------------------------------------+
 | replication_applier_configuration |
 | replication_applier_status |
 | replication_applier_status_by_coordinator |
 | replication_applier_status_by_worker |
 | replication_connection_configuration |
 | replication_connection_status |
 | replication_group_member_stats |
 | replication_group_members |
 +---------------------------------------------+
 8 rows in set (0.00 sec)

總結(jié)

MySQL 5.7推出的Enhanced Multi-Threaded Slave解決了困擾MySQL長(zhǎng)達(dá)數(shù)十年的復(fù)制延遲問(wèn)題,再次提醒一些無(wú)知的PostgreSQL用戶(hù),不要停留在之前對(duì)于MySQL的印象,物理復(fù)制也不一定肯定比邏輯復(fù)制有優(yōu)勢(shì),而MySQL 5.7的MTS已經(jīng)完全可以解決延遲問(wèn)題了。

Reference:

- http://www.ttlsa.com/mysql/mysql-5-7-enhanced-multi-thread-salve/

- http://moguhu.com/article/detail?articleId=129

- https://www.codercto.com/a/63073.html

- https://dev.mysql.com/doc/refman/5.7/en/replication-options-replica.html#sysvar_slave_preserve_commit_order

到此這篇關(guān)于MySQL5.7并行復(fù)制原理及實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)MySQL5.7并行復(fù)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • 詳解MySQL主從復(fù)制及讀寫(xiě)分離
  • MySQL主從復(fù)制斷開(kāi)的常用修復(fù)方法
  • MySQL復(fù)制問(wèn)題的三個(gè)參數(shù)分析
  • MySql主從復(fù)制機(jī)制全面解析
  • MySQL系列之十三 MySQL的復(fù)制

標(biāo)簽:衡水 仙桃 蘭州 湘潭 崇左 銅川 湖南 黃山

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《MySQL5.7并行復(fù)制原理及實(shí)現(xiàn)》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢(xún)

    • 400-1100-266
    保靖县| 霞浦县| 栖霞市| 泗水县| 阳信县| 庆元县| 安塞县| 巴东县| 郓城县| 砚山县| 山阴县| 武平县| 梁河县| 白银市| 桂林市| 大埔区| 南涧| 托克逊县| 安溪县| 长岛县| 黑河市| 秀山| 晴隆县| 汉源县| 桐城市| 长兴县| 元朗区| 仁化县| 南乐县| 临潭县| 霍林郭勒市| 沭阳县| 墨竹工卡县| 呼伦贝尔市| 县级市| 彭阳县| 金山区| 玉山县| 湘潭县| 黑河市| 鸡西市|