1. 程式人生 > 實用技巧 >writeset引數配置探索——究竟在哪個角色上配置引數?

writeset引數配置探索——究竟在哪個角色上配置引數?

關於writeset,一直以來我都是所有節點同時配置下面引數:

binlog_transaction_dependency_tracking=WRITESET
transaction_write_set_extraction=xxhash64

但是這幾天在嘗試整理的時候,突然發現writeset的概念並不是想象中的那麼清晰,
也想要驗證一下老師提到的結論:

  1. 8.0的設計是針對從庫,主庫開啟writeset後(個人補充說明), 即使主庫在序列提交的事務,只要不互相沖突,在slave上也可以並行回放。
  2. 如果主庫配置了binlog group commit,從庫開了writeset,會優先使用writeset。
  • 從group commit進化的角度、及writeset的hash表原理來看,引數應該設定在master
  • 從結論2的角度來看,引數應該設定在slave

為此,做了一個實驗,分別在兩個角色上配置以上2個引數,來驗證究竟哪一邊設定才是有效的。

環境簡介

IP port role info
192.168.188.81 3316 node1 master
192.168.188.82 3316 node2 slave1
192.168.188.83 3316 node3 slave2

1主2從, MySQL版本8.0.19

實驗一:writeset配置在slave上

  • slave配置writeset:binlog_transaction_dependency_tracking=WRITESET & transaction_write_set_extraction=xxhash64
  • master只配置:binlog_group_commit_sync_delay & binlog_group_commit_sync_no_delay_count

配置引數

master:
binlog_group_commit_sync_delay       =100
binlog_group_commit_sync_no_delay_count = 10 

gtid_mode                           =on
enforce_gtid_consistency            =on
binlog_format                       =row
skip_slave_start                     =1 
master_info_repository               =table 
relay_log_info_repository            =table
slave:
binlog_transaction_dependency_tracking=WRITESET
transaction_write_set_extraction=xxhash64

skip_slave_start                     =1             
master_info_repository               =table         
relay_log_info_repository            =table         
slave_parallel_type                  =logical_clock 
slave_parallel_workers               =4  
#slave-preserve-commit-order         =ON

驗證實驗

  • 為方便檢視,slave上先切換日誌
root@slave1 [kk]>flush logs;
Query OK, 0 rows affected (0.05 sec)
  • 在master上建立1張表,並插入資料
root@master [kk]>flush logs;
Query OK, 0 rows affected (0.05 sec)

root@master [kk]>create table k3 (id int auto_increment primary key , dtl varchar(20) default 'a');
Query OK, 0 rows affected (0.05 sec)

root@master [kk]>insert into k3(dtl) values ('a');
Query OK, 1 row affected (0.02 sec)

root@master [kk]>insert into k3(dtl) values ('b');
Query OK, 1 row affected (0.01 sec)

root@master [kk]>insert into k3(dtl) values ('c');
Query OK, 1 row affected (0.01 sec)

root@master [kk]>insert into k3(dtl) values ('d');
Query OK, 1 row affected (0.02 sec)
  • 解析master的binlog,可以看到,master的binlog上每一個事務都是自成一組(每一個事務一個last_committed)
[root@ms81 logs]# mysqlbinlog -vvv --base64-output=decode-rows mysql-bin.000006 |grep last_committed
#200514 11:09:58 server id 813316  end_log_pos 272 CRC32 0xa8811d1b     GTID    last_committed=0        sequence_number=1       rbr_only=no     original_committed_timestamp=1589425798790755immediate_commit_timestamp=1589425798790755      transaction_length=242
#200514 11:10:05 server id 813316  end_log_pos 516 CRC32 0x8f66cd2f     GTID    last_committed=1        sequence_number=2       rbr_only=yes    original_committed_timestamp=1589425805035310immediate_commit_timestamp=1589425805035310      transaction_length=335
#200514 11:10:06 server id 813316  end_log_pos 851 CRC32 0x909932ba     GTID    last_committed=2        sequence_number=3       rbr_only=yes    original_committed_timestamp=1589425806709355immediate_commit_timestamp=1589425806709355      transaction_length=335
#200514 11:10:08 server id 813316  end_log_pos 1186 CRC32 0x50c4e104    GTID    last_committed=3        sequence_number=4       rbr_only=yes    original_committed_timestamp=1589425808607557immediate_commit_timestamp=1589425808607557      transaction_length=335
#200514 11:10:10 server id 813316  end_log_pos 1521 CRC32 0xf074c523    GTID    last_committed=4        sequence_number=5       rbr_only=yes    original_committed_timestamp=1589425810449588immediate_commit_timestamp=1589425810449588      transaction_length=335
  • 然後去slave上解析binlog,可以看到,slave的binlog上這幾個insert的事務成為了一組(幾個事務在一個last_committed中)
[root@ms82 logs]# mysqlbinlog -vvv --base64-output=decode-rows mysql-bin.000003 |grep last_committed
#200514 11:09:58 server id 813316  end_log_pos 279 CRC32 0xbf39f999     GTID    last_committed=0        sequence_number=1       rbr_only=no     original_committed_timestamp=1589425798790755immediate_commit_timestamp=1589425798840582      transaction_length=249
#200514 11:10:05 server id 813316  end_log_pos 530 CRC32 0x7e0b2634     GTID    last_committed=1        sequence_number=2       rbr_only=yes    original_committed_timestamp=1589425805035310immediate_commit_timestamp=1589425805046566      transaction_length=337
#200514 11:10:06 server id 813316  end_log_pos 867 CRC32 0x79b980e9     GTID    last_committed=1        sequence_number=3       rbr_only=yes    original_committed_timestamp=1589425806709355immediate_commit_timestamp=1589425806723726      transaction_length=337
#200514 11:10:08 server id 813316  end_log_pos 1204 CRC32 0x09b728d3    GTID    last_committed=1        sequence_number=4       rbr_only=yes    original_committed_timestamp=1589425808607557immediate_commit_timestamp=1589425808616207      transaction_length=337
#200514 11:10:10 server id 813316  end_log_pos 1541 CRC32 0x499da890    GTID    last_committed=1        sequence_number=5       rbr_only=yes    original_committed_timestamp=1589425810449588immediate_commit_timestamp=1589425810459612      transaction_length=337
  • 檢視一下master的配置,雖然my.cnf中沒配置binlog_transaction_dependency_tracking引數,但是該引數在8.0中預設設定為COMMIT_ORDER
root@localhost [kk]>show global variables like '%tracking%';
+----------------------------------------+--------------+
| Variable_name                          | Value        |
+----------------------------------------+--------------+
| binlog_transaction_dependency_tracking | COMMIT_ORDER |
+----------------------------------------+--------------+
1 row in set (0.02 sec)

實驗一的結論

根據實驗一的現象,套用複製流程可推測為:
1. master生成序列事務日誌到binlog,
2. 通過複製結構將binlog拉取到slave,稱為relay log
3. slave會按照master的binlog內容(relay log)進行apply
4. apply後再寫入到slave的binlog
那麼slave的binlog能說明slave是怎麼應用的relay log麼? 還是因為slave配置了writeset,所以slave生成的binlog中發生了write-set?

實驗二:writeset配置在master上

  • slave不配置writeset:binlog_transaction_dependency_tracking=WRITESET & transaction_write_set_extraction=xxhash64
  • master增加配置:binlog_transaction_dependency_tracking=WRITESET & transaction_write_set_extraction=xxhash64

配置引數,並重啟例項

master:
binlog_transaction_dependency_tracking=WRITESET
transaction_write_set_extraction=xxhash64

binlog_group_commit_sync_delay       =100
binlog_group_commit_sync_no_delay_count = 10 

gtid_mode                           =on
enforce_gtid_consistency            =on
binlog_format                       =row
skip_slave_start                     =1 
master_info_repository               =table 
relay_log_info_repository            =table
slave:
#binlog_transaction_dependency_tracking=WRITESET  #註釋掉
#transaction_write_set_extraction=xxhash64   #註釋掉

skip_slave_start                     =1             
master_info_repository               =table         
relay_log_info_repository            =table         
slave_parallel_type                  =logical_clock 
slave_parallel_workers               =4  
#slave-preserve-commit-order         =ON

驗證實驗

  • 還是為方便檢視,slave上先切換日誌
root@slave1 [kk]>flush logs;
Query OK, 0 rows affected (0.05 sec)
  • 在master上建立1張表,並插入資料
root@master [(none)]>flush logs;
Query OK, 0 rows affected (0.03 sec)

root@master [kk]>create table k4 (id int auto_increment primary key , dtl varchar(20) default 'a');
Query OK, 0 rows affected (0.05 sec)

root@master [kk]>insert into k4(dtl) values ('a');
Query OK, 1 row affected (0.02 sec)

root@master [kk]>insert into k4(dtl) values ('b');
Query OK, 1 row affected (0.01 sec)

root@master [kk]>insert into k4(dtl) values ('c');
Query OK, 1 row affected (0.01 sec)

root@master [kk]>insert into k4(dtl) values ('d');
Query OK, 1 row affected (0.01 sec)

  • 解析master的binlog,可以看到,master上insert事務組成了一組(具有相同的last_committed)
[root@ms81 logs]# mysqlbinlog -vvv --base64-output=decode-rows mysql-bin.000008 |grep last_committed
#200514 11:25:55 server id 813316  end_log_pos 272 CRC32 0x1a3b45da     GTID    last_committed=0        sequence_number=1       rbr_only=no     original_committed_timestamp=1589426755949559immediate_commit_timestamp=1589426755949559      transaction_length=242
#200514 11:26:06 server id 813316  end_log_pos 516 CRC32 0x9f51382b     GTID    last_committed=1        sequence_number=2       rbr_only=yes    original_committed_timestamp=1589426766237292immediate_commit_timestamp=1589426766237292      transaction_length=335
#200514 11:26:08 server id 813316  end_log_pos 851 CRC32 0xb02fc356     GTID    last_committed=1        sequence_number=3       rbr_only=yes    original_committed_timestamp=1589426768166475immediate_commit_timestamp=1589426768166475      transaction_length=335
#200514 11:26:09 server id 813316  end_log_pos 1186 CRC32 0x615fb932    GTID    last_committed=1        sequence_number=4       rbr_only=yes    original_committed_timestamp=1589426769816765immediate_commit_timestamp=1589426769816765      transaction_length=335
#200514 11:26:12 server id 813316  end_log_pos 1521 CRC32 0x13bceeb8    GTID    last_committed=1        sequence_number=5       rbr_only=yes    original_committed_timestamp=1589426772153679immediate_commit_timestamp=1589426772153679      transaction_length=335

看來writeset在主庫上影響了binlog的內容了,接下來看一下slave的binlog

  • 然後去slave上解析binlog,可以看到,slave上這幾個insert的事務各自成了一組
[root@ms82 logs]# mysqlbinlog -vvv --base64-output=decode-rows mysql-bin.000005 |grep last_committed
#200514 11:25:55 server id 813316  end_log_pos 279 CRC32 0x96a31487     GTID    last_committed=0        sequence_number=1       rbr_only=no     original_committed_timestamp=1589426755949559immediate_commit_timestamp=1589426755999296      transaction_length=249
#200514 11:26:06 server id 813316  end_log_pos 530 CRC32 0x54711cb2     GTID    last_committed=1        sequence_number=2       rbr_only=yes    original_committed_timestamp=1589426766237292immediate_commit_timestamp=1589426766253024      transaction_length=337
#200514 11:26:08 server id 813316  end_log_pos 867 CRC32 0xf20ad235     GTID    last_committed=2        sequence_number=3       rbr_only=yes    original_committed_timestamp=1589426768166475immediate_commit_timestamp=1589426768176639      transaction_length=337
#200514 11:26:09 server id 813316  end_log_pos 1204 CRC32 0xa3b00643    GTID    last_committed=3        sequence_number=4       rbr_only=yes    original_committed_timestamp=1589426769816765immediate_commit_timestamp=1589426769825978      transaction_length=337
#200514 11:26:12 server id 813316  end_log_pos 1541 CRC32 0xce0fd88f    GTID    last_committed=4        sequence_number=5       rbr_only=yes    original_committed_timestamp=1589426772153679immediate_commit_timestamp=1589426772164468      transaction_length=337

此時slave的引數binlog_transaction_dependency_tracking為預設值

root@slave1 [(none)]>show global variables like '%tracking%';
+----------------------------------------+--------------+
| Variable_name                          | Value        |
+----------------------------------------+--------------+
| binlog_transaction_dependency_tracking | COMMIT_ORDER |
+----------------------------------------+--------------+
1 row in set (0.01 sec)

實驗二結論

根據實驗二的現象,套用複製流程可推測為:
1. master生成序列事務,writeset特性將事務按照write-set進行分組,寫到binlog中
2. 通過複製結構將binlog拉取到slave,稱為relay log
3. slave會按照master的binlog內容(relay log)進行apply
4. apply後再寫入到slave的binlog

參考官方文件,我傾向於認為,slave應用relay log時是按照master的writeset分組進行並行apply的。
那麼,目前的實驗結論就與前面的結論2相悖了。

The source of dependency information that the master uses to determine which transactions can be executed in parallel by the slave's multithreaded applier. This variable can take one of the three values described in the following list:

  • COMMIT_ORDER: Dependency information is generated from the master's commit timestamps. This is the default. This mode is also used for any transactions without write sets, even if this variable's is WRITESET or WRITESET_SESSION; this is also the case for transactions updating tables without primary keys and transactions updating tables having foreign key constraints.
  • WRITESET: Dependency information is generated from the master's write set, and any transactions which write different tuples can be parallelized.
  • WRITESET_SESSION: Dependency information is generated from the master's write set, but no two updates from the same session can be reordered.