第十章-复制

——「高性能mysql」读书笔记(第十章)

MySQL内建的复制功能是构建基于MySQL的大规模、高性能应用的基础,这类应用使用所谓的“水平扩展”的架构。

我们可以通过为服务器配置一个或多个备库的方式来进行数据同步。复制功能不仅有利于构建高性能的应用,同时也是高可用性、可扩展性、灾难恢复、备份以及数据仓库等工作的基础。

章节架构

基本脉络

本章将阐述所有与复制相关的内容,首先简要介绍复制如何工作,然后讨论基本的复制服务搭建,包括与复制相关的配置以及如何管理和优化复制服务器。

虽然本书的主题是高性能,但对于复制来说,我们同样需要关注其准确性和可靠性,因此我们也会讲述复制在什么情况下会失败,以及如何使其更好地工作。

KeyWord

  • 复制的原理

  • 复制拓扑

  • 主备是否一致

  • 复制方案

重点、亮点内容摘抄

复制解决的问题

  • 数据分布

  • 负载均衡

  • 备份

  • 高可用性和故障切换

  • MySQL升级测试

复制的原理

复制有两种形式,基于行的复制、基于语句的复制,实际上这两种都使用了 Binlog,通过在备库上重放主库的 Binary log -> Relay Log实现,由于重放是异步的,所以无法保证主备之间的延迟。获取事件和重放日志是解耦的,主库的日志在备库上串行地执行,有可能会受制于单线程。

image

MySQL 主从复制主要涉及三个线程:binlog 线程、I/O 线程和 SQL 线程。

  • binlog 线程 负责将主服务器上的数据更改写入二进制文件(binlog)中。

  • I/O** 线程:** 负责从主服务器上读取二进制日志文件,并写入中继日志中。

  • SQL** 线程:** 负责读取中继日志并重放其中的 SQL 语句。

log_slave_updates选项可以让备库变成其他服务器的主库。设置了该选项以后:MySQL会将其执行的事件记录到自己的二进制日志中。

image

基于行的复制

MySQL 5.1开始支持基于行的复制,这种方式会将实际数据记录在二进制日志中,跟其他数据库的实现比较相像。它有其自身的一些优点和缺点。最大的好处是可以正确地复制每一行。一些语句可以被更加有效地复制。

基于行的复制没有向后兼容性,和MySQL5.1一起发布的 mysql-binlog 工具可以读取基于行的复制的事件格式(它对人是不可读的,但MySQL可以解释),但是早期版本的mysql-binlog无法识别这类事件,在遇到错误时会退出。由于无须重放更新主库数据的查询,使用基于行的复制模式能够更高效地复制数据。

基于语句的复制

在MySQL 5.0及之前的版本中只支持基于语句的复制(也称为逻辑复制),这在数据库领域是很少见的。基于语句的复制模式下,主库会记录那些造成数据更改的查询,当备库读取并重放这些事件时,实际上只是把主库上执行过的SQL再执行一遍。

MySQL自动切换两种方式的使用,默认的使用基于语句的方式,如果无法正确的复制的话,就切换到基于行的模式 可以自己控制两种方式,使用binglog_format变量来控制。

复制拓扑

一个MySQL备库实例只能有一个主库。

每个备库必须有一个唯一的服务器ID。·

一个主库可以有多个备库(或者相应的,一个备库可以有多个兄弟备库)。

如果打开了log_slave_updates选项,一个备库可以把其主库上的数据变化传播到其他备库。

一主多备库

在有少量写和大量读时,这种配置是非常有用的。可以把读分摊到多个备库上,直到备库给主库造成了太大的负担,或者主备之间的带宽成为瓶颈为止。

image

用途

  • 为不同的角色使用不同的备库(例如添加不同的索引或使用不同的存储引擎)。

  • 把一台备库当作待用的主库,除了复制没有其他数据传输。

  • 将一台备库放到远程数据中心,用作灾难恢复。

  • 延迟一个或多个备库,以备灾难恢复。

  • 使用其中一个备库,作为备份、培训、开发或者测试使用服务器。

主动-主动模式下的主-主复制

主动—主动模式下主—主复制有一些应用场景,但通常用于特殊的目的。一个可能的应用场景是两个处于不同地理位置的办公室,并且都需要一份可写的数据拷贝。

这种配置最大的问题是如何解决冲突,两个可写的互主服务器导致的问题非常多。这通常发生在两台服务器同时修改一行记录,或同时在两台服务器上向一个包含AUTOINCREMENT列的表里插入数据。

image

image

主动-被动模式下的主-主复制

这种方式使得反复切换主动和被动服务器非常方便,因为服务器的配置是对称的。得故障转移和故障恢复很容易。它也可以让你在不关闭服务器的情况下执行维护、表、升级操作系统(或者应用程序、硬件等)或其他任务。这使优化表,操作系统(或者应用程序,硬件等)或其他任务。

image

拥有备库的主-主结构

这种配置的缺点是增加了冗余,对于不同地理位置的复制拓扑,能够消除站点单点失效的问题。你也可以像平常一样,将读查询分配到备库上。

如果在本地为了故障转移使用主一主结构,这种配置同样有用。当主库失效时,用备库来代替主库还是可行的,虽然这有点复杂。同样也可以把备库指向一个不同的主库,但需要考虑增加的复杂度。

image

环形复制

环形结构没有双主结构的一些优点,例如对称配置和简单的故障转移,并且完全依赖于环上的每一个可用节点,这大大增加了整个系统失效的几率。总地来说,环形结构非常脆弱,应该尽量避免。

image

树或金字塔形

这种设计的好处是减轻了主库的负担。缺点是中间层出现的任何错误都会影响到多个服务器。如果每个备库和主库相连就不会出现这样的问题。同样,中间层次越多,处理故障会更困难、更复杂。

image

复制方案

选择性复制

为了利用访问局部性原理(locality of reference),并将需要读的工作集驻留在内存中,可以复制少量数据到备库中。如果每个备库只拥有主库的一部分数据,并且将读分配给备库,就可以更好地利用备库的内存。并且每个备库也只有主库一部分的写入负载,这样主库的能力更强并能保证备库延迟。

分离功能

许多应用都混合了在线事务处理(OLTP)和在线数据分析(OLAP)的查询。一个常见的方法是将OLTP服务器的数据复制到专门为OLAP工作负载准备的备库上。这些备库可以有不同的硬件、配置、索引或者不同的引擎。

只读备库

许多机构选择将备库设置为只读,以防止在备库进行的无意识修改导致复制中断。可以通过设置read_only选项来实现。它会禁止大部分写操作,除了复制线程和拥有超级权限的用户以及临时表操作。只要不给也不应该给普通用户超级权限,这应该是很完美的方法。

场景分析

测量备库延迟

一个比较普遍的问题是如何监控备库落后主库的延迟有多大。虽然show slave status输出的Seconds_behind_master列理论上显示了备库的延时,但由于各种原因,并不总是准确的。

解决这些问题的方法是忽略Seconds_behind_master的值,并使用一些可以直接观察和衡量的方式来监控备库延迟。最好的解决方法是使用heartbeat record,这一个在主库上会每秒更新一次的时间戳。为了计算延时,可以直接用备库当前的时间戳减去心跳记录的值。

主备是否一致

主备一致是一种规范,而不是例外。所以检查主备库的一致应该是一个日常的规范。我们的数据库貌似没有日常的主备一致性检查。Percona Toolkit 里的 pt-table-checksum 能够解决上述几个问题。其主要特性是用于确认备库与主库的数据是否一致。工作方式是通过在主库上执行INSERT...SELECT查询。

通常情况下可以在主库上运行该工具,参数如下:

$ pt-table-checksum --replicate=test.checksum <master_host>
复制代码

该命令将检查所有的表,并将结果插人到test.checksum表中。当查询在备库执行完后,就可以简单地比较主备之间的不同了。

有没有什么通用的方案来检查主备库的一致性?

一主多从模式(多数公司的方案)

一主多从一台主库多台从库,A 为主库,负责读写,B、C、D为从库,负责读数据。

如果 A 库发生故障,B 库成为主库负责读写,C、D 负责读,修复故障后,A 也成为从库,主库 B 同步数据到从库 A。

image

  • 优点:多个从库支持读,分担了主库的压力,明显提升了读的并发度。

  • 缺点:只有1台主机写,因此写的并发度不高。

阅读思考

  1. 复制问题的根基是让服务器和服务器之间的数据同步。但在考虑复制问题的时候,也要顾及大局方面。比如系统资源的消耗,复制所带来的耗时,数据灾难的恢复。

  2. 保证复制的高性能的同时,同样需要关注其准确性和可靠性。想好处理偶发失败的兜底方案,来保证稳定性,也很重要。

  3. 局部性原理在复制方法上同样适用。可以更好地利用备库的内存,保证备库的低延迟,同时保证主库性能。

猜你喜欢

转载自juejin.im/post/7182920917599649829