一旦使用了MySQL的复制功能,就很有可能遇到主备切换。可能是为了迭代服务器升级,或者在主数据库出现问题时将备用数据库转换为主数据库,或者只是希望重新分配容量。但是,无论出于何种原因,有必要将新的主数据库告知其他备用数据库。对于主备倒换,如果是有计划的操作,还是比较容易的(至少比紧急情况下容易)。只需在备用数据库上使用CHANGEMASTERTO命令并指定适当的值。并且大部分值都是可选的,只需指定需要更改的配置项接口即可。备用数据库将丢弃以前的配置和中继日志,并从新的主数据库开始复制。同时,新的参数也会更新到master.info文件中,这样即使重启,备库的配置信息也不会丢失。整个过程中最困难的部分是在新主服务器上获取正确的二进制日志位置。这样,备用数据库可以从与旧主数据库相同的逻辑位置开始复制。备库提升为主库比较麻烦。我们将备库提升为主库分为计划内切换和计划外切换两种场景。1.将备库升级到计划内的主库,简单来说,有以下几个步骤:停止对旧主库的写操作。让备库赶上主库(可选,简化后续步骤)。将备用数据库配置为新的主数据库。将备用数据库和写操作指向新的主数据库,然后启用对主数据库的写入。但是上面的过程还有很多细节。某些情况可能取决于复制拓扑。更进一步,这里是大多数配置需要的步骤:停止当前master上的所有写操作。如果可能,最好关闭所有客户端程序(复制连接除外)。使用FLUSHTABLEWITHREADLOCK命令停止对主库的所有活动写入。也可以在主库上设置read_only选项。意味着从这一刻起,禁止对旧主库进行任何写操作。因为一旦切换新主库,旧主库的写入就意味着数据丢失。需要注意的是,即使设置了read_only,也不会阻止现有事务继续提交。因此,可以终止所有打开的事务,有效地结束所有写入。选择一个备用数据库作为新的主数据库,并确保它已经完全赶上主数据库(例如,让它执行所有从主数据库获取的中继日志)。确保新主库中的数据与旧主库中的数据一致。在新的master上执行STOPSLAVE。在新的主库上执行CHANGEMASTERTOMASTER_HOST='',然后执行RESETSLAVE断开与旧主库的连接,丢弃master.info中记录的信息(如果连接信息记录在my.cnf中),将无法正常工作,因此我们建议不要将复制连接信息写入配置文件)。执行SHOWMASTERSTATUS记录新主库的二进制日志坐标。确保其他备用数据库已赶上旧的主数据库。关闭旧的主库。将客户端连接到新的主服务器。在每个备库上执行CHANGEMASTERTO语句,使用之前获取的二进制日志坐标指向新的主库。2计划外切换当主库崩溃时,需要提升一个备库为主库。这个过程比较麻烦。如果只有一个备库,可以直接使用这个备库。但是如果有多个备用数据库,则需要做一些额外的工作。此外,还存在丢失复制事件的可能性。可能存在主数据库上发生的修改尚未更新到其任何备用数据库的情况。甚至有可能在主库上回滚了一条语句,但在备库上没有回滚,这样备库可能会??超过主库的逻辑复制位置。如果在某个时候可以恢复主数据库中的数据,则可以检索丢失的语句并手动执行它们。在下面的描述中,需要确保使用服务器中Master_Log_File和Read_Master_Log_Pos的值。2.1主备结构备库的升级决定了哪个备库有最新的数据。检查每个备用数据库上SHOW_SLAVE_STATUS命令的输出,并选择具有最新Master_Log_File和Read_Master_Log_Pos值的那个。让所有备库执行旧主库崩溃前获取的所有中继日志。在新的master上执行STOPSLAVE。对新的主库执行CHANGEMASTERTOMASTER_HOST='',然后执行RESETSLAVE,断开与旧主库的连接,丢弃master.info中记录的信息。执行SHOWMASTERSTATUS记录新主库的二进制日志坐标。比较每个standby和新master上Master_Log_File和Read_Master_Log_Pos的值。将客户端连接到新的主服务器。在每个备库上执行CHANGEMASTERTO语句,使用之前获取的二进制日志坐标指向新的主库。如果你在所有备库上都启用了log_bin和log_slave_updates,你可以将所有备库恢复到一个一致的时间点。如果不启用这两个选项,则很难做到这一点。上述过程中比较重要的一点是确定日志位置。接下来,让我们看看如何去做。3确定日志位置。如果备库和新主库的位置不同,需要在新主库的二进制日志中找到备库最后执行的事件对应的位置,然后执行CHANGEMASTERTO。可以使用mysqlbinlog工具找到备库上次执行的查询,然后在主库上找到相同的查询并进行简单的计算。为了便于描述,假设每个日志事件都有一个自动递增的数字ID。当旧主服务器崩溃时,新主服务器获得事件编号100,另外两个备用服务器:R2和R3。R2已获取事件99,R3已获取事件98。如果R2和R3都指向新主服务器上的相同二进制日志位置,它们将从事件101开始复制,导致数据不同步。但是只要通过log_slave_updates打开了新主库的二进制日志,就可以在新主库的二进制日志中找到事件99和100,从而使备库恢复到一致状态。由于服务器重启、不同配置、日志轮转或FLUSHLOGS命令,同一事件在不同服务器上可能具有不同的偏移量。我们可以使用mysqlbinlog从binarylog或者relaylog中解析出各个备库上执行的最后一个事件,也有这个命令可以解析新主库上的二进制文件找到相同的query,mysqlbinlog会打印出来该事件在CHANGEMASTERTO命令中使用该值。一种更快的方法是减去新主数据库和已停止备用数据库上的字节偏移量,这会显示字节位置的差异。然后从新主库的当前二进制日志位置减去这个值,得到预期的查询位置。让我们一起来看一个栗子。假设s1是s2和s3的主节点。s1崩溃的地方。根据SHOWSLAVESTATUS获取Master_Log_File和Read_Master_Log_Pos的值,s2已经执行完s1上的所有二进制日志,而s3还没有。如图1所示:我们可以确定s2执行完了主库上的所有二进制日志,因为Master_log_File和Read_Master_Log_Pos的值与s1上最后一条日志位置重合。所以我们可以将s2提升为新的主节点,并将s3设置为s2的备用节点。要在s3上执行的CHANGEMASTERTO语句应提供哪些参数?这里需要一点计算。s3在偏移量1493处停止,比s2执行的最后一条语句的偏移量1582少89个字节。s2在偏移量8167处写入二进制日志,因此理论上我们应该将s3指向偏移量8167-89=8078处的s2日志。最后在s2日志中的位置8078,确定这是否是正确的日志事件。如果验证没问题,可以通过以下命令将s3切换为s2的备库:CHANGEMASTERTOMASTER_HOST="s2host",MASTER_LOG_FILE="mysql-bin.000009",MASTER_LOG_POS=8078;如果服务器在崩溃时已经执行完成并记录了一个事件由于s2只被读取和执行到1582,事件a可能会丢失。但是如果旧主库的磁盘没有损坏,仍然可以通过mysqlbinlog或者从日志服务器的二进制日志中找到丢失的事件。总结备用升级区分计划内和计划外场景。备库升级时,找到新主库二进制日志的确切位置是关键。
