<b>背景</b>
对于解析mysql的binlog用来更新其他数据存储的应用来说,binlog的顺序标识是很重要的。比如根据时间戳得到binlog位点作为解析起点。
但是binlog里面的事件,是否有稳定的有序性?
binlog中有三个看上去可能有序的信息:xid、timestamp、gno。本文分析这三个信息在binlog中的有序性。
<b>xid</b>
当binlog格式为row,且事务中更新的是事务引擎时,每个事务的结束位置都有xid,xid的类型为整型。
mysql中每个语句都会被分配一个全局递增的query_id(重启会被重置),每个事务的xid来源于事务第一个语句的query_id。
考虑一个简单的操作顺序:
session 1: begin; select; update;
session 2: begin; select; update; insert; commit;
session 1: insert; commit;
显然xid2 > xid1,但因为事务2会先于事务1记录写binlog,因此在这个binlog中,会出现xid不是有序的情况。
<b>timestamp</b>
时间戳的有序性可能是被误用最多的。在mysqlbinlog这个工具的输出结果中,每个事务起始有会输出一个set timestamp=n。这个值取自第一个更新事件的时间。上一节的例子中,timestamp2>timestamp1,但因为事务2会先于事务1记录写binlog,因此在这个binlog中,会出现timestamp不是有序的情况。
<b>gno</b>
对于打开了gtid_mode的实例,每个事务起始位置都会有一个gtid event,其内容输出格式为uuid:gn,gno是一个整型数。
由于next_gtid是可以直接指定的,因此若故意构造,可以很容易得到不是递增的情况,这里只讨论automatic模式下的有序性。
与上述两种情况不同,gno生成于事务提交时写binlog的时候。注意这里不是生成binlog,而是将binlog写入磁盘的时候。因此实现上确保了同一个uuid下gno的有序性。
<b>小结</b>
一个binlog文件中的xid和timestamp无法保证有序性。在无特殊操作的情况下,相同的uuid可以保证gno的有序性。