MySQL 5.7才可稱為真正的并行復(fù)制,這其中最為主要的原因就是slave服務(wù)器的回放與主機(jī)是一致的即master服務(wù)器上是怎么并行執(zhí)行的slave上就怎樣進(jìn)行并行回放。不再有庫的并行復(fù)制限制,對于二進(jìn)制日志格式也無特殊的要求(基于庫的并行復(fù)制也沒有要求)。
從MySQL官方來看,其并行復(fù)制的原本計(jì)劃是支持表級的并行復(fù)制和行級的并行復(fù)制,行級的并行復(fù)制通過解析ROW格式的二進(jìn)制日志的方式來完成,WL#4648。但是最終出現(xiàn)給小伙伴的確是在開發(fā)計(jì)劃中稱為:MTS: Prepared transactions slave parallel applier,可見:WL#6314。該并行復(fù)制的思想最早是由MariaDB的Kristain提出,并已在MariaDB 10中出現(xiàn),相信很多選擇MariaDB的小伙伴最為看重的功能之一就是并行復(fù)制。
MySQL 5.7并行復(fù)制的思想簡單易懂,一言以蔽之:一個(gè)組提交的事務(wù)都是可以并行回放,因?yàn)檫@些事務(wù)都已進(jìn)入到事務(wù)的prepare階段,則說明事務(wù)之間沒有任何沖突(否則就不可能提交)。
為了兼容MySQL 5.6基于庫的并行復(fù)制,5.7引入了新的變量slave-parallel-type,其可以配置的值有:
如何知道事務(wù)是否在一組中,又是一個(gè)問題,因?yàn)樵娴腗ySQL并沒有提供這樣的信息。在MySQL 5.7版本中,其設(shè)計(jì)方式是將組提交的信息存放在GTID中。那么如果用戶沒有開啟GTID功能,即將參數(shù)gtid_mode設(shè)置為OFF呢?故MySQL 5.7又引入了稱之為Anonymous_Gtid的二進(jìn)制日志event類型,如:
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版本中即使不開啟GTID,每個(gè)事務(wù)開始前也是會存在一個(gè)Anonymous_Gtid,而這GTID中就存在著組提交的信息。
然而,通過上述的SHOW BINLOG EVENTS,我們并沒有發(fā)現(xiàn)有關(guān)組提交的任何信息。但是通過mysqlbinlog工具,用戶就能發(fā)現(xiàn)組提交的內(nèi)部信息:
root@localhost:~# 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
#150520 14:23:11 server id 88 end_log_pos 8834 CRC32 0x96864e6b GTID last_committed=6 sequence_number=8
#150520 14:23:11 server id 88 end_log_pos 10057 CRC32 0x2de1ae55 GTID last_committed=6 sequence_number=9
#150520 14:23:11 server id 88 end_log_pos 11280 CRC32 0x5eb13091 GTID last_committed=6 sequence_number=10
#150520 14:23:11 server id 88 end_log_pos 12504 CRC32 0x16721011 GTID last_committed=6 sequence_number=11
#150520 14:23:11 server id 88 end_log_pos 13727 CRC32 0xe2210ab6 GTID last_committed=6 sequence_number=12
#150520 14:23:11 server id 88 end_log_pos 14952 CRC32 0xf41181d3 GTID last_committed=12 sequence_number=13
...
可以發(fā)現(xiàn)較之原來的二進(jìn)制日志內(nèi)容多了last_committed和sequence_number,last_committed表示事務(wù)提交的時(shí)候,上次事務(wù)提交的編號,如果事務(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。先來看源碼中對于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)前文件的相對值。使用LOGICAL_CLOCK的場景如下:
class MYSQL_BIN_LOG: public TC_LOG
{
...
public:
/* Committed transactions timestamp */
Logical_clock max_committed_transaction;
/* "Prepared" transactions timestamp */
Logical_clock transaction_counter;
...
可以看到在類MYSQL_BIN_LOG中定義了兩個(gè)Logical_clock的變量:
更多建議: