October 2013

近期对semisync的一些优化

最近对同机房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 的大锁对性能的影响? 原创文章,转载请注明: 转载自Simple Life 本文链接地址: 近期对semisync的一些优化 Post Footer automatically generated by wp-posturl plugin for wordpress.

MySQL5.7 简述新的复制模式LOGICAL_CLOCK

我们知道,在MySQL5.6中引入了并行复制模式,当实例上有多个库的时候,可以在备库上对这几个库进行并发操作;这在基于分库的应用场景下,可以显著提升备库的复制效率,但对于我们以分表为主的场景,则效果甚微。 MySQL5.7.2是最新的开发版本release,在该版本中可以看到对复制部分做了非常大的改动,例如半同步复制的after sync, 使用Performance Schema表来监控复制线程,实验室版本的多主复制,以及本文要提到的新的多线程复制模式,MySQL里用一个新的参数来控制:slave_parallel_type,默认值为DATABASE,表示默认行为;另外一个值为LOGICAL_CLOCK,即为新增的模式 1.基本思路 由于MySQL存储引擎层已经保证了同时能够进入事务prepare/commit阶段的事务是没有冲突的(例如Innodb的行锁机制来保证事务的调度),那么可以认为在同时进入Prepare阶段的事务是可以在备库并发执行的,因为他们互相没有冲突; LOGICAL_CLOCK是一个全局递增的64位长整型数字,主要通过它来判断哪些事务能够并发; a.分配 在二阶段提交的binlog prepare阶段进行分配    binlog_cache_mngr *const cache_mngr= thd_get_cache_mngr(thd); cache= cache_mngr->get_binlog_cache_log(all); if (cache->commit_seq_no == SEQ_UNINIT) cache->commit_seq_no= mysql_bin_log.commit_clock.get_timestamp(); }   在之前版本中binlog_prepare函数都是空函数 b.写入 LOGICAL_CLOCK只有记录到binlog中,才能为备库所用,在将每个线程cache的binlog写入时,调用函数write_commit_seq_no,每组事务的第一个事件才记录LOGICAL_CLOCK 具体的存储位置,可以阅读函数Gtid_log_event::Gtid_log_event() c.递增 MySQL的group commit有三个阶段,FLUSH_STAGE, SYNC_STAGE, 以及COMMIT_STAGE,递增LOGICAL_CLOCK发生在第二阶段结束之后,第三阶段开始之前,这时候SYNC阶段的leader还没有释放LOCK_SYNC。 7300   mysql_bin_log.commit_clock.step(); 7301   if (opt_binlog_order_commits) 7302   { 7303     if (change_stage(thd, Stage_manager::COMMIT_STAGE, 7304   这里并不是严格要求所有同时进入Prepare阶段的事务都在备库并发执行,因此一组提交的事务中可能存在不同的seq no 备库根据主库上记录的seq no来决定哪些事务是可以并行的,因此主库上并发线程数越多,复制效果越好,目前代码还处于开发阶段,在试玩时,发现打开gtid时,无法使用该特性,bug链接:http://bugs.mysql.com/bug.php?id=70536  包含具体的代码分析 更具体的可以阅读如下链接: 想知道具体的代码怎么实现的可以看看这个:http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/6256 […]