最近对同机房semisync性能优化告一段落,性能基本能达到预期;目前优化的版本基于MySQL5.6.14,基本优化思路是让备库尽快的发送ACK。主要的优化点简单总结下:
a).备库在接受到需要ack的事件时,先ack,再去写relay log。对于不需要ack的事件只写IO Cache
原始行为为每接受到一个事件就写一次relay log,在同机房场景下,可能存在网络IO已经完成,备库还没写完数据到磁盘
b).备库在需要ack时才去刷master info文件
原始行为是每接受一个事件写一次master_info文件
a)和b)以牺牲备库日志的持久化来提升semisync场景下的主库性能,当备库挂了时,只需要从一个安全的位点重拉binlog即可;
使用sysbench测试的结果:TPS 13000(原生semisync) => 24000 (改进后semisync)
无semisync的TPS约为28000
上述测试同时基于以下的改进
c).主库上在事务commit之前等待备库ack(AFTER_SYNC),在等待期间其他事务无法看到等待线程所做的修改,如果主库挂了,切换到备库后,应用连接只需要检查数据是否更新成功即可 (Port From MySQL5.7.2)
原始行为为在事务commit之后(AFTER_COMMIT),每个应用连接等待备库ack,这种情况下在主备切换后,应用连接将无法判断其事务是否成功提交(数据可能被修改多次)
AFTER_SYNC比AFTER_COMMIT更能保证数据的一致性,并且有一定的性能提升,因为在AFTER_SYNC发生在innodb group commit之前,由Leader线程来等待,只需要唤醒leader,而AFTER_COMMIT在大thread running下,可能需要唤醒大量应用连接,开销更大
d).mysql_binlog_send函数不再需要持有Lock_log锁来读取binlog事件,而是维持一个文件末尾的偏移量;(Port From MySQL5.7.2, Facebook mysql5.6有类似实现)
原始行为中,写binlog和读binlog都需要Lock_log这个大锁来保护,这会导致锁竞争,如果有多个备库dump线程,这种竞争会影响到TPS
e).在rotate时,需要生成下一个binlog文件,在设定文件名后缀时,避免扫描整个文件夹,改为维护一个递增数字
其他一些小的修改点不一一列出;
semisync接下来潜在的优化点:
a).大量dump线程对主库性能的影响需要纳入考虑(例如bug#70342)
b).如何保证主备库的强一致;例如,主库宕机,事务已写入本地Binlog,但还没发送到备库;主备切换后,如果应用链接在备库重试事务,则主备一致;如果应用抛弃该事务,或走其他逻辑,那么挂掉重启后的主库可能比备库多执行了事务(利用ADHA回滚机制?)
c).在跨机房场景下,网络称为瓶颈时,如何解决(并发网络IO?)
d).内建semisync,而不是通过plugin的形式,是否可能带来性能提升?
e).主库semisync 的大锁对性能的影响?