一旦使用 MySQL 的复制功能,就很大可能会碰到主备切换的状况。也许是为了迭代升级服务器,或者是主库出现问题时,将一台备库转换成主库,或者只是但愿从新分配容量。不过出于什么缘由,都须要将新主库的信息告诉其它备库。mysql
对于主备切换,若是是计划内的操做,较为容易(至少比紧急状况下容易)。只需在备库简单的使用 CHANGE MASTER TO 命令,并指定合适的值便可。并且大多数的值是可选的,只要指定须要改变的配置项接口。sql
备库将抛弃以前的配置和中继日志,并重新的主库开始复制。同时,新的参数会被更新到 master.info 文件中,这样就算重启,备库配置信息也不会丢失。服务器
整个过程当中最难的是获取新主库上合适的二进制日志位置。这样备库才能够从老主库相同的逻辑位置开始复制。工具
把备库提高为主库要较为麻烦,咱们把备库提高主库分为计划内切换和计划外切换两种场景。spa
备库提高为主库,简单来讲,有如下步骤:日志
但上面的过程当中还所以着不少细节。一些场景可能依赖于复制的拓扑结构。更深刻一点,下面是大多数配置须要的步骤:blog
当主库崩溃时,须要将一台备库提高为主库。这个过程就比较麻烦。若是只有一台备库,能够直接使用这台备库。但若是有超过一台的备库,就须要作一些额外的工做。接口
另外,还有潜在的丢失复制事件的问题。可能有主库上已发生的修改尚未更新到它任何一台备库上的状况。甚至可能一条语句在主库上执行了回滚,但在备库上没有回滚,这样备库可能就超过主库的逻辑复制位置。若是能在某一点恢复主库的数据,也许就能够取得丢失语句,并手动执行他们。事件
在如下描述中,须要确保在服务器中使用 Master_Log_File 和 Read_Master_Log_Pos 的值。事务
若是已经在全部备库上开启了 log_bin 和 log_slave_updates,就能够将全部备库恢复到一个一致的时间点,若是没有开启这两个选项,则很难作到这一点。
上面过程当中比较重要的一点是肯定日志位置。接下来,咱们就来看看如何却。
若是有备库和新主库的位置不相同,则须要找到该备库最后一条执行的事件在新主库的二进制日志中对应的位置,而后再执行 CHANGE MASTER TO。能够经过 mysqlbinlog 工具来找到备库执行的最后一条查询,而后再主库上找到一样的查询,进行简单的计算便可获得。
为了便于描述,假设每一个日志事件都有一个自增数字 ID。新主库在老主库崩溃时得到了编号为 100 的事件,另外两条备库:R2 和 R3。R2 已结获取了 99 号事件,R3 获取了 98 号事件。
若是把 R2 和 R3 都指向新主库的同一个二进制日志位置,它们将从 101 号事件开始复制,从而致使数据不一样步。但只要新主库的二进制日志已结经过 log_slave_updates 打开,就能够在新主库的二进制日志中找到 99 号 和 100 号事件,从而将备库恢复到一致的状态。
因为服务器重启,不一样的配置,日志轮转或者 FLUSH LOGS 命令,同一个事件在不一样的服务器上可能有不一样的偏移量。咱们能够经过 mysqlbinlog 从二进制日志或中继日志中解析出每台备库上执行的最后一个事件,并还有该命令解析新主库上的二进制文件,找到相同的查询,mysqlbinlog 会打印出该事件的偏移量,在 CHANGE MASTER TO 命令中使用这个值。
更快的方法是把新主库和中止的备库上的字节偏移量相减,它显示了字节位置的差别。而后把这个值和新主库当前二进制日志的位置相减,就能够获得指望的查询位置。
一块儿来看个栗子。
假设 s1 是 s2 和 s3 的主库。其中 s1 已经崩溃。根据 SHOW SLAVE STATUS 得到 Master_Log_File 和 Read_Master_Log_Pos 的值,s2 已结执行完了 s1 上全部的二进制日志,但 s3 尚未。如图 1:
咱们能够确定 s2 已经执行完了主库上的全部二进制日志,由于 Master_log_File 和 Read_Master_Log_Pos 的值和 s1 上最后的日志位置相吻合。所以,咱们能够将 s2 提高为新主库,并将 s3 设置为 s2 的备库。
应该在 s3 上为须要执行的 CHANGE MASTER TO 语句赋予什么参数呢?这里须要作一点计算。
s3 在偏移量 1493 处中止,比 s2 执行的最后一条语句的偏移量 1582 要小 89 字节。
s2 正在向偏移量为 8167 的二进制日志写入,所以,理论上咱们应该将 s3 指向 s2 日志的偏移量为 8167-89=8078 的位置。
最后在 s2 日志中的 8078 位置,肯定该位置上是不是正确的日志事件。
若是验证没问题,能够经过下面命令将 s3 切换为 s2 的备库:
CHANGE MASTER TO MASTER_HOST="s2 host", MASTER_LOG_FILE="mysql-bin.000009", MASTER_LOG_POS=8078;
若是服务器在它崩溃时已经执行完成并记录了一个事件 a。由于 s2 仅仅读取并执行到了 1582,所以可能会失去事件 a。可是若是老主库的磁盘没有损坏,仍然能够经过 mysqlbinlog 或者从日志服务器的二进制日志中找到丢失的事件。