如何重新同步 AWS RDS 只读副本

How to re-sync AWS RDS read replica

有没有办法修复已停止与主数据库同步的只读副本?我已经在删除它并创建一个新的,因为我找不到这个答案,但很高兴知道它是否再次发生。

数据库是一个 MySQL 带有 Innodb 表的数据库。

MySQL复制背后的原理很简单:如果您从两个相同的数据集开始,并且每次更改一个时,都会更改另一个,那么这两个数据集将保持相同。这就是 MySQL 复制的工作原理——您从两台相同的服务器开始,要么完全空白,要么一台是另一台的精确快照,然后复制在两台服务器上执行相同的操作。

复制是通过二进制日志 ("binlog") 完成的,它捕获对主服务器的所有更改。在标准 MySQL 异步复制中——如在 RDS 中使用的那样——副本有两个特定用途的线程,I/O 线程连接到主服务器并从主服务器的二进制日志中捕获复制事件并写入它们到称为 中继日志 的临时保存区域,以及从中继日志读取并将更改应用到副本的 SQL 线程。

在副本上,查询 SHOW SLAVE STATUS; 会告诉您这两个线程是否 运行。如果它们是 运行,则副本是健康的,尽管它可能落后于主副本,正如您在该查询的输出中也可以找到的值 Seconds_Behind_Master 所证明的那样。否则,您会发现遇到的错误导致一个或另一个线程停止。

理论上,MySQL 副本永远不会不同步,除非发生以下三种情况之一:

  • 你做了一些你不应该做的事情,使副本与主副本不一致 -- 例如使副本可写,然后写入它。
  • MySQL 源代码中存在导致不一致的错误
  • 副本与主服务器断开连接的时间足够长,以至于主服务器已经丢弃了一些副本从未见过的复制事件。

第一个问题将导致 SQL 线程停止,因为它试图应用无意义的更改——通常是删除不存在的行,更新不存在或不存在的行t匹配,插入一个已经存在的行等

第二个问题可能会导致 IO 线程或 SQL 线程出现问题,但这种情况很少见。

最后一个问题将导致 IO 线程停止,因为它会记住它在 master 上停止的位置,如果此时 master 上没有可用的二进制日志文件,它就会陷入僵局。 RDS 应该通过将日志保存在主服务器上直到所有托管副本都捕获它们来防止这种情况。

因此,一般 答案是,您可以修复 MySQL 只读副本,方法是将其所有数据完全置于其应有的状态,基于在中继日志中,复制 SQL 线程当前指向的时间点上主服务器的状态。

这在 RDS 中有点棘手,因为您没有 SUPER 权限,但它仍然是可能的。还是...

tl;dr:复制中断只是一种症状——您必须弄清楚实际问题是什么。

您需要能够识别出了什么问题,并采取措施加以纠正。问题是,当复制停止时,除非您非常清楚地了解到底发生了什么,否则您实际上并不知道副本上的情况有多糟糕。

回想上面提到的原理——从两个相同的数据集开始,每次改变一个,改变另一个——接下来要注意的是MySQL没有任何构建- 在没有实际复制错误的情况下确保一致性的机制。两台服务器可能存在巨大差异,但复制将愉快地继续,直到 SQL 线程遇到无法复制的内容。您需要可以比较两台服务器上的数据并指出任何差异的第三方实用程序。

如果您清楚地了解出了什么问题,您可以暂时使副本可写(使用 read_only 系统变量的参数组设置),进行更正更改,然后重新启动复制。在 RDS 上,您只能通过重新启动副本在当前事件指针处重新启动,因为您没有 SUPER 权限,或者您可以将副本恢复到它应该处于的状态 有问题的事件被复制之后,然后使用他们为此提供的解决方法,使用 CALL mysql.rds_skip_repl_error();不要在不了解它的作用的情况下使用它——具体来说,它会忽略失败并继续进行下一个事件,绝对会使您的副本处于不一致状态,除非您手动将副本带入持续的。它应该只保留用于紧急情况,当保持副本最新比保持副本正确更重要时,因为跳过错误本质上保证将来会出现更多错误。

修复复制品并非易事。这是有经验的 DBA 的任务。在 RDS 中,最好的选择通常是丢弃副本并创建一个新副本,但由于复制错误永远不会发生——这不是您应该做的事情。如果这样做,您需要找出原因。