关于 WriteSet 对复制延迟的改进

一、复制延迟的现象问题

   说到复制延迟。我曾经(现在也是)眼睁睁的看着每天好几封告警邮件,有一半是来自复制延迟,却又奈何不了。估计很多 MySQL DBA也是对他恨到牙痒痒。

二、MySQL官方给出的解决方案

 2.1  5.6 --> 基于库级别的并行复制    

   MySQL中可能会有多个库,不同的库之间可能没有什么关系,所以在slave那边为每一个库分配了一个线程。以此提高复制的效率。也有可能会出现跨库的情况,当出现这种情况,也就这能等待这个事务完成

 2.2  5.7 --> 基于组提交的并行复制

   组提交的思想是:所有处于 prepare 阶段的事务同属于一个组,一个组内的事务可以并行提交。

   基于此思想,同组事务到了 slave 端就可以并行处理。

   那么在 slave 端是怎么区分是同组事务呢?

   MySQL在binlog中加入了 last_committed,sequence_number

  #180915  2:59:19 server id 883306  end_log_pos 259 CRC32 0xad68c74f     GTID    last_committed=0        sequence_number=1       rbr_only=yes
  #180915  2:59:19 server id 883306  end_log_pos 582 CRC32 0x347b8079     GTID    last_committed=1        sequence_number=2       rbr_only=yes
  #180915  2:59:19 server id 883306  end_log_pos 905 CRC32 0x9728debf     GTID    last_committed=1        sequence_number=3       rbr_only=yes
  #180915  2:59:19 server id 883306  end_log_pos 1228 CRC32 0x5a8c2d37    GTID    last_committed=1        sequence_number=4       rbr_only=yes
  #180915  2:59:19 server id 883306  end_log_pos 1551 CRC32 0x79d0f774    GTID    last_committed=1        sequence_number=5       rbr_only=yes
  #180915  2:59:19 server id 883306  end_log_pos 1874 CRC32 0xc75b96fa    GTID    last_committed=1        sequence_number=6       rbr_only=yes
  #180915  2:59:19 server id 883306  end_log_pos 2197 CRC32 0x03bbc228    GTID    last_committed=1        sequence_number=7       rbr_only=yes
  #180915  2:59:19 server id 883306  end_log_pos 2520 CRC32 0x876377ab    GTID    last_committed=1        sequence_number=8       rbr_only=yes

   last_committed 相同的属于同一个组,例如:

   last_committed = 0 中只有 1 个事务

   last_committed = 1 中有 2-8 7个事务

   假设 slave 端的 parallel 是 10,那么就可以同时执行7个事务。虽然看着挺美好,但还是有个问题。介绍这个问题的时候,首先介绍两个参数:

   binlog_group_commit_sync_delay:等待多少时间后才进行组提交,单位 (ms),最大 1000000ms == 1s

   binlog_group_commit_sync_no_delay_count:等待一组里面有多少事物我才提交

   以上两个参数,默认都是0,意思是 MySQL 不等待就进行提交。所以当系统不繁忙是,last_committed 通常只有 1 个 sequence_number。也就是一组只有一个事务。而当系统比较繁忙时,last_commttied 中有可能有多个 sequence_number。这个由 MySQL 自己决定。但是MySQL本身决定是有问题的,假如 1 秒 中有 500 个事务(这个在我们的生产系统中最高达到1000,业务高峰300-500都是常见的)。但是一组中的事物并非都是 10 个以上的,基本上都是 1、2、3 …… 参差不齐的。所以我的从库本来是有 10 个并行线程的。但是最能同时处理 1、2、3个事务,你说这让人气不气。那么不是有 binlog_group_commit_sync_no_delay_count 这个参数吗?可以控制一组有多少事务才提交,我设置为 10,那么到从库就可以 10 个事务并行处理了啊。是这样没错,但是设置这个 binlog_group_commit_sync_no_delay_count 参数之前,需要打开 binlog_group_commit_sync_delay,否则不生效。

   

   那么既然需要打开,那就打开呗!设置多少好呢?假设设置到最大 1s,1s 最大 500个事务,开50个并行,每个并行每秒处理 10 个事务,每个事物 0.1 秒,0.1 秒从库处理的过来。从库没有延迟很开心有没有,但是这种设置有没有问题,有。看一下 binlog_group_commit_sync_delay 的解释,等待多少时间后才进行组提交。这个时间,不管你 1s 内有多少个事务,统统等待 1s。也就是我一个 insert 本来 0.01 可以完成的,我非要等待 1 秒后才提交。并发高的时候没有影响,并发低的时候问题就来了。非要阻塞 1s 才提交。还会有什么其他影响吗?有,没有提交是不是就持有锁,那么锁没释放,其他会话是不是就需要等待。所以,我曾经没有好好理解 等待多少时间后才进行组提交 这句话,导致了生产事故。具体看我写的另一篇博客:https://www.cnblogs.com/ziroro/p/9600359.html  

 2.3  5.7.22以上 --> 基于写集合的并行复制

   一不小心说了大多血泪史,回归正题。writeset的思想是:不同事物修改了不同行的数据,那么可以视为同一组。MySQL 会对这个提交的事务中的一行记录做一个 HASH值,这些 HASH 值称为 writeset。writeset会存入一张 HASH 表。其他事务提交时会检查这张 HASH 表中是否有相同的记录,如果不相同,则视为同组,如果有相同,则视为不同组。怎么判断是否同组,依然采用了last_committed,sequence_number。具体看实验:

  2.3.1 binlog_transaction_dependency_tracking 设置为 writeset   

  set global binlog_transaction_dependency_tracking = WRITESET

  2.3.2 插入不相同的数据

  insert into t1 select 1,‘a‘;
  insert into t1 select 2,‘b‘;

  2.3.3 解析binlog

  mysqlbinlog --base64-output=decode-rows -vv /data/mysql/mysql_3306/logs/bin.000004 > 4.sql

  内容如下

  ### INSERT INTO `vcyber`.`t1`
  ### SET
  ###   @1=1 /* INT meta=0 nullable=0 is_null=0 */
  ###   @2=‘a‘ /* VARSTRING(40) meta=40 nullable=1 is_null=0 */  …………
  #180915  6:19:32 server id 883306  end_log_pos 572 CRC32 0x88c31fe8     GTID    last_committed=1        sequence_number=2       rbr_only=yes
  …………
  ### INSERT INTO `vcyber`.`t1`
  ### SET
  ###   @1=2 /* INT meta=0 nullable=0 is_null=0 */
  ###   @2=‘b‘ /* VARSTRING(40) meta=40 nullable=1 is_null=0 */  …………
  #180915  6:19:35 server id 883306  end_log_pos 885 CRC32 0x6901dc68     GTID    last_committed=1        sequence_number=3       rbr_only=yes

   可以看到修改了不相同的数据,last_committed 都是相同的。为了比较不同,把 binlog_transaction_dependency_tracking 修改回 COMMIT_ORDER   

  2.3.4 binlog_transaction_dependency_tracking 设置为 COMMIT_ORDER

  set global binlog_transaction_dependency_tracking = COMMIT_ORDER

  2.3.5 插入不相同的数据

  insert into t1 select 11,‘aa‘;
  insert into t1 select 12,‘bb‘;

  2.3.6 解析binlog

  ### INSERT INTO `vcyber`.`t1`
  ### SET
  ###   @1=11 /* INT meta=0 nullable=0 is_null=0 */
  ###   @2=‘aa‘ /* VARSTRING(40) meta=40 nullable=1 is_null=0 */
  …………
  #180915  6:30:30 server id 883306  end_log_pos 575 CRC32 0x24a2ace1     GTID    last_committed=1        sequence_number=2       rbr_only=yes
  …………
  ### INSERT INTO `vcyber`.`t1`
  ### SET
  ###   @1=15 /* INT meta=0 nullable=0 is_null=0 */
  ###   @2=‘ee‘ /* VARSTRING(40) meta=40 nullable=1 is_null=0 */
  …………
  #180915  6:30:34 server id 883306  end_log_pos 891 CRC32 0xe3bb6418     GTID    last_committed=2        sequence_number=3       rbr_only=yes

   两个事物的 last_committed 不相同,到从库是没有办法并行复制的。

   那么 writeset 最多可以并行执行多少个事务呢?假设插入 30000 条不同记录,统计下 last_committed 有多少个,就可以证明可以并行执行多少个事务,为了少啰嗦一点,我就直接贴出我的结果

   12500 last_committed=1
   12501 last_committed=12501
    4997 last_committed=25002

   看来好像最多可以并发执行 12500 事务。12500 这个数字接近 binlog_transaction_dependency_history_size 这个参数的一半

   binlog_transaction_dependency_history_size:哈希表可以存储的最大大小

   为了证明猜想,将 binlog_transaction_dependency_history_size 设置为 50000 又会怎么样

   25000 last_committed=1
   25001 last_committed=25001
    9997 last_committed=50002

  看起来好像确实接近于 binlog_transaction_dependency_history_size 的一半。

原文地址:https://www.cnblogs.com/ziroro/p/9651792.html

时间: 2024-08-01 00:19:43

关于 WriteSet 对复制延迟的改进的相关文章

seconds_behind_master监控复制延迟的不足及pt-heartbeat改进方法

seconds_behind_master含义及不足 seconds_behind_master的值是通过将salve服务器当前的时间戳与二进制日志中的事件的时间戳相比得到的,所以只有执行事件时才会报告延迟. 1.1  如果备库复制线程没有运行,就会报延迟为null. 1.2  一些错误比如网络不稳定可能导致复制中断或停止复制线程,但是seconds_behind_master将显示为0,而不是显示错误 1.3  即使备库线程正在运行,备库有时候可能无法计算延时,如果发生这种情况,备库会报0或者

mysql复制延迟监控脚本

#!/bin/sh #[email protected] #repdelay.sh #查看复制延迟具体多少event #####1.juede the rep slave status export black='\033[0m' export boldblack='\033[1;0m' export red='\033[31m' export boldred='\033[1;31m' export green='\033[32m' export boldgreen='\033[1;32m' e

实战:mysql 5.6复制延迟监控

#repdelay.sh #!/bin/sh #[email protected] #查看复制延迟具体多少event #set mysql evn MYSQL_USER_MASTER=root MYSQL_PASS_MASTER='password' MYSQL_HOST_MASTER=192.168.2.188 MYSQL_USER_SLAVE=root MYSQL_PASS_SLAVE='password' MYSQL_HOST_SLAVE=192.168.2.14 tmpfile_01="

MariaDB 10之并行复制--延迟测试结果

测试参数: sysbench  --test=/root/sysbench0.5/sysbench/tests/db/insert.lua  --mysql-table-engine=innodb --oltp-table-size=1000000  --max-requests=0 --max-time=300 --num-threads=16  --oltp-tables-count=10 --report-interval=10  --mysql-host=10.8.8.100 --mys

MySQL 5.7并发复制和mysqldump相互阻塞引起的复制延迟

本来MySQL BINLOG和SHOW PROCESSLIST命令属于八竿子打不着的两个事务,但在最近故障排查中,发现主库和从库已经存在很严重的复制延迟,但从库上显示slave_behind_master值为0,复制SQL线程与备份线程之间相互阻塞,但未报死锁. 在从库上执行SHOW PROCESSLIST发现复制的SQL线程等待锁,而等待SQL的WHERE条件竟然是类似于WHERE C1='ABC' AND C2>'2018-03-01' AND C2<'2018-03-26' 这种个范围查

谈谈MySQL的WriteSet并行复制

[历史背景] 岁月更迭中我已经从事MySQL-DBA这个工作三个年头,见证MySQL从"基本可用","边缘系统可以用MySQL","哦操!你怎么不用MySQL"; 正所谓!"一个数据库的境遇既取决于历史的进程,取决于它的自我奋斗!",关于"历史的进程"在此不表,关于"自我奋斗"这里也只想谈一下 并行复制的几个关键时间结点 总的来说MySQL关于并行复制到目前为止经历过三个比较关键的时间结

MySQL 5.7复制延迟之sync_relay_log

一.描述MySQL 5.7版本主从复制,批量时候显示延迟上万秒. 二.现象 1.io使用率高 #iostat -dxm 1 1000 Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await svctm %util scd0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 vda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0

logical_clock 并发复制mysql5.7解决复制延迟问题

slave-parallel-type=LOGICAL_CLOCK ##默认database ,logical_clock可能还存在bug,5.7.19修复主从不一致bug * Replication: In certain cases, the master could write to the binary log a last_committed value which was smaller than it should have been. This could cause the s

Mysql复制-Slave库设置复制延迟

mysql> stop slave; mysql> change master to master_delay=10;#单位是秒 mysql> start slave; mysql> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event ... SQL_Delay: 10 S