轉(zhuǎn)載于:https://blog.csdn.net/demonson/article/details/80981632
并發(fā)復(fù)制(Parallel Replication) Enhanced Multi-threaded Slaves
首先梳理下傳統(tǒng)MySQL/MariaDB主備復(fù)制基本原理:
主從復(fù)制通過三個線程來完成滞项,在master節(jié)點運行的binlog dump的線程,I/O線程和SQL線程運行在slave 節(jié)點
master節(jié)點的Binlog dump線程枚赡,當slave節(jié)點與master正常連接的時候,master把更新的binlog 內(nèi)容推送到slave節(jié)點。
slave節(jié)點的I/O 線程 茉帅,該線程通過讀取master節(jié)點binlog日志名稱以及偏移量信息將其拷貝到本地relay log日志文件瘫絮。
slave節(jié)點的SQL線程,該線程讀取relay log日志信息私恬,將在master節(jié)點上提交的事務(wù)在本地回放债沮,達到與主庫數(shù)據(jù)保持一致的目的。
問題1:
Master節(jié)點的數(shù)據(jù)庫實例并發(fā)跑多個線程同時提交事務(wù)本鸣,提交的事務(wù)按照邏輯的時間(數(shù)據(jù)庫LSN號)順序地寫入binary log日志疫衩,,slave節(jié)點通過I/O線程寫到本地的relay log日志,但是slave節(jié)點只有SQL單線程來執(zhí)行relay log中的日志信息重放主庫提交得事務(wù)荣德,造成主備數(shù)據(jù)庫存在延遲(lag)
思考1:
那么為了減少主備數(shù)據(jù)同步延遲時間闷煤,由于備庫只有單線程補償數(shù)據(jù)的原因而造成延遲,那么能否使slave節(jié)點同時運行多個如SQL線程一樣的功能來重放在主庫執(zhí)行的事務(wù)涮瞻?答案當然是:可以鲤拿!但是我們需要解決以下問題:
1、slave本地的relay log記錄的是master 的binary log日志信息饲宛,日志記錄的信息按照事務(wù)的時間先后順序記錄皆愉,那么為了保證主備數(shù)據(jù)一致性,slave節(jié)點必須按照同樣的順序執(zhí)行,如果順序不一致容易造成主備庫數(shù)據(jù)不一致的風險幕庐。
如:
在master節(jié)點提交T1和T2事務(wù)按照以下順序
State0: x= 1, y= 1
T1: { x:= Read(y);
x:= x+1;
Write(x);
Commit; }
State1: x= 2, y= 1
T2: { y:= Read(x);
y:=y+1;
Write(y);
Commit; }
State2: x= 2, y= 3
slave節(jié)點執(zhí)行T1和T2相反的順序:
State0: x= 1, y= 1
T2: { y:= Read(x);
y:= y+1;
Write(y);
Commit; }
State1: x= 1, y= 2
T1: { x:= Read(y);
x:=x+1;
Write(x);
Commit; }
State2: x= 3, y= 2
MySQL 5.6改進:
MySQL 5.6版本引入并發(fā)復(fù)制(schema級別)久锥,基于schema級別的并發(fā)復(fù)制核心思想:“不同schema下的表并發(fā)提交時的數(shù)據(jù)不會相互影響,即slave節(jié)點可以用對relay log中不同的schema各分配一個類似SQL功能的線程异剥,來重放relay log中主庫已經(jīng)提交的事務(wù)瑟由,保持數(shù)據(jù)與主庫一致”≡┦伲可見MySQL5.6版本的并發(fā)復(fù)制歹苦,一個schema分配一個類似SQL線程的功能。
實現(xiàn)1:
slave節(jié)點開啟并發(fā)復(fù)制(slave_parallel_workers=3)如下圖督怜,當前的slave的SQL線程為Coordinator(協(xié)調(diào)器)殴瘦,執(zhí)行relay log日志的線程為worker(當前的SQL線程不僅起到協(xié)調(diào)器的作用,同時也可以重放relay log中主庫提交的事務(wù))
+-----+-------------+-----------+------+---------+-------+--------------------------------------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+-----+-------------+-----------+------+---------+-------+--------------------------------------------------------+------------------+
| 1 | system user | | NULL | Connect | 29923 | Slave has read all relay log; waiting for more updates | NULL |
| 2 | system user | | NULL | Connect | 29923 | Waiting for an event from Coordinator | NULL |
| 3 | system user | | NULL | Connect | 29923 | Waiting for an event from Coordinator | NULL |
| 4 | system user | | NULL | Connect | 29923 | Waiting for an event from Coordinator | NULL |
問題2:
MySQL 5.6基于schema級別的并發(fā)復(fù)制能夠解決當業(yè)務(wù)數(shù)據(jù)的表放在不同的database庫下号杠,但是實際生產(chǎn)中往往大多數(shù)或者全部的業(yè)務(wù)數(shù)據(jù)表都放在同一個schema下蚪腋,在這種場景即使slave_parallel_workers>0設(shè)置也無法并發(fā)執(zhí)行relay log中記錄的主庫提交數(shù)據(jù)。 高并發(fā)的情況下姨蟋,由于slave無法并發(fā)執(zhí)行同個schema下的業(yè)務(wù)數(shù)據(jù)表屉凯,依然會造成主備延遲的情況。
思考2:
那么如果slave同時可以用多線程的方式眼溶,同時執(zhí)行一個schema下的所有業(yè)務(wù)數(shù)據(jù)表悠砚,將能大大提高slave節(jié)點執(zhí)行ralay log中記錄的主庫提交事務(wù)達到與主庫數(shù)據(jù)同步的目的,實現(xiàn)該功能我們需要解決什么問題堂飞?
1灌旧、前面提到過為了保證主庫數(shù)據(jù)一致性,master節(jié)點寫入的binary log日志按照數(shù)據(jù)庫邏輯時間先后的順序并且slave節(jié)點執(zhí)行relay log中主庫提交的事務(wù)必須按照一致的順序否則會造成主備數(shù)據(jù)不一致的情況酝静。
2节榜、既然要實現(xiàn)scehma下所有的業(yè)務(wù)數(shù)據(jù)表能夠并發(fā)執(zhí)行,那么slave必須得知道并發(fā)執(zhí)行relay log中主庫提交的事務(wù)不能相互影響而且結(jié)果必須和主庫保持一致别智。
實現(xiàn)2:
MySQL 5.7 引入Enhanced Muti-threaded slaves,當slave配置slave_parallel_workers>0并且global.slave_parallel_type=‘LOGICAL_CLOCK’,可支持一個schema下宗苍,slave_parallel_workers個的worker線程并發(fā)執(zhí)行relay log中主庫提交的事務(wù)。但是要實現(xiàn)以上功能薄榛,需要在master機器標記binary log中的提交的事務(wù)哪些是可以并發(fā)執(zhí)行讳窟,雖然MySQL 5.6已經(jīng)引入了binary log group commit,但是沒有將可以并發(fā)執(zhí)行的事務(wù)標記出來敞恋。
我們用命令 mysqlbinlog -vvv mysqlbinlog.0000003 | grep -i last_committed 在MySQL 5.7的master機器上可以看到last_committed 和sequence_number
-
151223 15:11:28 server id 15102 end_log_pos 14623 CRC32 0x767a33fa GTID last_committed=18 sequence_number=26
-
151223 15:11:28 server id 15102 end_log_pos 15199 CRC32 0x7dd1bf05 GTID last_committed=26 sequence_number=27
-
151223 15:11:28 server id 15102 end_log_pos 15773 CRC32 0xb01dc76e GTID last_committed=26 sequence_number=28
-
151223 15:11:28 server id 15102 end_log_pos 16347 CRC32 0x7a8e0ee8 GTID last_committed=26 sequence_number=29
-
151223 15:11:28 server id 15102 end_log_pos 16921 CRC32 0x92516d17 GTID last_committed=26 sequence_number=30
-
151223 15:11:28 server id 15102 end_log_pos 17495 CRC32 0xeb14a51e GTID last_committed=26 sequence_number=31
-
151223 15:11:28 server id 15102 end_log_pos 18071 CRC32 0x750667d0 GTID last_committed=26 sequence_number=32
-
151223 15:11:28 server id 15102 end_log_pos 18645 CRC32 0xcaed6159 GTID last_committed=26 sequence_number=33
-
151223 15:11:28 server id 15102 end_log_pos 19219 CRC32 0x62408408 GTID last_committed=26 sequence_number=34
-
151223 15:11:28 server id 15102 end_log_pos 19793 CRC32 0x5cf46239 GTID last_committed=33 sequence_number=35
slave機器的relay log中 last_committed相同的事務(wù)(sequence_num不同)可以并發(fā)執(zhí)行丽啡。從上面截取的信息可以看出last_committed=26的事務(wù)一共有8個:從sequence_number=27~24。假設(shè)當slave_parallel_workers=7時硬猫,Coordinator線程(SQL線程)分配這一組事務(wù)到worker中排隊去執(zhí)行补箍。這里可以看出增加master庫binary log group commit組中事務(wù)的數(shù)量可以提高slave機器并發(fā)處理事務(wù)的數(shù)量改执,MySQL5.7引入 binlog_group_commit_sync_delay和 binlog_group_commit_sync_no_delay_count參數(shù)即提高binary log組提交并發(fā)數(shù)量。MySQL等待binlog_group_commit_sync_delay毫秒的時間直到binlog_group_commit_sync_no_delay_count個事務(wù)數(shù)時坑雅,將進行一次組提交辈挂。
總結(jié):
MySQL 5.7 GA版本推出的 Enhanced Multi-threaded Slaves功能,徹底解決了之前版本主備數(shù)據(jù)復(fù)制延遲的問題裹粤,開啟該功能參數(shù)如下:
-
slave機器
slave-parallel-type=LOGICAL_CLOCK
#slave-parallel-type=DATABASE #兼容MySQL 5.6基于schema級別的并發(fā)復(fù)制
slave-parallel-workers=16 #開啟多線程復(fù)制
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON
從MySQL5.5.X版本開始终蒂,增加了relay_log_recovery參數(shù),這個參數(shù)的作用是:當slave從庫宕機后遥诉,假如relay-log損壞了拇泣,導(dǎo)致一部分中繼日志沒有處理,則自動放棄所有未執(zhí)行的relay-log矮锈,并且重新從master上獲取日志霉翔,這樣就保證了relay-log的完整性。默認情況下該功能是關(guān)閉的愕难,將relay_log_recovery的值設(shè)置為 1時早龟,可在slave從庫上開啟該功能惫霸,建議開啟猫缭。
關(guān)于relay_log_recovery參數(shù)的介紹,請參見MySQL5.5手冊:
把relay.info記錄在slave_relay_log_info表里有兩個好處:
1.relay.info明文存儲不安全壹店,把relay.info中的信息記錄在table中相對安全猜丹。
2.可以避免relay.info更新不及時,SLAVE 重啟后導(dǎo)致的主從復(fù)制出錯硅卢。
執(zhí)行下述查詢射窒,檢查relay_log_info_repository,master_info_repository值是否為table,
relay_log_recovery 是否開啟将塑。
SHOW VARIABLES WHERE variable_name IN ('relay_log_recovery','relay_log_info_repository','master_info_repository');
relay_log_info_repository,master_info_repository值如果為FILE脉顿,建議將其修改為TABLE.
修改步驟如下:
- stop slave;
- set GLOBAL relay_log_info_repository='TABLE';
3.在my.cnf中設(shè)置
relay_log_info_repository = TABLE
master_info_repository = TABLE
relay_log_recovery = on
4.restart mysql
5.start slave;
- 檢查relay_log_info_repository是否修改成功。
show variables where variable_name in ('relay_log_info_repository','master_info_repository');
relay_log_info_repository,master_info_repository值設(shè)置為TABLE后点寥,可以利用如下SQL查詢主從同步的信息:
select * from mysql.slave_master_info;
select * from mysql.slave_relay_log_info;