0

我正在使用 AWS RDS,因此区域之间的数据库复制是不可能的。

我的应用程序用 PHP 编写并部署在所有区域,我正在寻找一种快速可靠的方法来实现这一目标。

我要建立 MySQL 连接:

SET @@auto_increment_increment= NUM​​BER_OF_WRITEABLE_DATABASES;

SET @@auto_increment_offset = REGION_ID ;

所以AI pk在所有地区都是独一无二的。

我目前的计划是保留一个查询日志表,其中包含字段 => id、queries、status、user_id。它将所有插入、更新、删除查询记录到同一页面加载的查询字段中。

状态码:

状态 0 => 未执行

状态 1 => 在所有区域上成功执行

状态 2 => 失败

状态 3 => 失败,受影响的行不匹配

示例行:

id=>1 个查询=> INSERT INTO PROFILES VALUES (1,{USER_ID},'Username','Email')##SEPERATOR##AFFECTED_COUNT UPDATE USERS SET last_modified='2012-12...' where id={USER_ID }##SEPERATOR##AFFECTED_COUNT 状态=0 user_id=>{USER_ID}

并且将有一个守护进程读取 status != 1 的记录,并将在所有区域上处理它们而不提交,一旦所有区域都运行没有错误,它将提交或回滚以防出错。

这就是我的想法并打算使用。

我的问题是该场景是否有更体面/经过测试的方法,或者我的方法有任何问题。

提前致谢

4

2 回答 2

2

我最初的想法是,如果您尝试使用 RDS 作为跨多个区域强制执行唯一记录 ID 的解决方案,那么您将走错路。我认为您可能需要重新考虑您对跨区域唯一性的实际需求或使用多个列(即自动增量加上区域标识符)强制唯一性。这可以被读取并放入一些最终一致的数据存储中以用于读取目的。

于 2012-12-26T16:56:04.883 回答
0

您正在做出值得称赞的努力,但正如其他评论者所说,由于多种原因,您的解决方案不可行。

您真的不想在会话级别使用 auto_increment_offset 和 auto_increment_increment。您想在服务器级别设置它们。如果 RDS 不允许您这样做,这就是 RDS 可能不是最佳解决方案的另一个原因。

如果我出来建议您在多主环中部署 MySQL 服务器(EC2,而不是 RDS)的全球网络,其中数据复制 1 => 2 => 3 => 4 => 1 并且每个服务器忽略传入的复制带有自己的服务器 ID 的消息,我的 MySQL DBA 同事会指责我失去了理智,让你陷入了难以管理的境地;但是,我相信这会容易得多解决方案比您建议的解决方案,因为至少,那么,世界各地的数据将以几乎与实际更改相同的顺序发生变化——这将减少来自多个位置的冲突更新的可能性。MySQL 复制是异步的,因为服务器 1 在向客户端返回成功(表明事务已提交)之前不会等待服务器 2 上的事务提交,但不要将该事实与它的事实混淆顺序的——事务按照提交的顺序在每台服务器上复制。(MySQL 5.6 中的新选项允许通过并行复制线程对此进行一些例外处理,但这对本次讨论并不重要)。

由于您已经设计了一个避免冲突的自动增量值的方案,您更大的问题可能来自更新和删除。在我刚刚描述的场景中,如果服务器 2 删除了一条记录,并且服务器 4 同时删除了同一条记录,那么服务器 4 将在收到来自服务器 2 的删除时停止复制传入事件,因为“受影响的行”将有所不同。您的方案同样会失败。不同之处在于,使用实际的 MySQL 复制,在冲突事件发生后什么也没有发生,所以在你解决冲突之前,至少你的数据不会因为上面讨论的顺序性质和 MySQL 复制完全停止的事实而进一步分化为不一致每当遇到冲突。在主服务器环中,已停止复制的服务器继续从上游系统收集复制事件日志,但执行停止并且该服务器上的数据被冻结,除非在本地进行更改,直到冲突解决并重新启动复制。

另请注意,在您的场景中,您需要在更新时为每一列保留“from”和“to”值,因为除非您知道它回滚到,否则您无法回滚任何内容。

值得注意的是,回滚需要实时发生,而不是稍后发生。如果我在两个银行账户之间转账,并且由于某种原因需要回滚,我需要在使用银行的网站时看到——银行不能在中间回滚该交易晚上只是因为他们的一个服务器在我的银行账户中有不同的余额。

这里有一个想法:在你的场景中,如果我转移“到”的帐户在所有服务器之间是一致的,但我转移“来自”的帐户不是,那么我想知道......你的设置是否会回滚从“from”账户,但将存款留在“to”账户?我认为可能。

请记住,您受到CAP 定理的限制。没有一个系统可以是全局一致的、可用的,并且可以容忍节点之间的隔离。充其量,您可以选择任何两个。

有了这个想法,我的问题是:为什么你的全局系统中的所有节点都需要同步?如果主要原因是性能,请考虑部署单个全局主服务器的可能性,其中只读副本分布在各个区域之间。使用两个数据库连接线程池编写应用程序,以便大多数SELECT查询转到本地只读副本,而INSERTDELETEUPDATECALL(更新数据的存储过程)发送到全局主服务器。那么,你最大的担心变成了你只有最终一致性的事实在只读副本上。使用适当大小的服务器和编写良好的查询,这是非常快的(受制于光学和电信号全球传播的物理定律),但它不是瞬时的。您必须做的是对于最近对数据库进行更改的会话,它们的读取可能需要访问全局主服务器——如果您下订单,您需要立即查看订单,因此主服务器可能是最好的地方,马上。稍后,查看本地副本将起作用。由于跨区域问题,您仍然超出 RDS 的范围......但是 EC2 上的 MySQL 非常适合。

只读副本对主服务器施加了非常小的负载,但即使是这种负载也可以通过将单个只读副本连接到主服务器,然后将下游只读副本连接到该中间服务器来减轻。

在主服务器和副本上设置slave_compressed_protocol= 1 将使机器能够使用压缩连接来传输复制事件。我发现这个比例在 3:1 到 10:1 之间,具体取决于被复制数据的性质,并且压缩和解压缩数据的延迟似乎微不足道。

此外,您可以设置第二个主控,与主主控相邻(可能在不同的 A/Z 中),将这两个服务器与主控复制链接,将只读副本链接到第二个主控,使用自动增量增量和偏移量适当,但在正常情况下不要写入或读取第二个主机。你为什么要这样做?这样,您就有了第二个全局主节点,如果主主节点发生故障,您可以通过重定向您的应用程序访问它来立即投入使用。

当然,您的应用程序的性质在实际需要多少全局集成方面起着重要作用。解决这个问题需要您重新考虑应用程序的工作方式,以确定是否需要进行架构更改。

作为一名 DBA,我不喜欢 RDS 强加给我的一些限制和灵活性约束。作为失去控制的回报,我真正得到的只是备份和时间点恢复的相对简单性……我喜欢……但是,对我来说,这些并不能弥补限制。


脚注:在第 3 段中,我说“事务按照提交的顺序在每个服务器上复制。” 但这并不一定意味着在现实世界的挂钟实际顺序中它们被提交......它实际上意味着它们被提交到每个服务器相对于该服务器提交的其他事务的顺序。 .. 因此,在服务器 #3 上的不同事务之前实际提交的服务器 #1 上的事务可能会在来自 #3 的事务之后而不是之前到达服务器 #4,具体取决于事务通过服务器 #2 传播所需的时间并在服务器 #3 上提交。然而,这在原则上仍然“足够真实”,因为如果 #1 上的事务在服务器 #3 上被认为与 #3 上发生的任何事情相冲突,

于 2012-12-28T17:23:41.240 回答