ITPub博客

首页 > 数据库 > MySQL > mysql多线程slave的演化

mysql多线程slave的演化

原创 MySQL 作者:myownstars 时间:2015-02-08 09:59:51 0 删除 编辑
淘宝内部分享:怎么跳出MySQL的10个大坑  之  MySQL · 优化改进· 复制性能改进过程

pre-5.6 ,sql_thread的执行堆栈如下,
sql_thread:
exec_relay_log_event
    apply_event_and_update_pos
         apply_event
             rows_log_event::apply_event
                 storage_engine operation
         update_pos
由于其是单线程, 经常会造成备库延迟;
      mysql-transfer

先看一下oracle是怎么实现logical standby的

其中只有preparer/applier进程可以有多个
  • reader:读取redo记录传递给preparer进程
  • preparer: 根据redo记录和数据字典信息生成LCR
  • builder: 将同一个事务的LCR打包。对于大事务(eager transaction),可能被打成多个事务包(transaction chunk),那么可能有些包里是不包含commit的,每一个事务包都可能交给不同的applier进程。
  • analyzer:分析事务包之间的依赖关系
  • coordinator:将分析好的事务包交给applier进程
  • applier:将事务包应用,如果事务包依赖其他事务包,则需要等待相应的事务包完成。事务能否commit,可能还需要根据不同的情况从coordinator获得相应的信息。



5.6并行复制
 5.6 中,引入了多线程模式,在保留io_thread的前提下,将sql_thread改造为coordinator,并新增多个worker_thread即MTS
  Relay Log File
        -------
        | W01 |                   ---> Worker 01 (W01)
        -------
        | W01 |   ---> SQL THREAD ---> Worker 02 (W02)
        -------
        | W02 |                   ---> Worker 03 (W03)
        -------
        | ... |
coordinator_thread: 负责读取 relay log,将读取的binlog event以事务为单位分发到各个 worker thread 进行执行,并在必要时以串行方式执行binlog event(Description_format_log_event, Rotate_log_event )。
worker_thread: 执行分配到的binlog event,各个线程之间互不影响;
参数slave_parallel_workers用于设置MTS数量;

实现原理
在内存中构造一个hash表,维护数据库和worker_thread的映射关系;
多个数据库可并行执行,同一个数据库则只能串行执行;如果事务是跨数据库行为的,则需要等待已分配的该数据库的事务全部执行完毕,才会继续分发,其分配行为的伪码可以简单的描述如下:
get_slave_worker
  if (contains_partition_info(log_event))
     db_name= get_db_name(log_event);
     entry {db_name, worker_thread, usage} = map_db_to_worker(db_name);
     while (entry->usage > 0)
        wait();
    return worker;
  else if (last_assigned_worker)
    return last_assigned_worker;
  else
    push into buffer_array and deliver them until come across a event that have partition info

需要注意的细节
内存的分配与释放,relay thread 每读取一个log_event, 则需要 malloc 一定的内存,在work线程执行完后,则需要free掉;
临时表的处理,临时表是和entry绑定在一起的,在执行的时候将entry的临时表挂在执行线程thd下面,但没有固化,如果在临时表操作期间,备库crash,则重启后备库会有错误;
维护一个绑定信息的array , 在分发事务的时候,更新绑定信息,增加相应 entry->usage, 在执行完一个事务的时候,则需要减少相应的entry->usage;
slave worker 信息的维护,即每个 worker thread执行了哪些事务,执行到的位点是在哪,延迟是如何计算的,如果执行出错,mts_recovery_group 又是如何恢复的;
总体上说,5.6 的并行复制打破了5.5 单线程的复制的行为,只是在单库下用处不大,并且5.6的并行复制的改动引入了一些重量级的bug
MySQL slave sql thread memory leak (http://bugs.MySQL.com/bug.php?id=71197)
Relay log without xid_log_event may case parallel replication hang (http://bugs.MySQL.com/bug.php?id=72794)
Transaction lost when relay_log_info_repository=FILE and crashed (http://bugs.MySQL.com/bug.php?id=73482)



5.7
并行复制的实现添加了另外一种并行的方式,即主库在 ordered_commit中的第二阶段的时候,将同一批commit的 binlog 打上一个相同的seqno标签,同一时间戳的事务在备库是可以同时执行的(因为这些事务相互不干涉,所以才能在primary并发commit,因此在备库同样也能并发执行),因此大大简化了并行复制的逻辑,并打破了相同 DB 不能并行执行的限制。备库在执行时,具有同一seqno的事务在备库可以并行的执行,互不干扰,也不需要绑定信息,后一批seqno的事务需要等待前一批相同seqno的事务执行完后才可以执行。

5.7实现了MTS下的SLAVE_TRANSACTION_RETRIES 
1 当某个worker thread执行事务遭遇错误,则根据参数定义再次执行; 
2 单个worker thread重试期间不影响其他wokrer thread; 
3 若尝试SLAVE_TRANSACTION_RETRIES仍然失败,则worker stop,进而通知其他worker和coordinator stop,slave停止更新; 
coordinator照旧将event包装成Slave_job_item形式转发,但是多加入event的起始位置信息(binlog name + offset); 
worker执行事务组时记录第一个event的起始位置,当执行出错时,事务组的event可分为3类: 
1 已经执行成功的 
2 引发错误的 
3 尚未执行的(仍在job queue中) 
worker无需从relay log读取整个事务组,只需part 1和part 2部分; 
注: relay thread 每读取一个log_event, 则需要 malloc 一定的内存,在work线程执行完后,则需要free掉;因此需要重新读取; 

typedef struct slave_job_item 

void *data; 
+ uint relay_number; 
+ my_off_t relay_pos; 
} Slave_job_item; 
http://dev.mysql.com/worklog/task/?id=6964 



mysql-transfer
这是淘宝自主开发的一个基于MySQL+patch后得到的主从同步工具。
其主要目的是为了解决原生版本的主从同步里,从库是单线程apply主库的binlog,导致的延迟。

 

说明:左上角是Master, 右上角是Transfer,下面是Slave。
1、             由于Transfer是在MySQL基础上打的patch,因此支持几乎所有MySQL的监控命令,你原来加在Slave上的监控,可以直接改到Transfer上。
2、             一般我们将Transfer和Slave放在同一个机器上(等于是装两个MySQL,一个是Transfer,一个是真正的slave)
3、             Transfer按照表名hash将不同表的更新分配到不同的线程,因此在多表环境下才能看得到性能提升
4、             Master的binlog格式必须设置成row
5、             若需要用到多个Master,给每个Master命令一个channel,命令 序列为 change master channel1 to master_log_file=xxx…… ; start slave channel1; 可以单独对一个chanel执行start\stop等命令
6、             若只需要一个master,则语法格式不变

 transfer 2.0

 Transfer第一版本存在两个可改进的点:单表并发和事务支持。
a)      Transfer2.0支持单表并发,基本原理就是按照更新行的主键id (因此有一个限制是同步的表必须要有主键)。
b)      Transfer2.0支持slave回放主库事务时以事务为单位执行。

 Transfer的推荐配置结构是
      Master  ==> Transfer ==> Slave
也可以将transfer直接patch到slave上,这样就不必为tranfer单独创建一个实例;
patch地址
http://mysql.taobao.org/images/b/b3/Transfer_mysql.diff


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/15480802/viewspace-1430099/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2010-03-18

  • 博文量
    375
  • 访问量
    3095422