MySQL5.7.6: 通过序列区间来优化并行复制性能

 

我们知道,在MySQL5.7.2中增加了一种新的并行模式:为同时进入COMMIT阶段的事务分配相同的序列号,这些拥有相同序列号的事务在备库是可以并发执行的。

 

具体如何实现参阅我之前的一篇博客:http://mysqllover.com/?p=810

 

在之前的实现中,序列号是在binlog prepare阶段赋值,在engine commit(group commit的第三个阶段)之前递增,因此主库在GROUP COMMIT阶段的并发越高,在备库能够并发执行的事务越多。这个序列号被写入binlog中,备库根据序列号决定哪些事务可以并发执行。

 

然而我们考虑如下序列(Copy from worklog…)

 

    Trx1 ------------P----------C-------------------------------->
                                |
    Trx2 ----------------P------+---C---------------------------->
                                |   |
    Trx3 -------------------P---+---+-----C---------------------->
                                |   |     |
    Trx4 -----------------------+-P-+-----+----C----------------->
                                |   |     |    |
    Trx5 -----------------------+---+-P---+----+---C------------->
                                |   |     |    |   |
    Trx6 -----------------------+---+---P-+----+---+---C---------->
                                |   |     |    |   |   |
    Trx7 -----------------------+---+-----+----+---+-P-+--C------->
                                |   |     |    |   |   |  |

 

在之前的逻辑中,trx5 和 trx6是可以并发执行的,因为他们拥有相同的序列号;Trx4无法和Trx5并行,因为他们的序列号不同。同样的trx6和trx7也无法并行。当发现一个无法并发的事务时,就需要等待前面的事务执行完成才能继续下去,这会影响到备库的TPS。

 

但是理论上trx4应该可以和trx5和trx6并行,因为trx4先于trx5和trx6 prepare,如果trx5 和trx6能进入Prepare阶段,证明其和trx4是没有冲突的。

 

 

解决方案:

 

0.增加两个全局变量:

  /* Committed transactions timestamp */
Logical_clock max_committed_transaction;
/* "Prepared" transactions timestamp */
Logical_clock transaction_counter;

每个事务对应两个counter:last_committed 及 sequence_number

 

1.每次rotate或打开新的binlog时
MYSQL_BIN_LOG::open_binlog:
max_committed_transaction.update_offset(transaction_counter.get_timestamp());
transaction_counter.update_offset(transaction_counter.get_timestamp());
—>更新max_committed_transaction和transaction_counter的offset为当前的state值(或者说,为上个Binlog文件最大的transaction counter值)

 

 

2.每执行一条DML语句完成时,更新当前会话的last_committed= mysql_bin_log.max_committed_transaction
参考函数: binlog_prepare (参数all为false)

 

3. 事务提交时,写入binlog之前
binlog_cache_data::flush:
trn_ctx->sequence_number= mysql_bin_log.transaction_counter.step();
其中transaction_counter递增1

 

4.写入binlog
将sequence_number 和 last_committed写入binlog
MYSQL_BIN_LOG::write_gtid
记录binlog文件的seq number 和last committed会减去max_committed_transaction.get_offset(),也就是说,每个Binlog文件的序列号总是从(last_committed, sequence_number)=(0,1)开始

 

5.引擎层提交每个事务前更新max_committed_transaction
如果当前事务的sequence_number大于max_committed_transaction,则更新max_committed_transaction的值
MYSQL_BIN_LOG::process_commit_stage_queue –> MYSQL_BIN_LOG::update_max_committed

 

 

6.备库并发检查
函数:Mts_submode_logical_clock::schedule_next_event

 

假设初始状态下transaction_counter=1, max_committed_transaction=1, 以上述流程为例,每个事务的<last_committed,  sequence_number>序列为:
Trx1 prepare: last_commited = max_committed_transaction = 1;
Trx2 prepare: last_commited = max_committed_transaction = 1;
Trx3 prepare: last_commited = max_committed_transaction = 1;
Trx1 commit: sequence_number=++transaction_counter = 2, (transaction_counter=2, max_committed_transaction=2), write(1,2)
Trx4 prepare: last_commited =max_committed_transaction = 2;
Trx2 commit: sequence_number=++transaction_counter= 3,  (transaction_counter=3, max_committed_transaction=3), write(1,3)
Trx5 prepare: last_commited = max_committed_transaction = 3;
Trx6 prepare: last_commited = max_committed_transaction = 3;
Trx3 commit:  sequence_number=++transaction_counter= 4, (transaction_counter=4, max_committed_transaction=4), write(1,4)
Trx4 commit:  sequence_number=++transaction_counter= 5, (transaction_counter=5, max_committed_transaction=5), write(2, 5)
Trx5 commit:  sequence_number=++transaction_counter= 6, (transaction_counter=6, max_committed_transaction=6), write(3, 6)
Trx7 prepare: last_commited = max_committed_transaction = 6;
Trx6 commit:  sequence_number=++transaction_counter= 7, (transaction_counter=7, max_committed_transaction=7), write(3, 7)
Trx7 commit:  sequence_number=++transaction_counter= 8, (transaction_counter=8, max_committed_transaction=8), write(6, 8)

 

并发规则:
因此上述序列中可以并发的序列为:
trx1 1…..2
trx2 1………….3
trx3 1…………………….4
trx4        2………………………….5
trx5               3………………………………..6
trx6               3………………………………………………7
trx7                                                       6……………………..8

 

 

备库并行规则:当分发一个事务时,其last_committed 序列号比当前正在执行的事务的最小sequence_number要小时,则允许执行。
因此,
a)trx1执行,last_commit<2的可并发,trx2, trx3可继续分发执行
b)trx1执行完成后,last_commit < 3的可以执行, trx4可分发
c)trx2执行完成后,last_commit < 4的可以执行, trx5, trx6可分发
d)trx3、trx4、trx5完成后,last_commit < 7的可以执行,trx7可分发

 

原创文章,转载请注明: 转载自Simple Life

本文链接地址: MySQL5.7.6: 通过序列区间来优化并行复制性能

Post Footer automatically generated by wp-posturl plugin for wordpress.


Comments

Leave a Reply

Your email address will not be published. Name and email are required


Current month ye@r day *