本文将回顾MySQL复制概念和MySQL几种复制方案,同时也会澄清一些关于复制问题的误解。
MySQL复制是什么?
复制能够保护信息得到备份,并且备份会不同于原数据,备份会被保存到另一个环境。即主备数据不在同一台服务器。下图是MySQL复制示意图:
MySQL有 哪 些复制方案?
复制如此重要,那么在MySQL中我们有哪些选择呢?
1. 异步复制
异步复制意味着本地环境操作完成,事务就完成 ,不会受到slave复制是否完成的影响。
当改变被提交后,master就会把数据修改信息放到binlog中(也可能把实际的statement放到binlog中,这是row-based复制和statement-based复制的不同,后面会讲到)。dump线程读取binlog日志然后将其发送到slave,slave接受并保存到待处理队列中(被称为relay-log),slave会执行每一个在master上的改变:
2. 半同步复制
半同步复制(Semi-synchronous replication)意味着master和slave彼此通讯确保事务的正确转移。 当改变发生时,master需要等待slave已经将日志保存到relay-log中并向master回复确认master才能提交事务 。 半同步复制可以保证事务被正确的复制,但不能保证在slave上一定发生:
需要注意的是,半同步复制的话,master需要等待至少有一个slave服务器确认接收到事务并保存了relay-log(或达到超时)才能继续处理同一个SESSION中的当前事务,至于具体多少个slave确认,可以通过参数rpl_semi_sync_master_wait_slave_count进行配置,这个值有效范围是1~1024之间,而且这个值可以动态更新。举个栗子:
假设rpl_semi_sync_master_wait_slave_count被设置为2,并且有两个slave,分别是: slave1和slave2。
1. T1等待两个slave的ack;
2. master收到slave1的ack;
3. 此时加入一个slave3,并将rpl_semi_sync_master_wait_slave_count改为3;
4. master收到 sl av e2的ack ;
5. master收到 sl av e3的ack;
6. master唤醒等待中的事务,并准备提交;
记住半同步复制会影响性能,因为它需要等待来自slave的确认(ack)。但是,它也能减少slave上由于故障导致数据丢失的风险。
3. 组复制
组(Group)复制是MySQL5.7版本新介绍的概念,在5.7.17发布了GA,而且以插件模式提供。
任意一个数据库节点无论什么时候执行一个事务,组复制插件在向客户端响应它已经完成事务前,会尝试得到其他数据库节点的同意。组复制示意图如下:
4. Percona XtraDB Cluster / Galera Cluster
再介绍一个把master数据复制到其他节点的解决方案,就是Percona XtraDB Cluster,简称PXC。这个解决方案把重心放在一致性上,并且通过使用一个认证过程来保证事务避免冲突和执行的正确性。在这个集群方案的数据库环境下, 每个节点的数据都是相同的,节点之间会依赖galera提供的广播机制来保证一致性 。
以一条SQL为例,某节点接收SQL请求后,在commit之前,由wsrep API 调用galera库进行集群内广播,所有其他节点验证成功后事务在集群所有节点进行提交,反之rollback。PXC保证整个集群所有数据的强一致性,满足CAP理论中的CA,即 Consistency 和 Availability。
Percona XtraDB Cluster 有很多组件:
Percona Server for MySQL(MySQL的Percona分支);
Percona XtraBackup (主要用于集群的快照备份);
wsrep patches / Galera Library;
该解决方案几乎是同步的,可与组复制相媲美。但是,它还具有使用多主复制的能力。Percona XtraDB Cluster这样的组件能很好的提高数据库基础架构可用性:
Row-Based VS. Statement-Based
讨论MySQL复制,就不得不提Row-Based复制和Statement-Based复制。 因为它们是两种不同复制方案的实现原理。
对于statement-based 复制(被翻译为基于语句复制),执行的SQL本身会被写入binlog中,例如完全相同的 INSERT/UPDATE/DELETE 语句会被在slave上执行。它的优缺点如下:
审计数据库会更容易,因为实际执行的SQL语句就被记录在binlog中;
主从之间会有更少的数据传输;
binlog日志需要的空间更小;
不确定性SQL可能会给slave带来很大的影响;
某些操作(例如insert...select)会有性能劣势;
Statement-based复制会由于SQL优化和执行变得更慢;
slave上一些复杂SQL执行时,执行计划评估可能变得糟糕;
数据一致性问题会有更大的挑战;
Row-based 复制(基于行复制)是从MySQL 5.7.7起默认的选择,它有很多优点,改变的行会被记录在binlog中,因此它不需要上下文信息。它的其他优点如下::
每一个改变都能被复制,所以是最安全的复制方式;
对于包含不是很多行改变的高并发操作,性能有一定的提升;
显著的改善了数据一致性;
当然,也有缺点:
网络流量显著变大,尤其当操作很多行记录的时候,可能打爆网络;
对于影响很多行的操作,Row-based就会很吃力,不擅长;
数据库操作审计变得更加困难,因为binlog中不记录SQL,取而代之的是记录变更的数据;
Row-based相比statement-based在一些场景下会更慢;
关于复制的误解
误解1: 复制就是集群
标准的异步复制不是集群,记住不管是标准的异步复制还是半同步复制,都不能保证环境服务于同一数据集。 而使用集群(例如Percona XtraDB Cluster)时,这是不同的,任意一个请求打到任意一台服务器上其结果都一样。如果不是,则会从群集中删除受影响的节点。异步复制没有这样的保障,即使某个slave节点与master处于不一致状态时仍然会接受操作请求。
误解2: 复制作为手动故障转移方案
理论上来说,两个环境之间是有可比性的。然而,有许多参数能影响性能和数据一致性。只要你使用了异步复制,在master上发生的事务正确性就无法在slave上得到保障。当然,你可以通过增强持久化的配置来改善这点,但是它相应的会带来一定的性能损耗,性能和可靠之间总需要做一定的取舍。
误解3: 我有复制,所以不用备份
复制是为了对数据集有一个可访问的副本的解决方案,通过把读请求打到复制节点,能减轻master的压力。但是复制不是备份。备份一般是指离线备份,它的作用是数据库所在环境发生灾难性的破坏不可恢复时,还能通过备份恢复数据库。对数据库进行离线备份是非常重要和有意义的事情!
误解4: 因为有复制,所以数据库能负载均衡事务请求
给master增加一个slave尽管可以改善系统的可用性,但是你仍然需要自己做几件事情:把读请求打到slave上,把写请求打到master上。有很多代理工具可以完成这样的事情,当然你可以自己动手造轮子!