参考文档:https://www.jianshu.com/p/634c661227d4

复制

Mysql内建了复制功能,我们平时的使用也是利用了复制功能支持的水平扩展架构。会计、报账、台账系统都使用了一主多从的水平架构来进行数据库间的同步。
复制功能除了引入从库,减轻主库的读取压力(虽然这也是很重要的功能)之外,也是灾备、高可用的基础。

解决的问题

复制功能解决的本质问题,是保证不同的服务器之间的数据保持一致。

  • 负载均衡

其所衍生的第一种应用就是一主多从架构,实现负载均衡。组内目前使用一主多从架构,主库数据同步给多台从库。在主从同步中,我们将节点的角色划分为master和slave,slave对外提供读操作,而master负责写操作,形成一个读写分离的架构,从而承载更多的业务请求,如下图所示。
image.png
这里是不是很像Redis的主从同步,与其类似,Mysql的复制也是其负载均衡的基石。

  • 故障切换

目前互联网公司都有多个机房,在意外情况下可能出现某个机房的部分服务器宕机导致服务不可用,而复制则可以避免Mysql的单点故障导致全局服务不可用,即使出现单点故障也可以利用其他备份数据库保证服务正常运行,通过复制功能可以减小服务不可用的时间或概率。

  • 不停服升级

该应用场景较为普遍,在需要服务升级时,可以选择高版本新服务器作为从服务器,使用innobackupex在不停止旧mysql服务的情况下备份数据到从数据库,迁移结束后将该新数据库提升为主库(通过修改域名解析规则或者直接修改远程连接),最终实现不停服升级。

复制的原理

mysql中的复制的基础是mysql的二进制文件binlog,所以在了解复制的原理之前需要首先了解binlog

binlog

binlog在 MySQL 3.23.14 中引入,其会记录所有数据库表结构变更以及表数据修改的二进制日志,也就是说不会记录SELECT、SHOW这类操作,但是包含可能对其进行更新的语句(例如,即使无法匹配到任何行的DELETE语句)。语句以描述修改的“事件”的形式存储,二进制日志还包含有关每个语句更新数据所执行的时间。

binlog文件结构

binlog日志由一组二进制日志文件和一个索引文件组成。
image.png
索引文件如下图所示:主要负责记录所有的binlog文件
image.png
每个日志文件包含一个 4 字节的魔法字节,后跟一组描述数据修改的事件:
魔法字节: 0xfe 0x62 0x69 0x6e = 0xfe ‘b’’i’’n’
事件:

  1. 35 37 8F 5C // 事件创建的时间, 秒, 0x5C8F3735, 即2019/3/18 14:14:13
  2. 0F // event type, 15表示binlog描述事件
  3. 01 00 00 00 // server id, 01
  4. 78 00 00 00 // event size, 事件大小, 120字节. 包括header, post-header, body
  5. 7C 00 00 00 // 下一个事件的位置,
  6. 01 00 // flag, 即0x0001. LOG_EVENT_BINLOG_IN_USE_F,
  7. // 如果当前文件正在被mysql使用, 则置成1, 否则, 置为0
  8. 04 00 // binlog-version, 0x0004,
  9. 38 2E 30 2E 31 35 00 // mysql-server版本, 50个字节, 本处为字符串"8.0.15"
  10. 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  11. 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  12. 00 00 00 00 00 00 00 00 00 00 00
  13. 35 37 8F 5C // binlog创建时间
  14. 13 // Binlog Event Header的消息头大小, 固定值19
  15. 00 0D 00 08 00 00 00 00 04 00 04 00 00 00 60 00 // 以下三行是为各种类型的Header所对应的长度大小
  16. 04 1A 08 00 00 00 08 08 08 02 00 00 00 0A 0A 0A // 源代码中有40种type定义
  17. 2A 2A 00 12 34 00 0A
  18. 01 F7 B8 86 9B // 这一段不知道是什么东西, 可能是检验和之类的东西
  19. 35 37 8F 5C // 时间
  20. 23 //事件类型35, 表示PREVIOUS_GTIDS_LOG_EVENT
  21. 01 00 00 00
  22. 47 00 00 00 // 事件长度71字节
  23. C3 00 00 00 // 下一个事件的位置
  24. 80 00 // flag
  25. 01 00 00 00 00 00 00 00 6F 16 6D 02 44 84 11 E9
  26. 8A 8E 00 16 3E 10 05 86 01 00 00 00 00 00 00 00
  27. 01 00 00 00 00 00 00 00 09 00 00 00 00 00 00 00 BA
  28. 09 A9 48
  29. AA 37 8F 5C // 时间
  30. 21 //事件类型33, 表示GTID_LOG_EVENT
  31. 01 00 00 00
  32. 4F 00 00 00
  33. 12 01 00 00
  34. 00 00
  35. 00 6F 16 6D 02 44 84 11 E9 8A
  36. 8E 00 16 3E 10 05 86 09 00 00 00 00 00 00 00 02
  37. 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
  38. 15 07 24 53 58 84 05 FC 11 01 8F 38 01 00 20 9E
  39. 37 7F
  40. AA 37 8F 5C
  41. 02 //QUERY_EVENT
  42. 01 00 00 00
  43. 4B 00 00 00
  44. 5D 01 00 00
  45. 08 00
  46. 0B 00 00 00 // slave_proxy_id
  47. 00 00 00 00 // execution time
  48. 04 // schema length
  49. 00 00 // error-code
  50. 1D 00 //status-vars length, 29,
  51. 00 00 00 00 00 01 20 00 A0 45 00 00 00 00
  52. 06 03 73 74 64 04 FF 00 FF 00 FF 00 12 FF 00
  53. 74 65 73 74 00 //schema, "test"
  54. 42 45 47 49 4E 4B 0E 6C
  55. A5
  56. AA 37 8F 5C
  57. 13 //TABLE_MAP_EVENT, 官网上没写. 不知道这该如何定义
  58. 01 00 00 00
  59. 30 00 00 00
  60. 8D 01 00 00
  61. 00 00
  62. 45 00 00 00 00 00 01 00 04 74 65 73 74 00 02 74
  63. 31 00 01 03 00 01 01 01 00 DD 9F 06 84 AA 37 8F
  64. 5C 1E 01 00 00 00 28 00 00 00 B5 01 00 00 00 00
  65. 45 00 00 00 00 00 01 00 02 00 01 FF 00 09 00 00
  66. 00 A0 D7 5B 35
  67. AA 37 8F 5C
  68. 10 // XID_EVENT
  69. 01 00 00 00
  70. 1F 00 00 00
  71. D4 01 00 00
  72. 00 00
  73. 17 00 00 00 00 00 00 00
  74. 7F 0D 0C AF

每个事件包含头字节和数据字节:

  • 标头字节提供有关事件类型、事件生成时间、服务器等的信息。
  • 数据字节提供特定于事件类型的信息,例如特定的数据修改。

查看具体的binlog目录可以通过 show variables like ‘%log_bin%’ show binary logs查看
image.pngimage.png
event 查询的数据行关键字:

  • Pos:当前事件的开始位置,每个事件都占用固定的字节大小,结束位置(End_log_position)减去Pos,就是这个事件占用的字节数。上面的日志中我们能看到,第一个事件位置并不是从 0 开始,而是从 4。MySQL 通过文件中的前 4 个字节,来判断这是不是一个 Binlog 文件。这种方式很常见,很多格式的文件,如 pdf、doc、jpg等,都会通常前几个特定字符判断是否是合法文件。
  • Event_type:表示事件的类型,具体分类参考https://dev.mysql.com/doc/internals/en/binlog-event-type.html
  • Server_id:表示产生这个事件的 MySQL server_id,通过设置 my.cnf 中的 server-id 选项进行配置
  • End_log_position:下一个事件的开始位置
  • Info:包含事件的具体信息

image.png
BinLog除了记录修改数据的操作,还会记录元信息:

  • 确保操作重放正确性的额外信息
  • Error Code
  • binlog自身的维护信息,比如rotate事件。

除了Redo、undo、binlog这些用于事务日志;MySQL中还有一些操作日志:Errorlog、General Query Log、Slow Query Log、DDL Log,暂不讨论。

binlog的作用

Binlog 的主要作用有两个:

  1. 数据恢复因为 Binlog 详细记录了所有修改数据的 SQL,当某一时刻的数据误操作而导致出问题,或者数据库宕机数据丢失,那么可以根据 Binlog 来回放历史数据。
  2. 主从复制想要做多机备份的业务,可以去监听当前写库的 Binlog 日志,同步写库的所有更改。

Binlog中以事务为单位存储了event,在执行事务的过程中,event数据暂时存放在IO_CACHE中,大小为binlog_cache_size;当超过binlog_cache_size后,转存在临时文件中;
当SQL层启用binlog时,为了保证上下日志的一致,需要采用XA 2pc(之后雨亮他们讲事务的时候再说,prepare和commit)进行两阶段提交,这里binlog就作为2pc中的协调者么,在多个事务并发的进行2PC提交的时候,redolog的写入顺序和binlog的写入顺序可能不一致;为了保证binlog和引擎日志的提交顺序一致,通过在MySQL中的2PC步骤中加锁prepare_commit_mutex确保。
针对不同的使用场景,Binlog 提供了三种模式来提供不同详细程度的日志内容。

  • Statement 模式:基于 SQL 语句的复制(statement-based replication-SBR)
  • Row 模式:基于行的复制(row-based replication-RBR)
  • Mixed 模式:混合模式复制(mixed-based replication-MBR)

mysql的复制也相应分为三种模式。

relay-log

中继日志与二进制日志一样,由一组包含描述数据库更改事件的编号文件和一个包含所有使用的中继日志文件名称的索引文件组成。
image.png
上图中多出了两个文件:master.info、relay-log.info
master.info记录了上一次读取到master同步过来的binlog的位置,以及连接master和启动复制必须的所有信息。
relay-log.info记录了文件复制的进度,下一个事件从什么位置开始,由sql执行线程负责更新。

何时创建

每次复制 I/O 线程启动时。
刷新日志时(例如,使用 FLUSH LOGS)。
当前中继日志文件的大小变得过大时(max_relay_log_size为0则取binlog日志的size)。

relay-log作用

基于语句的复制

在5.0版本之前,只支持基于语句的复制,复制的原理可以概括为:从库把所有主库执行过的会引起数据变动的SQL语句重新执行一遍。
这种模式的问题在于 MySQL 数据库的服务器本地环境可能不一样,如果存在本地依赖的函数,或者涉及到上下文相关的处理,同样的语句在不同的机器上执行出来的效果可能不一致。

基于行的复制

它与基于语句模式的区别在于它不保存具体的 SQL 语句,而是记录具体被修改的信息。
比如一条 update 语句更新10条数据,如果是 Statement 模式那就保存一条 SQL 就够,但是 Row 模式会保存每一行分别更新了什么,有10条数据。
Row 模式的优缺点就很明显了。保存每一个更改的详细信息必然会带来存储空间的快速膨胀,换来的是事件操作的详细记录。所以要求越高代价越高。
对于 ROW 格式的 Binlog,所有的 DML 语句都是记录在 ROWS_EVENT (参考binlog文件结构中的事件类型)。
ROWS_EVENT分为三种:

  • WRITE_ROWS_EVENT
  • UPDATE_ROWS_EVENT
  • DELETE_ROWS_EVENT

分别对应 insert,update 和 delete 操作。
对于 insert 操作,WRITE_ROWS_EVENT 包含了要插入的数据。
对于 update 操作,UPDATE_ROWS_EVENT 不仅包含了修改后的数据,还包含了修改前的值。
对于 delete 操作,仅仅需要指定删除的主键(在没有主键的情况下,会给定所有列)。
以上两种模式的一种应用场景(个人理解)
基于行的场景,适用于扫描范围大但是影响数据少的情况,比如
insert into tableA (c1,c2,c3)
select c1,c2,c3 from tableB groupby c1 order by c2 asc;
以上语句实际进行了多遍扫描,但是最终只产生了几条数据,如果使用基于语句的模式会导致备库中重新走一遍扫描过程降低复制效率。
基于语句的场景,语句简单但是影响数据大的情况,比如
update tableA set c1 =0
如果上述语句按照行模式复制,会导致全表数据都需要被记录,该模式将会低于基于语句的模式。

混合模式

混合模式就是以上两种模式的混用,从 V5.1.8 开始引入 Mixed 模式,V5.7.7 之前的版本默认是基于语句的模式,之后默认使用Row模式, 但是在 8.0 以上版本已经默认使用 Mixed 模式了。
我的5.8默认使用了Row模式:
show global variables like ‘%binlog_format%’;
image.png

主备通信

MySQL 复制功能使用三个主线程实现,一个在主库上,两个在备库上:
Binary log dump thread
当备库连接时,主库创建一个日志线程将二进制日志内容发送到备库。该线程可以SHOW PROCESSLIST在主库上的输出中标识为Binlog Dump线程。二进制日志转储线程获取源二进制日志的锁,用于读取要发送到副本的每个事件。在从库读取bin-log中的操作时,此线程会对主库上的bin-log加锁,当读取完成。
Replication I/O thread
从库Start slave生效后,会创建一个 I/O 线程,该线程连接到主库并接收其发送的记录在其二进制日志中的更新,I/O线程接收到主节点binlog dump 进程发来的更新之后,保存在本地relay-log中。
Replication SQL thread
SQL线程负责读取relay log中的内容,解析成具体的操作并执行,最终保证主从数据的一致性。

复制方式

异步复制

异步复制中,主库将事务 Binlog 事件写入到 Binlog 文件中,此时主库只会通知一下 Dump (Binary log dump thread)线程发送这些新的 Binlog,然后主库就会继续处理提交操作,无法保证这些 Binlog 已经被从库节点接收。
异步复制流程图
image.png

同步复制

异步复制不关注从库是否完成了sql重做,同步复制与之相反,主库在接收到从库重新提交了binlog中的事务之后才会继续执行后续操作。
同步复制流程图
image.png
同步复制中因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。

半同步复制

MySQL 复制默认是异步的。对于异步复制,如果主库崩溃,它提交的事务可能不会传输到任何备库。在这种情况下,从库就可能丢失这个事务,从而造成主从不一致。但是全同步复制又是一个比较重的模式。为了均衡效率与准确性,Mysql5.5引入了半同步复制机制(google贡献的布丁)。
MySQL5.5由Google贡献的补丁才开始支持半同步复制模式,该模式可以确保从服务器接收完主服务器发送的binlog日志文件并写入自己的中继日志(relay log)里,然后会给主服务器一个反馈,告诉对方已经接收到完毕,这时主库线程才返回当前session告知操作完成,当出现超时情况时,源主服务器会暂时切换到异步复制模式,直到至少有一台设置为半同步复制模式的从服务器及时收到信息为止。 一主多从模式下,有一个从节点返回成功,即成功,不必等待多个节点全部返回。
如果主库在某个过程中宕机,事务没能提交成功,那么从库也将不会收到事务对应的binlog。
半同步复制流程图
image.png
除首次是由主库推送更新以,之后的复制均为slave根据offset主动拉取binlog中的事件。

多线程复制

从上述的复制流程中可以发现,从库的IO线程和SQL线程都是单线程的,不过从库的两个线程是独立的。如果SQL线程应用relay-log中更改的速度较慢,并不会影响IO线程,同样的,如果IO线程一次性从主库读取了所有的binlog,也不能提高SQL线程较慢的执行速度。

复制的过程

压测数据

测试环境(单机)

处理器:2.6 GHz 六核Intel Core i7
内存:16 GB 2667 MHz DDR4
测试脚本:oltp_read_write.lua
测试工具:sysbench
测试表:10张表
测试线程数:5/10
实例数:2
3307 主库 3306 从库
image.png
sysbench工具简介
sysbench是跨平台的基准测试工具,支持多线程,支持多种数据库;主要包括以下几种测试:

  • cpu性能
  • 磁盘io性能
  • 调度程序性能
  • 内存分配及传输速度
  • POSIX线程性能
  • 数据库性能(OLTP基准测试)

数据处理大致可以分成两大类:联机事务处理OLTP(on-line transaction processing)、联机分析处理OLAP(On-Line Analytical Processing)。OLTP是传统的关系型数据库的主要应用,主要是基本的、日常的事务处理,例如银行交易。OLAP是数据仓库系统的主要应用,支持复杂的分析操作,侧重决策支持,并且提供直观易懂的查询结果。

异步复制

测试结果
写入+读取混合场景
image.pngimage.png
写入场景
image.png
image.png
读取场景
image.png
image.png

半同步复制

建立半同步复制
主库
1.安装本同步插件
install plugin rpl_semi_sync_master soname ‘semisync_master.so’;
2.检查半同步复制启用状态
show variables like ‘rpl%’;
image.png
3.开启半同步复制
set persist rpl_semi_sync_master_enabled=on;
4.确认半同步复制开启状态
show global status like ‘rpl%’;
image.png
从库1.安装本同步插件
install plugin rpl_semi_sync_slave soname ‘semisync_slave.so’;
2.检查半同步复制启用状态
show variables like ‘rpl%’;
image.png
3.开启半同步复制
set persist rpl_semi_sync_slave_enabled=on;
4.重启从库IO线程
stop slave io_thread;
start slave io_thread;
5.确认半同步复制开启状态
show global status like ‘rpl%’;
image.png
测试结果
混合模式
image.png
插入模式
image.png
读取模式**
image.png

总体结果统计

5线程混合qps 10线程混合qps 5线程混合tps 10线程混合tps 5线程insert qps 10线程insert qps 5线程read qps 10线程read qps
半同步复制 18122.59 25782.62 906.13 1289.13 7507.07 12314.11 36694 50012
异步复制 20788.48 26651.73 1039.42 1332.59 4723 7629 33384 47298
同比 -13% -4% -13% 3.3% -59% -61.7% -10% -6%

总结

硬件条件限制,无法模拟多库复制的情况,因为时间原因没能找到记录主从延迟的工具(=。=)。
在读取场景上,两者性能接近。
在写入场景上,半同步复制需要等待一个从库3306的relay-log写入ack信号才可继续提交,因此qps相比于异步复制性能下降较多,本机测试的情况下,由于系统访问localhost并不需要通过网卡,通信延迟远低于正常多主机情况下的网络延迟,因此实际情况下的半同步复制写入性能将会更差。
在混合场景上,读写混合的情况下,两者差异不大(因为读多写少)。

主从延迟

Seconds_Behind_Master=丛库的当前时间- 主库执行binlog事件的时间-主从库之间的时间差(clock_diff_with_master,rpl_mi.h中定义了clock_diff_with_master,该值为从库相对于主库的时间差)。

出现原因

  1. 在日常应用中,负责写入的主库一般是并发跑多个线程同时提交事务,提交的事务按照逻辑的时间(数据库LSN号,日志的逻辑序列号(log sequence number))顺序地写入binlog,但是slave节点只有SQL单线程来执行relay log中的主库事务,造成主从延迟。
  2. 下图简单罗列了基于Gtid主从同步的过程,Master在binlogcommit的时候产生gtid,记为GTID_LOG_EVENT;Slave按照事务为单位进行恢复,每次读取GTID,按照该GTID执行事务;这样保证整个复制集群的GTID的一致性。但是last_master_timestamp的更新是在从库事务执行结束后,如果出现一个很大的事务,主从延迟就会变大。比如insert ….. select …..。
  3. 从库的机器性能比主库要差,在业务高峰,从库apply relay log的过程会跟不上主库生产binlog的速率。
  4. 从库的压力大,出于对主库的敬畏之心,从库负责大量的读取操作,

    导致的问题

  • 读取到老数据、插入失败

解决方案

官方解决方案(本部分内容可以转移到上面复制的章节):

  • 并行复制(5.6)从库的relay log记录的是主库的binlog,日志记录的信息按照事务的时间先后顺序记录,为了保证主备数据一致性,从库必须按照同样的顺序执行,如果顺序不一致容易造成主备库数据不一致的风险。解决方案:MySQL 5.6版本引入schema级别的并发复制,其核心思想:“不同schema下的表并发提交时的数据不会相互影响,即slave节点可以用对relay log中不同的schema各分配一个类似SQL功能的线程,来重放relay log中主库已经提交的事务,保持数据与主库一致”。该版本的并发复制,简单来说就是一个schema分配一个类似SQL线程的功能。配置方式如下:https://dev.mysql.com/doc/refman/5.6/en/replication-implementation-details.html。解决方案存在的问题:MySQL 5.6基于schema级别的并发复制能够解决当业务数据的表放在不同的database(也就是scheme)下,但是实际生产中往往大多数或者全部的业务数据表都放在同一个schema下,在这种场景即使slave_parallel_workers>0设置也无法并发执行relay log中记录的事件。 高并发的情况下,由于slave无法并发执行同个schema下的业务数据表,依然会造成主从延迟的情况。
  • redo log 组提交(5.7)如果同一个schema中的relay log可以兵法执行,实际生产过程中必然可以大大提高复制效率,但是需要判断,哪些事件是可以并发执行且不影响主从一致性的。在介绍组提交之前,需要首先了解一下WAL,WAL指的是对数据文件进行修改前,必须将修改先记录日志。MySQL为了保证ACID中的一致性和持久性,使用了WAL。参见上一节的redo log。解决方案:MySQL 5.7 引入Enhanced Muti-threaded slaves,当从库配置slave_parallel_workers>0并且global.slave_parallel_type=‘LOGICAL_CLOCK’,可支持一个schema下,slave_parallel_workers个的worker线程并发执行relay log中主库提交的事务。Redo log的刷盘操作将会是最终影响MySQL TPS的瓶颈所在。为了缓解这一问题,MySQL使用了组提交,将多个刷盘操作合并成一个,如果说10个事务依次排队刷盘的时间成本是10,那么将这10个事务一次性一起刷盘的时间成本则近似于1。但是要实现以上功能,需要在master机器标记binary log中的提交的事务哪些是可以并发执行,由于在MySQL中写入是基于两阶段锁的并发控制,并且我们知道锁的释放是在XA-engine-commit阶段(InnoDB);那么,在Master端同时处于prepare阶段且未提交的事务就不会存在锁冲突,在Slave端执行时都可以并行执行,这就是基于commit order的Logical clock。MySQL5.7引入 binlog_group_commit_sync_delay和 binlog_group_commit_sync_no_delay_count参数来提高binary log组提交并发数量:MySQL等待binlog_group_commit_sync_delay毫秒的时间直到binlog_group_commit_sync_no_delay_count个事务数时,将进行一次组提交,从而提升组提交的效率(组提交可以等雨亮讲事务的时候说一下)。补充解释表格 | 每次事务提交seq number将会加1。 | | —- | | last commit在前面的binlog准备阶段就赋值给了每个事务。 | | last commit是前一个COMMIT队列的最大seq number。 |

  • 基于write set的并行复制组提交形式的并发其实是主要是通过主库增加并行度实现高效率复制,但是如果主库本身的并发度非常低,那么从库的执行效率也不会高。在https://dev.mysql.com/doc/dev/mysql-server/8.0.23/rpltrxtracking_8h_source.html中定义了Writeset_trx_dependency_tracker::Writeset_history,利用该map存储了writeset的hash值与最新一次本行数据修改事务的seq number。writeset对与last_commit的处理流程假设一个事务中包含了四条数据(更改了R1、R2、R3、R4这四行),该事务在ORDER_COMMIT下的last commit=135,seq number=130假设此时的Writeset_history的map中存储的数据为在writeset模式下,其历史map表以及last_commit将会出现如下变化第一行数据的seq_number为125,小于该事务的seq_number,则改行的seq_number修改为130,last_commit为135>125,因此last_commit置换为125第四行数据由于没有历史数据,所以新增一行,不影响last_commit。最终last_commit从从135降低为125,因此可以WriteSet是在“组提交”方式上建立起来的,一种新的并行复制实现;相比“组提交”来说更加灵活;当然,由于并发度上去了,相比“组提交”,WriteSet在性能上会更加好一些,但是WriteSet本身以及Writeset_history都会占据额外的内存空间以及维护成本(初始化+清理),造成一定的系统压力。 | key | value | 备注 | | —- | —- | —- | | R1 | 125 | | | R2 | 102 | | | R3 | 103 | |

key value last_commit
R1 130 125<130=>125
R2 130 102<125=>125
R3 130 103<125=>125
R4 130 不存在历史数据,last_coomit保持125

业务解决方案:

  • 批量的DDL操作,由于DDL的apply可能花费较长时间,所以每次涉及到DDL操作时可以放在低峰期。
  • 对与主库来说,大事务长期占有锁,会导致与锁相关的操作日志堆积,堆积量较大时批量发送到从库后可能会导致主从延迟升高,对于这种大事务可以拆分为小事务。
  • 减少大量写QPS导致的主从复制的延迟
  • 对于热数据,走从库会导致数据过期影响业务,所以热数据应当强制走主库。
  • 尽量采用短的链路,也就是主库和从库服务器的距离尽量要短,提升端口带宽,减少binlog传输的网络延时。

备注:
mysql中的schema:从概念上讲,schema是一组相互关联的数据库对象,如表、视图、存储过程、索引,外键等等。但是从物理层面上来说,模式与数据库是同义的。你可以在MySQL的SQL语法中用关键字SCHEMA替代DATABASE,例如使用CREATE SCHEMA来代替CREATE DATABASE。
MySQL的GTID是全局事务ID,每个事务由GTID标识,在master上跟踪事务状态并在slave上应用。GTID具体就是由冒号连接的两个ID的组合:GTID = source_id:transaction_id
当数据库忽然掉电,再重新启动时,MySQL可以通过Redo log还原数据。每次事务提交时,不用同步刷新磁盘数据文件,只需要同步刷新Redo log就足够了。相比写数据文件时的随机IO,写Redo log时的顺序IO能够提高事务提交速度。
source_id就是master的server_id。transaction_id是一个序列值,表示哪些事务在master上commit成功了。比如,3E11FA47-71CA-11E1-9E33-C80AA9429562:23表示在uuid=3E11FA47-71CA-11E1-9E33-C80AA9429562的server上事务号23的事务提交成功了。GTID在整个复制集群中是唯一的,slave中如果重做了某个GTID标识的事务,那么后续该GTID标识的事务则不予理睬(参数enforce-gtid-consistency)。