概述
复制功能不仅有利于构建高性能的应用,同时也是高可用、可扩展性、容灾恢复、备份以及数据仓库等工作的基础。
MySQL 支持两种复制方式:
- 基于行的复制
- 基于语句的复制(也称为逻辑复制)
两种方式都是通过在主库上记录二进制日志,在备库中重放日志实现异步的数据复制,因此存在延迟。
MySQL 的复制大部分后向兼容,新版本的服务器可以作为老版本服务器的备库,但反之不行,因为它可能无法解析新版中的新特性或语法。对于小版本号升级通常是兼容的。
这里记下经历过的一个坑,oracle 10g 小版本不同也不兼容无法恢复 rman 备份。主库版本是 10.2.0.5,尝试在 10.2.0.1、10.2.0.3 下都无法恢复备份。MySQL 也说了通常,最好还是看一下更新的 changelog。
复制主要开销在于:
- 备库从主库读取二进制日志文件时的 IO 开销
- 从高吞吐主库复制到多个备库时唤醒复制线程的开销
复制的常见用途
- 数据分布:在不同的物理位置分布数据备份
- 负载均衡:对读密集型应用进行优化
- 备份:复制可以作为备份的补充,但不能取代备份
- 高可用性和故障切换:避免单点失败造成的系统宕机
- MySQL 升级测试:用高版本 MySQL 作为备库,进行新版本测试
复制的三个步骤:
- 主库把数据更改记录到二进制日志中
- 发生在事务提交后实际更新数据之前,按照事务提交顺序而不是语句执行顺序记录
- 备库将主库上的日志复制到自己的中继日志(Relay Log)中
- 备库读取中继日志中的事件,将其重放到备库数据之上
- 在主库上并发运行的查询在备库上只能串行化执行,因为只有一个 SQL 线程来重放中继日志中的事件,这会成为很多工作负载的性能瓶颈
配置
假设有 server1(192.168.0.1),server2(192.168.0.2)
- 创建复制账号
1 | GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* |
在主库和备库都创建这个账号,尽管这个账号无法执行 select 等查询,但可以从二进制日志获取数据。
复制账号事实上只需要主库上的
REPLICATION SLAVE
权限,不一定需要每一端服务器都有REPLICATION CLIENT
权限,如此设置原因有:
- 用来监控和管理复制的账号需要此权限,针对这两种目的使用同一个账号更方便
- 备库上的设置和主库完全相同,方便交换主备库
- 配置主库和备库
在主库的my.cnf
文件中设置如下,重启服务器
1 | # 开启二进制日志 |
备库中类似,同样需要重启:
1 | log_bin = mysql-bin |
- 启动复制
1 | CHANGE MASTER TO MASTER_HOST='server1', |
可以通过SHOW SLAVE STATUS
查看是否成功,使用START SLAVE
开始复制。
新备库初始化
当主库已经运行一段时间要新增一个备库的时候,需要初始化备库,保持主库和备库同步需要满足如下条件:
- 在某个时间点主库的快照
- 主库当前的二进制文件,和获得数据快照时在该二进制日志文件中的偏移量
- 从快照时间到现在的二进制日志
从其他服务器克隆备库的方法:
- 冷备份,重启主库后使用一个新的二进制日志文件,备库指向这个新文件
- 热备份,如果仅使用了 MyISAM 标,可在主库运行时使用
mysqlhotcopy
或rsync
来复制数据 - MySQLdump,如果只有 InnoDB 表,可使用如下语句导出数据,将其加载到主库后设置相应的二进制日志坐标
1 | mysqldump --single-transaction --all-databases \ |
- 使用快照或备份,确保从备份时间开始的二进制日志都存在,恢复备份后,使用
CHANGE MATER TO
指定二进制日志坐标 - 其他热备工具如 Xtrabackup
- 使用另外的备库,注意不能使用
SHOW MATER STATUS
来获取主库的日志坐标,而是在获取快照时使用SHOW SLAVE STATUS
来获取备库在主库上的执行位置。
复制的原理
基于语句的复制(统计查询并记录开销大)和基于行的复制(全表更新开销大)各有优缺点,MySQL 能在两种模式间动态切换,默认情况下使用基于语句的复制。
基于语句的复制
- 优点:主备模式不同时,逻辑复制能在多种情况下工作。例如,主备上的表的定义不同但数据类型兼容、列的顺序不同等情况。很容易修改备库上的 schema,将其升级成主库
- 缺点:在使用触发器或者存储过程的时候比较容易出问题
基于行的复制
- 优点:几乎没有无法处理的场景,除了修改 schema。这种方式可以减少锁的使用。
- 缺点:无法知道执行了哪些 SQL
设置log_slave_updates
选项可以让备库变成其他服务器的主库,实现复制事件的传递
复制过滤选项允许仅复制服务器上的部分数据,有两种过滤方式:
- 在主库上过滤记录到二进制日志中的事件
- 在备库上过滤记录到中继日志的事件
使用复制过滤比较容易出问题,要慎重。更好的办法是阻止一些特殊的语句被复制,通常是设置SQL_LOG_BIN=0
。
复制拓扑
基本原则:
- 一个备库只能有一个相应的主库
- 每个备库都必须有唯一的服务器 ID
- 一个主库可以有多个备库
log_slave_updates
选项,可以让备库传递复制
一主多备
结构简单,备库之间没有交互,通常用途:
- 为不同角色使用不同的备库(如添加不同的索引或使用不同的存储引擎)
- 把一个备库作为候补主库
- 灾备
- 测试、培训、开发等
主 - 主复制
主动 - 主动模式:在并发修改数据的时候容易起冲突
主动 - 被动模式:其中一台服务器为只读
服务器的配置是对称的,使得切换主动和被动服务器非常方便,便于维护。
例如,ALTER TABLE
操作可能会锁住整个表,非常耗时,影响服务。在主-主配置下,可以先停止主动服务器上的备库复制线程(从被动库复制),在被动库上执行耗时操作后交换角色,重启先前主动库上的复制线程,后台执行操作。这样两个库上的操作都在“后台”完成。
配置:
- 确保两机有相同的数据
- 启用二进制日志,选择唯一 ID,创建复制账号
- 启用备库更新的日志记录,用于故障转移和故障恢复
- 把被动库配置成只读,防止数据冲突
- 启动实例
- 将对方设置为备库
主动服务器上发生更新后,更新被记录在二进制日志中,通过复制传递到被动服务器的中继日志中。被动服务器重放查询并记录到自己的二进制日志中。由于时间的服务器 ID 和主动服务器的相同,主动服务器将忽略这些事件。
有备库的主 - 主结构
环形复制
环形结构没有双主结构的一些有点,如对称配置和简单的故障转移,并且完全依赖于环上的每一个可用节点,增加了系统失效的几率,非常脆弱,应该避免使用。为每个节点增加备库可以减少风险。
分发主库
当备库较多时,为了减小主库的负担,指定一个库作为分发主库,从主库获取日志后分发给其他备库。分发主库使用 blackhole 引擎,不执行实际操作。
树结构
定制化方案
- 选择性复制:每个备库只拥有主库的部分数据,将数据驻留在内存中。有点类似水平数据划分,但是主库中拥有所有数据。
- 分离功能:将 OLTP 服务器的数据复制到专门的 OLAP 备库上,这个备库可以使用不同的硬件、配置、索引或存储引擎
- 数据归档:选择性阻止 delete 语句的传递,在备库上保留猪肚上删除过的数据
- 全文检索:在备库中使用 MyISAM 支持全文检索,主库使用支持事务的 InnoDB
- 模拟多主库复制
- 创建日志服务器:使用复制代替
mysqlbinlog
工具实现备份恢复
复制和容量规划
考虑备库吞吐量的使用不能只使用总查询/备库数量,每台机器还需要加上主库分发的写数据的工作量。备库的扩展不是线性的,查询数量增加 4 倍可能要增加 17 倍的服务器。
复制无法扩展写操作,虽然主-主结构理论上可以提升写入性能(复制时写入是串行化的,效率更高)但这么做提升非常有效而且风险很大。数据分区是唯一可以扩展写入的方法。
可以人为地制造延迟,测量备库的性能。比如在12点将备库停止,1点重新开启,发现备库在2点时追上的主库的进度保持同步,则说明备库的性能极限能承担两倍于现在的负载。
复制管理和维护
管理和维护工作应该尽量自动化,涉及的工作通常有:
- 监控复制
- 测量备库延迟
- 确认主备是否一致
- 未同步的备库修复
- 更换主库
- 主-主结构中交换角色
复制的问题和解决方案
涉及到非常多细节,在此详细记录,实际用到时查阅相关资料。
高级特性
半同步复制
半同步复制在提交过程中增加了一个延迟:提交事务时,在客户端接收到查询结束反馈前必须保证二进制日志已经传输到至少一台备库上。主库将事务提交到磁盘之后会增加一些延迟,同样的也增加了客户端的延迟,因此其执行事务的速度受到复制速度的限制。
特别注意:
- 主库不会阻塞事务提交,只有通知客户端被延迟了
- 备库在接收到事务后就发送反馈,而不是等到事务执行完才发送
- 如果备库一直没有会应已收到事件,会超时并转化为正常的异步复制
半同步复制在某些场景下能提供足够的灵活性以改善性能,在主库关闭 sync_binlog
的情况下保证安全。写入远程的内存(备库反馈)比写入本地的磁盘要更快。
复制心跳
在主备库之间建立联系,如果网络断开,备库会注意到丢失的心跳数据。