MySQL数据库的可扩展与高可用(读书笔记)-2 复制原理

复制剖析

复制原理

下面深入的了解复制。看看复制究竟如何工作的。

基于语句的复制

在 MySQL 5.0 以及之前只支持基于语句的复制,也就是主库记录所有对数据库进行更改的查询,当备库重放这些事件的时候世纪就是把那些SQL在执行一遍。这种方式有好处也有缺点。

好处:

  1. 实现简单
  2. binlog里面的事件更加紧凑

所以基于语句的模式不会使用太多带宽。一条更新好几兆的语句在binlog里面可能只占几个字节。mysqlbinlog工具是使用基于语句的日志的最佳工具。

坏处:

  1. 主库与备库执行的时间可能稍微或很不同,所以需要加上一些时间戳
  2. 还有一些无法被正确复制的语句,如 CURRENT_USER
  3. 存储过程和触发器在使用基于语句的复制模式时也可能存在问题。
  4. 更新必须是串行的。这需要更多的锁。

基于行的复制

这种方式将实际的数据记录在binlog里面。

好处就是正确的复制每一行,一些语句可以被更加有效的复制。比如一些语句需要通过大量的计算得到仅仅只有几行的数据。那么用这种方式就可以减少数据库在执行SQL语句时的开销。但是如果有基于全表的更改,这种方式开销就会比基于语句的复制大。

由于没有那个方案是完美的,所以MySQL能够在这两种复制模式之间动态切换。默认是基于语句,如果又无法正确传达的语句,MySQL就切换到基于行的复制。还可以根据需要来设置会话级别的变量设置 binlog_format,控制二进制格式。

那么这两种哪个更好呢?

理论上基于行的复制更好。并且世纪应用也适合大多数场景。下面来汇总一下在应用过程中这两个方式的有点与缺点。

基于语句复制的优点

  1. 当主备模式不同的时候,逻辑复制能够在多种情况下工作。例如主备表的定义不同但是数据类型兼容或者列顺序不同。
  2. 基于语句就是执行SQL,所以在服务器的变更都以一种容易理解的方式运行。出现问题时好定位。

缺点

  1. 无法正确复制,对于存储过程,触发器以及其他的一些语句复制在5.0和5.1的一些列版本中存在大量的Bug。这些语句的复制方式被更改很多次。如果使用触发器或者存储过程就不要使用基于语句的复制模式,除非能够清楚的确定不会碰到复制问题。

基于行复制的优点

  1. 几乎所有场景都可以用这种方式处理。只是当你试图做一些诸如在备库修改表的schema这样的事情时才可能导致复制失败。
  2. 这种方式可以减少锁的使用。因为他不要求这种强串行化是可复制的。
  3. 因为记录的是数据,所以不用才一个语句可能会更改那些数据。另外一些情况基于行的二进制日志还会记录发生改变之前的数据,因此可能有利于数据恢复。
  4. 由于无需建立执行计划并查询,因此基于行的复制占用更少的CPU。
  5. 能够快速找到数据不一致的地方

缺点

  1. 无法知道执行了哪些SQL。
  2. 无法知道服务器正在做什么,如果出现问题很难找出原因。
  3. 无法处理在备库修改表schema这样的情况。
  4. 如果发现不一致可能会停止复制,但是可以通过slave_exec_mode进行配置

复制文件

之后看一下复制会用到那些文件。不同版本的MySQL默认情况可能会将这些文件放到不同的目录里面,大多取决具体的配置选项。

  1. mysql-bin.index
    这个文件是一个和二进制文件同名但是是以index为结尾的文件。这个文件每一行都包含了二进制文件的文件名。MySQL依赖这个文件,如果这个文件没有记录,MySQL识别不了二进制日志文件。

  2. mysql-relay-bin-index
    这个文件是中继日志的索引文件,和mysql-bin.index的作用类似。

  3. master.info
    记录备库连接到主库的信息。这个文件以文本的方式记录了复制用户的密码,因此要注意此文件的权限控制。

  4. relay-log.info
    这个文件包含了当前备库复制的二进制日志和中继日志坐标,如果删除则备库无法得知从哪个位置开始复制。

.index文件也与设置expire_logs_days存在交互,该参数定义了MySQL清理过期日志的方式,如果文件mysql-bin.index在磁盘上不存在,在某些MySQL版本自动清理就不会起作用。所以应该用MySQL服务器管理二进制日志,这样就不会产生误解。

而且应该显式的执行一些日志清理策略,比如expire_logs_days参数或者其他,否则MySQL二进制可能会将磁盘撑满。

发送复制事件到其他备库

log_slave_updates选项可以让备库变成其他备库获取binlog的来源。如下图所示:
在这里插入图片描述
这个选项默认是打开的。

当地一个备库将从主库获得的事件写入到二进制日志中,这个事件在备库二进制日志中的位置与其主库二进制日志的位置几乎肯定是不相同的。这意味着你不能假定所有拥有同一逻辑复制点的服务器拥有相同的日志坐标。

复制过滤器

复制过滤器允许你仅复制服务器上的一部分数据,不过不是很好用。有两种复制过滤方式:

  1. 在主库上过滤记录到二进制日志中的事件
  2. 在备库上过滤记录到relay log的事件。

使用选项 binlog_do_db 和 binlog_ignore_db 来控制过滤。但是会导致数据永久消失并且无法恢复。

在备库上,可以通过设置replicate_*选项,在从中继日志中读取事件时进行过滤。你可以复制或者忽略一个或多个数据库,把一个数据库重写到另一个数据库,或使用类似LIKE的模式复制或忽略数据库表。

最后强调一点,不在万不得已的情况下不要使用过滤器。

复制拓扑

原则:

  1. 一个备库只能由一个主库。
  2. 每个备库必须有一个唯一的服务器ID
  3. 一个主库可以有多个备库
  4. 如果打开了log_slave_updates选项,一个备库可以把其主库的数据变化传播到其他备库

一主库多备库

再有少量写大量读的时候,这种配置十分有用。可以把读分摊到多个备库上,直到备库给主库造成了太大的负担,或者主备库之间的带宽成为瓶颈为止。你可以按照之前介绍的方法一次性设置多个备库,或者根据需要增加备库。

用途:

  1. 为不同的角色使用不同的备库(例如添加不同的索引或者使用不同的存储引擎)
  2. 把一台备库当作待用的主库,除了复制没有其他数据传输。
  3. 将一台备库放到远程数据中心用作灾难恢复
  4. 延迟一个或多个备库,以备灾难恢复
  5. 使其中一个备库,作为备份,培训,开发或者测试使用服务器。

这种结构避免了其他拓扑结构的复杂性。所有备库同时停止的话都在读取的是主库上同一个日志文件的相同物理位置。

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

主 - 主复制包含两台服务器,每一个都被配置成对方的主库和备库,也就是一对主库。这种模式应用在一些特殊场景,比如两个不同地理位置的办公室都需要一份可写的数据拷贝。

这种配置最大问题就是解决冲突,比如同时对一行数据进行修改过着用自增键。如果可以仔细配置这种架构例如数据划分可以避免一些问题。但是这种方式的坏处远远大于好处。

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

这种方式是构建容错性和高可用性系统非常强大的方式,主要区别在于其中的一台服务器是只读的被动服务器。

这种配置下如果被动主库想更改数据可以先停止主动服务器上的备库复制线程(这样就不会在被动服务器上执行任何更新),然后在被动服务器上执行ALTER操作,交换角色,最后在先前的主动服务器上启动复制线程。这个服务器将会读取中继日志并执行ALTER语句。会花很长时间但是该服务器没有为任何服务查询提供服务所以不要紧。

在两台服务器上执行如下设置后,会使其拥有对称的设置:

  1. 确保两台服务器上拥有相同的数据
  2. 启用二进制日志,选择唯一的服务器ID,并创建复制账号。
  3. 启用备库更新的日志记录,后面将会看到,这是故障转移和故障恢复的关键。
  4. 吧被动服务器配置成只读,防止可能与主动服务器上的更新产生的冲突,这一点是可选的。
  5. 启动每个服务器的MySQL实例。
  6. 将每个主库设置为对方的备库,使用新创建的二进制日志开始工作。

更新被记录到二进制日志中,通过复制传递给被动服务器的中继日志中,被动服务器执行查询并将其记录到自己的二进制日志中(开启了log_slave_updates)。由于事件的服务器ID与主动服务器的相同,因此主动服务器将忽略这些事件。然而,你不会获得比单台服务器更好的写行能。

拥有备库的主 - 主结构

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

环形复制

在这里插入图片描述
很脆弱,如果有一个节点故障,这个节点发起的事务就会一直循环下去,因为唯一可以过滤掉这个事件的节点就是这个事件的发起者。我们可以通过增加备库来降低风险但是这种结构还会有狠毒哦其他的问题。

主库,分发主库与备库

分发主库可以代替主库执行binlog dump,不会让主库因为分发数据而消耗资源。分发主库也是一个备库,他唯一的目的就是提取和提供主库的二进制日志。多个备库连接到分发主库,这使得原来的主库摆脱了负担。为了避免在分发主库上做实际的查询,可以将他的表修改为blackhole存储引擎。当对分发库进行查询的时候,代价会很小,因为blackhole表没有任何数据。blackhole的缺点就是他的Bug,例如在某些情况下会忘记将自增ID写入到二进制日志中。

缺点就是无法禁止使用非blackhole存储引擎。还有就是无法用备库当作主库的替代库,因为binlog坐标已经不一样。

树或金字塔形

好处就是减轻了主库的负担,坏处就是如果有一个节点有故障,下面的字库都无法正常工作。

定制的复制方案

典型的定制方案包括组合过滤,分发和向不同的存储引擎复制。也可以用blackhole存储引擎的服务器上复制或复制到这样的服务器。其中最大的限制就是合理的监控和管理,以及所拥有资源的约束(贷款和cpu)

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

  2. 分离功能
    很多应用都混合了在线事务处理(OLTP)和在线数据分析(OLAP)的查询。OLTP查询比较短而且是事务性的,OLAP查询则很大很慢,并且不要求绝对最新的数据。这两种查询给服务器带来的负担完全不同,因为他们需要不同的配置,甚至不同的存储引擎和硬件。

  3. 数据归档
    可以在备库上实现数据归档,也就是在备库上保留数据,在主库上删除数据。有两种方法,第一是选择性禁止二进制日志,另一种是在备库上使用replicate_ignore_db规则。但是两种方法都很危险。

对于第一种方法需要先将SQL_LOG_BIN设置为0,然后再进行数据清理。这种方法的好处就是不需要在备库进行任何的设置,由于SQL语句根本没有记录到二进制日志中,效率会提升。缺点就是无法使用binlog进行审计或按时间点恢复数据。还需要SUPER权限。

第二种方法先在主库上对特定的数据库使用USE语句,然后再my.cnf文件里设置

bashreplicate_ignore_db=数据库名称

并重启服务器。备库就会忽略之前指定的数据库。但是这种方法有一个缺点就是备库要去读他不需要的数据。

  1. 将备库用作全文检索
    许多应用要求合并事务和全文检索。一个做法就是配置一台备库,将表设置为MyISAM存储引擎,然后创建全文索引。

  2. 只读备库
    将备库设置为只读,以防止在备库进行无意识的修改导致复制复制中断。可以用read_only实现

  3. 模拟多主库复制
    两个主库数据不相同,让他们假一致的方法就是对方的数据用blackhole表。之后让备库轮询两个主库。也可以就让备库链接一个主库,这个主库里面对于另一个主库的数据用blackhole存储。

  4. 创建日志服务器
    唯一的目的就是更加容易重放并且过滤binlog事件。假设日志被命名为 somelog-bin.000001, somelog-bin.000002,等。将这些日志放到日志服务器的日志文件夹中。假设为/var/log/mysql。然后在启动服务器前编辑my.cnf文件如下:

log_bin = /var/log/mysql/somelog-bin
log_bin_index = /var/log/mysql/somelog-bin.index

服务器不会自动发现日志文件,因此还需要更新日志的索引文件。之后再UNIX系统完成:

# /bin/ls -1 /var/log/mysql/somelog-bin.[0-9]* > /var/log/mysql/somelog-bin.index

确保云心MySQL的账户可以读写日志索引文件。现在可以启动日志服务器并通过SHOW MASTER LOGS命令来确保其找到日志文件。

日志服务器比mysqlbinlog的好处:

  • mysqlbinlog不能确保像复制那样工作,并且可能无法正确生成二进制日志中的数据更新。
  • 复制速度更快,因为无需将语句从日志导出来传达给MySQL
  • 可以很容易观察到复制过程
  • 能够更方便的处理错误。例如可以跳过执行失败的语句
  • 更方便过滤复制时间
  • 有时候mysqlbinlog会因为日志记录格式更改而无法读取二进制日志。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值