时间戳的有序性可能是被误用最多的。在mysqlbinlog��个工具的输出结果中,每个事务起始有会输出一个SET TIMESTAMP=n。这个值取自第一个更新事件的时间。上一节的例子中,timestamp2>timestamp1,但因为事务2会先于事务1记录写binlog,因此在这个binlog中,会出现TIMESTAMP不是有序的情况。
GNO
对于打开了gtid_mode的实例,每个事务起始位置都会有一个gtid event,其内容输出格式为UUID:gn,gno是一个整型数。
由于NEXT_GTID是可以直接指定的,因此若故意构造,可以很容易得到不是递增的情况,这里只讨论automatic模式下的有序性。
与上述两种情况不同,gno生成于事务提交时写binlog的时候。注意这里不是生成binlog,而是将binlog写入磁盘的时候。因此实现上确保了同一个UUID下gno的有序性。
小结
一个binlog文件中的Xid和TIMESTAMP无法保证有序性。在无特殊操作的情况下,相同的UUID可以保证gno的有序性。
MySQL· 答疑释惑·server_id为0的Rotate背景
在MySQL的M-S结构里面,event是binlog日志的基本单位。每个event来源于主库,每个Event都包含了serverid,用于表示该event是哪个实例生成的。
在5.6里面,细心的同学会发现,备库的relaylog中出现了server_id为0的event,其类型为Rotate Event。
这里说说server_id=0的Rotate Event。
心跳event
MySQL Cluster中从NDB 6.3开始就出现的HEADBEAT event(hb event), 在社区版直到5.6.2才提供。
hb event的目的是为了保持M-S之间的心跳。用法上是slave在change master的时候可以指定MASTER_HEARTBEAT_PERIOD。当此值为0时,主库发送完所有事件后这个主备通道就一直idle直到发送新的event;当此值为非0的n时,主库通道在idle超过n秒之后,发一个hb event。
心跳event的另外一个作用是主库将当前的最新位点通知给备库。hb event中包含主库当前binlog最新位置的文件名和位点。备库收到hb event后判断主库位点是否大于本地保存的位点,若是,则在relay log中记录一个server_id为0的Rotate事件, 这意味着主库上新增了不需要发送给自己的event。
出现条件
在传统的主备环境中,正常情况下心跳事件是不会被触发写入到备库的relaylog的。这是因为所有的主库binlog中的事件都会发给备库,所以备库收到的hb event中的位点总是不大于备库已经接收到的binlog event最大值(注意到hb event只在通道idle时才发)。
但是在5.6启用了GTID以后,就出现了这样的case。最常见的是每个binlog文件开头用于表示之前所有binlog执行过的事件合集的Previous-GTIDs,这个事件需要记录在binlog中,但是不需要发给slave。这就会让备库在接收到hb之后记录一个server_id=0的Rotate event。
主库relaylog
与此相关的,一个可能出现的现象是双M单写场景下,备库没有更新,但是主库会一直写relay log。
步骤如下:
1、主备之间完成MM关系(GTID_MODE=on)
2、主库和备库各自stop slave
3、主库执行大量更新
4、主库start slave
5、备库start slave
在备库同步日志过程中生成了本地的binlog,这些binlog需要再发回给主库。5.6的一个机制是,如果发现通道对面的接收方的executed_set已经包含了这个事件,则不发送。
由于这些事件本身就是主库发送过来的,因此备库都不需要发回。但是备库必须通知主库本地的binlog的最新位点,因此构造了一个hb event。
主库收到hb event后记录在relaylog中,形式就是server_id=0的Rotate事件。
MySQL· 性能优化·Bulk Load for CREATE INDEX背景
MySQL5.6以后的版本提供了多种优化手段用于create index,比如online方式,Bulk Load方式。
Online提供了非阻塞写入的方式创建索引,为运维提供了很大的便利。 Bulk Load提升了索引创建的效率,减少了阻塞的时间。这篇介绍下MySQL 5.7.5 Bulk Load的细节,并从查找,排序,redo,undo,page split等维度比较一下传统方式和Bulk Load方式。
传统方式
MySQL 5.7.5版本之前,create index使用的是和insert一条记录相同的api接口,即自上而下的插入方式。
步骤1: 扫描clustered index,得到行记录。 步骤2: 根据record,按照B-Tree的结构,从root->branch->leaf page查找到属于record的位置。: 步骤3: 调用write index record接口,维护索引。1. 查找: 对每一条记录在插入前从B-Tree上查找到自己的位置。 2. 排序: 因为是按照B-Tree的结构,所以每一条记录插入都是有序的。 3. redo: 每条记录的插入都会记录innodb的redo做保护。 4. undo: 记录每个插入记录位置的undo 5. page split: 插入采用optimistic的方式,如果失败而发现page full,那么就split page,并向上更新branch page。
从上面的步骤和几个维度的说明上,传统的create index比较简单,但一方面会阻塞写入,另一方面效率会比较低,延长了不可用时间。
Bulk Load方式