剖析复制线程

传统复制线程

复制线程图
  • master
    • Dump_thread
  • slave
    • IO_Thread
    • SQL_Thread
  • 纠结的问题
    • MySQL Replication是主库把日志推给Slave,还是Slave从主库把日志拉过来的?
    • 可以这么理解,延迟时间过长,比如用备份恢复时就是拉取,正常主从没有延迟或延迟比较低时是推
    • 主从结构的瓶颈是什么?
    • sql_thread是单线程重放,master是多线程写入,容易造成瓶颈

GTID原理

  • GTID
    • 事务唯一编号,全剧唯一(一个复制Group里)
    • 同时和事物记录到binlog中,用来标识事务
    • binlog中多一个:Gtid_log_event
  • 构成
    • UUID:sequence_number
    • sequence_number是MySQL内部的一个事务编号,一个MySQL不会重复的顺序号(保证服务器内唯一)
    • 每个MySQL有一个全局唯一的UUID:$datadir/auto.cnf中存储
    • GTID复制中出现断点,估计是使用:master_auto_position=0
  • master_auto_position=1
    • MySQL可以记录执行过的事务ID,可以通过show master status -> gtid_executed查看
    • MySQL5.6依赖于binlog和gtid_purge;MySQL5.7依赖于mysql.gtid_executed表
    • slave上记录了接收和执行的gtid,可以通过show slave status:
      • Retrieve_gtid_set
      • Execute_gtid_set
    • slave连接Master时,会把gtid_executed中的gtid发给Master,Master会Skip过executed_gtid_set,把没有执行过的GTID事务发送给slave
    • BUG:slave_net_timeout 参数设置过小,造成MySQL Master Dump thread增多,主库会认为自己多了从库,其实是频繁的从库连接又断开造成的
  • MySQL5.6从非GTID到GTID切换,需要重启
  • MySQL5.7支持在线启用GTID
    • 不用重启mysqld
    • 在启用GTID过程,可以对外提供服务
    • 不需要改变复制结构
    • 如果需要GTID,又不想太多停机时间:升级到MySQL5.7在线启用就OK
  • MySQL5.7GTID启动过程
    • gtid_mode
gitd_mode 解释
OFF 不产生GTID,Slave只接收不带GTID的事务
OFF_PERMISSIVE 不产生GTID,Slave接收不带GTID的事务也接收带GTID的事务
ON_PERMISSIVE 产生GTID,Slave接收不带GTID的事务也接收带GTID的事务
ON 产生GTID,Slave只接收带GTID的事务
  • 5.7GTID的切换流程
gitd_mode 执行对象
set global gtid_mode='OFF_PERMISSIVE'; 在Group中每个MySQL上执行
set global gtid_mode='ON_PERMISSIVE'; 在Group中每个MySQL上执行,为了安全尽量现在从库上执行
确认每个Group中binlog非GTID的执行完毕
set global gtid_mode='ON'; 在Group中每个MySQL上执行
  • MySQL5.7GTID会存储到表里
    • 支持slave不用开启binlog(log_slave_status),建议还是开启
CREATE TABLE `gtid_executed` (
  `source_uuid` char(36) NOT NULL COMMENT 'uuid of the source where the transaction was originally executed.',
  `interval_start` bigint(20) NOT NULL COMMENT 'First number of interval.',
  `interval_end` bigint(20) NOT NULL COMMENT 'Last number of interval.',
  PRIMARY KEY (`source_uuid`,`interval_start`)
  • 如何记录gtid

    • 如果开启binlog,在binlog日志文件切换时,将当前的gtid插入到gtid_executed表中
      • insert into mysql.gtid_executed(UUID,1000,2000);
    • 如果没有开启binlog,每个事务提交前,会执行一个insert操作
      • Begin
      • 事务操作
      • insert into mysql.gtid_executed(UUID,1000,2000); #隐式MySQL内部添加
      • commit
  • gtid_executed表压缩

    • 控制压缩频率
      • mysql>set global gtid_executed_compression_period=N;(N事务个数,默认是1000)


        压缩前后对比
  • enforce-gtid-consistency

    • OFF 不检测是否有GTID不知的语句/事务
    • WARN 当发现不支持语句/事务,返回警告,并在日志中记录警告信息
    • ON 当发现语句/事务不支持GTID时,返回错误
  • TIPS

    • 在线上从非GTID到GTID切换过程中,可以先设置成:WARN
  • GTID Limit

    • 不能使用 create table ... select ...
    • 事务中更新非事务表
      • begin:update no_trx_tabe set col1=xxx where xxx;update trx_tb set col1=xxx where ....;commit;
    • 事务中创建/删除临时表
      • begin:update trx_tb set xxx;create temporary table ...;commit;
    • sql_slave_skip_counter 不支持
    • 如果在传统复制到GTID复制切换时,主从卡住了,可以用start slave sql_thread试一下看能不能过去,要是过不去只能使用enforce-gtid-consistency=off先让主从能跑通
  • GTID跳过错误

    • stop slave sql_thread;
    • set gtid_next='uuid:N';
    • begin;commit;
    • set gtid_next='automatic';
    • start slave sql_thread;

半同步复制

MySQL5.7无数据丢失的半同步复制

半同步复制
  • 半同步复制里面主从会不会存在延迟?
    • 会存在延迟,半同步只能保证写入到relay log,也就是IO_thread同步的部分,sql_thread重放有可能会出现延迟
  • 在Master接收到slave的ACK应答后才Commit事务(5.6上是Master在Commit后,才等待Slave应答)
    • 因此在事务复制到slave之前,并发的事务看不到当前的事务的数据(5.6这有点问题)
    • 当Master故障时,所有已提交的事务都会复制到slave上
    • 缺省采用无数据丢失的应答等待机制,用户可以选择使用5.6的应答待机制
    • mysql>set rpl_semi_sync_master_wait_point={AFTER_SYNC|AFTER_COMMIT}

增强半同步

  • mysql>set rpl_semi_sync_master_wait_point=AFTER_SYNC;
    [图片上传失败...(image-e3c6a6-1513426634210)]

半同步

  • mysql>set rpl_semi_sync_master_wait_point=AFTER_COMMIT;


    半同步

更快的半同步复制

  • MySQL5.6


    mysql5.6半同步复制
    • mysql5.6半同步复制两个事务中间有三个流程要走,所以两个事务之间存在时间间隔
  • MySQL5.7
    • 创建单独的应答接收线程
    • 变成双工模式:发送和接收互不影响


      mysql5.7半同步复制

5.7半同步

  • Master接收到N个Slave应答后,才Commit事务
  • 用户可以设置应答的Slave数量
mysql>set global rpl_semi_sync_master_wait_for_slave_count=2;
  • 特别提示:
    • 低于5.7版本,在从库关闭一段时间后,刚启动时,注意先用异步复制,复制追上后,在用半同步复制
    • master:
      • set global rpl_semi_sync_master_enabled=ON|OFF;
    • slave:
      • set global rpl_semi_sync_slave_enabled=ON|OFF;
  • 增强半同步mysqld creash recovery
    • 扫描最后一个binlog提取其中Xid
    • 扫描InnoDB维持状态在Prepare的事务链表,和Binlog中的Xid比较,如果Binlog中存在,则提交,否则回滚事务
    • 提交到InnoDB中处于Prepare,并且写入Binlog的,就可以从崩溃中恢复事务
    • 三种场景
      • redo中有Xid,filename,position 执行Commit
      • redo中有prepare_mutex_lock,Xid
        • 在last binlog中找到对应的事务 执行Commit
        • 反之rollback
      • redo只有事务本身,没有Xid,prepare_mutex_lock 执行rollback

并行复制

并发复制

  • 在MySQL5.6的并发复制是基于库级别
  • 实质上需要:
    • 让在Master上能并发执行的事务,在Slave上也并发执行
    • 在Binlog中记录事务并发执行的相关信息
    • Slave上根据以上这些信息,让这些事务在Slave上多个线程中并发执行
  • MySQL5.7的并发复制是基于事务级别(Logical Clock)
  • 在Master上并发COMMIT事务越多,slave上并发性能越好
  • 微调参数
    • binlog_group_commit_sync_delay #group_commit等待时间,建议20微妙
    • binlog_group_commit_sync_no_delay_count #group_commit等待时间内到达多少个事务,比如这个参数是50个,当等待时间内已经有50个事务在等待,就直接提交,不在等待了,建议设置20
    • slave_preserve_commit_order=ON|OFF
      • 开启binlog
      • Logical_clock有作用

基于锁的并行复制

  • 事务能不能并发是锁来决定的.如果有锁冲突,则一个事务要等待另一个事务执行完毕
  • 如何判断并行事务没有锁冲突
    • 如果两个事务(操作)可以并行执行,这两个事务没有锁的冲突
    • 当事务开始执行Commit语句时,它已经获取了所有的锁
    • 当事务进入到prepare阶段时,它已经获取了所有的锁
  • 并发信息以逻辑的时间方式写入gtid_log_event中,共记录两个逻辑时间
    • sequence_number
      • 当事务写入binlog时,事务自己的逻辑时间,按照事务记录binlog的顺序递增
    • commit_parent
      • 当事务进行prepare阶段时,已经提交的事务的最大逻辑时间
  • 事务在Slave上执行
动作 事务 依赖关系
insert commit T1 (1,0)
update commit T2 (2,0)
delete commit T3 (3,1)
  • commit_parent之前执行的事务全部提交以后,才开始执行
  • T1和T2同事开始执行,T1 Commit后,T3开始执行

启用并行复制

  • 启用GTID!!!
mysql>stop slave sql_thread;
mysql>set global slave_parallel_workers=4|8|max_cpu_core/2;  #最多可以设成cpu核数,不过不建议,一般4个或8个就够了
mysql>set global slave_parallel_type='LOGICAL_CLOCK'; #OR DATABASE
mysql>start slave sql_thread;

  • MySQL 5.7并行复制的思想简单易懂,一言以蔽之: 一个组提交的事务都是可以并行回放 ,因为这些事务都已进入到事务的prepare阶段,则说明事务之间没有任何冲突(否则就不可能提交)。
  • DATABASE:默认值,基于库的并行复制方式
  • LOGICAL_CLOCK:基于组提交的并行复制方式
  • 最好配置binlog group commit
    • binlog_group_commit_sync_delay
    • binlog_group_commit_sync_no_delay_count

延迟复制

  • 让从库和主库保持固定时间的延迟
  • 使用场景
    • 利用延迟复制做误操作恢复
    • 利用延迟复制做统计分析环境处理
mysql>stop slave sql_thread;
mysql>change master to master_delay=N;  #N单位秒
mysql>start slave sql_thread;
  • 从库在某一个复制位置停住
    • start slave中有个参数为until可以实现这个功能
    • start slave sql_thread until master_log_file='xxx',master_log_pos=xxx;
    • 或者可以用GTID模式,{SQL_BEFORE_GTIDS|SQL_AFTER_GTIDS}=gtid_set

多源复制

  • Slave 可以同时从多个Master复制
  • 每个DB中的名字不能一样,否则有可能复制出错
    [图片上传失败...(image-6f90e6-1513426634210)]
  • 场景
    • 集中备份
    • 数据分析聚合
    • 分片数据聚合


  • 多个channels(channels包含:recevier thread ,relay logs ,applier threads)每个channel能独立的运行和停止
  • 通过P_S表进行状态监控:
  • 下列表中添加了channel_name字段,不同的Channel的信息在不同的行中显示
    • replication_applier_status_by_coordinator
    • replication_applier_status_by_worker
    • replication_connection_status

group replication

group replication
  • Group Replication的实质是:
    • 二进制日志
    • 基于Row格式+GTID
    • 一个通信框架+事务排序控制(atomic message delivery & total ordering of message)
    • 增强半同步 & 并行复制
  • Group Replication是一个趋势
  • 备份不好搞定
    • mysqldump不支持一致性备份(5.7.18后支持)
    • xtrabackup备份,造成性能损失比较严重
  • 新的节点加入过程对原有集群性能有影响

5.7复制其他方面的增强

  • 动态变更filter
    • 不需要重启MySQL
    • 支持所有的Filter选项
    • 支持各种字符集
mysql>stop slave sql_thread;
mysql>CHANGE REPLICATION FILTER REPLICATE_DO_DB= (db1,db2);
mysql>start slave sql_thread;
  • 切换主时不用停sql_tread
  • 切换master时,只需停止io_thread,不需要停止sql_thread
mysql>stop slave io_thread;
mysql>change master to master_host='master-2',...;
mysql>start slave io_thread;
  • Replication的信息添加到了Performance Schema中
    • 通过SQL进行监控
    • 逻辑上无关的信息被放在不同的表中
  • 配置信息表
    • replication_connection_configuration
    • replication_applier_configuration
  • 状态信息表
    • replication_connection_status
    • replication_applier_status
    • replication_applier_status_by_coordinator
    • replication_applier_status_by_worker
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,924评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,781评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,813评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,264评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,273评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,383评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,800评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,482评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,673评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,497评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,545评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,240评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,802评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,866评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,101评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,673评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,245评论 2 341

推荐阅读更多精彩内容