1 主从复制
在主库上记录二进制日志,在从库重放日志,实现异步的数据复制。非强一致性,由于时延、大语句执行等。
主要涉及三个线程:BinLog 线程、I/O 线程和 SQL 线程。
- BinLog 线程:在主库上把“数据更改”(按事物提交顺序)记录到二进制日志(Binary Log)中。
- I/O 线程:从库从主库拉取二进制日志,复制到自己的重放日志(Replay Log)中。
- SQL 线程:从库读取重放日志中的SQL 语句,并重放到从库数据之上。
2 复制的原理
MySQL 默认使用“基于语句”的复制,在发现语句无法正确被复制时,会动态切换到“基于行”的复制。
2.1 基于语句的复制
主库只记录“造成数据更改”的 SQL,从库把主库执行过的 SQL 再执行一遍。
- 优点:
- 实现简单,binlog 紧凑
- 支持在从库先修改表结构,升级从库为主库,减少停机时间
- 缺点:
- 实际上 SQL 可能还依赖其他元信息,比如“当前时间戳”、“CURRENT_USER()”。
- 复制存储过程和触发器也可能出错。
2.2 基于行的复制
将实际数据记录在 binlog 中
- 优点:
- 可以正确地复制每一行;
- 复制查询代价高的 SQL 时更高效
- 缺点:
- 在复制“全表更新”这类影响行数大的 SQL 时,代价大;
- 在涉及到“在从库修改表”这种情况会失败
- 无法判断执行了哪些 SQL,很难 debug
3 强一致性
从库可能因为各种错误或特性,导致数据和主库不一致。例如 MySQL 的 Bug、网络中断、服务器崩溃、非正常关闭……
3.1 单机数据库
在单机数据库中为了保证事务更新操作不会丢失会使用 WAL 日志优先(Write-Ahead-Logging)技术:即事务提交时,保证将事务产生的日志先刷到磁盘上,若事务跟新失败,则通过日志可以回滚
3.2 主从数据库
1)异步复制(Asynchronous replication)
MySQL 默认的复制即是异步的,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理。
这样就会有一个问题,主如果 crash 掉了,此时主上已经提交的事务可能并没有传到从上,如果此时,强行将从提升为主,可能导致新主上的数据不完整。
2)全同步复制(Fully synchronous replication)
指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。
因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。
3)半同步复制(Semisynchronous replication)
介于异步复制和全同步复制之间,主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到 relay log 中才返回给客户端。
相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一定程度的延迟,这个延迟最少是一个 TCP/IP 往返的时间。所以,半同步复制最好在低延时的网络中使用。
半同步复制的潜在问题:客户端事务在存储引擎层提交后,在得到从库确认的过程中,主库宕机了……
4)Loss-Less 半同步复制
MySQL 5.7 引入了一种新的半同步方案:Loss-Less 半同步复制。
优先保证从库的 relay log 中继日志更新落盘比主库返回给应用程序事务已提交早:
- 在主库事务提交的时候,同时发起两个操作,操作一是将日志写到本地磁盘,操作二是将日志同步到从库并确保落盘
- 主库此时等待两个操作全部成功返回之后,才返回给应用程序,事务提交成功
- 当有多个从库的时候,为了提升性能,只要有一个从库返回日志落盘成功,在主库日志已落盘的情况下,即可返回应用程序提交成功
4 读写分离
主服务器处理写操作以及实时性要求比较高的读操作,而从服务器处理读操作。
读写分离能提高性能的原因在于:
- 主从服务器负责各自的读和写,极大程度缓解了锁的争用;
- 从服务器可以使用 MyISAM,提升查询性能以及节约系统开销;
- 增加冗余,提高可用性。
读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。
5 增加从机
5.1 mysqldump
- 通过 mysqldump 备份主库,恢复到从库
- mysqldump 是逻辑备份,数据量大时,备份速度会很慢,锁表的时间也会很长。
5.2 xtrabackup
- 通过 xtrabackup 工具备份主库,恢复到从库
- xtrabackup 是物理备份,备份速度快,不锁表。
- 不锁表:因为自身会监控主库日志,如果有更新的数据,就会先写到一个文件中,然后再回归到备份文件中,从而保持数据一致性。