我正在使用AWS RDS,因此无法在区域之间进行数据库复制。
我的应用程序用PHP编写并部署在所有地区,我正在寻找一种快速可靠的方法来实现这一目标。
我将建立MySQL连接:
SET @@ auto_increment_increment = NUMBER_OF_WRITEABLE_DATABASES;
SET @@ auto_increment_offset = REGION_ID;
所以AI pk在各个地区都是独一无二的。
我目前的计划是保留一个包含fields =>的查询日志表。 ID,查询,状态,USER_ID。它会在同一页面加载中将所有插入,更新,删除查询记录到查询字段中。
状态代码:
状态0 =>没有执行
状态1 =>在所有地区成功执行
状态2 =>失败
状态3 =>失败,受影响的行不匹配
示例行
ID =大于1 查询=> 插入配置文件值(1,{USER_ID},'用户名','电子邮件')## SEPERATOR ## AFFECTED_COUNT 更新用户设置last_modified ='2012-12 ...'其中id = {USER_ID} ## SEPERATOR ## AFFECTED_COUNT 状态= 0 USER_ID => {USER_ID}
并且将有一个守护进程读取记录状态!= 1并将在没有提交的所有区域上处理它们,一旦所有运行没有错误它将提交或回滚以防错误。
这就是我的想法和将要使用的。
我的问题是,对于这种情况,还是有更好的/经过测试的方法,或者我的方法是否存在任何问题。
提前致谢
答案 0 :(得分:2)
我最初的想法是,如果您尝试使用RDS作为在多个地区强制执行唯一记录ID的解决方案,那么您将走错路。我认为您可能想要重新考虑跨区域的唯一性的实际需求,或使用多个列强制实现唯一性(即自动增量加区域标识符)。这可以被读取并放入一些最终一致的数据存储中以供读取。
答案 1 :(得分: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收到删除时,服务器4将停止复制传入事件,因为"行受影响& #34;可能会有所不同。您的方案同样会失败。不同之处在于使用实际的MySQL复制,冲突事件发生后没有任何事情发生,所以在你解决冲突之前,至少你的数据不会因为上面讨论的顺序性和MySQL复制的事实而进一步分歧。遇到冲突时>完全停止。在主服务器环中,已停止复制的服务器继续从上游系统收集复制事件日志,但执行暂停并且该服务器上的数据将被冻结,除非在本地更改,直到解决冲突并重新启动复制为止。
另请注意,在您的方案中,您需要保留"来自"和"到"更新中每列的值,因为您不能回滚任何内容,除非您知道它回滚到。
需要注意的是,回滚需要实时发生,而不是以后发生。如果我在两个银行账户之间转账,并且由于某种原因转账需要回滚,我需要看到,当我使用银行的网站时 - 银行无法滚动那个交易在半夜回来只是因为他们的一个服务器在我的银行账户中有不同的余额。
以下是一个想法:在您的方案中,我正在转移的帐户"到#34;在所有服务器中都是一致的,但是我正在转移的帐户"来自"不是,那我想知道......你的设置是否会退出"来自"帐户,但保留在"到"帐户?我想可能会这样。
请注意,您受CAP theorem的限制。没有系统可以全局一致,可用并且容忍节点之间的隔离。充其量,你可以挑选任何两个。
有了这个想法,我的问题是:为什么全局系统中的所有节点都需要同步?如果主要原因是性能,请考虑部署单个全局主服务器的可能性,并在区域之间分配只读副本。使用两个数据库连接线程池编写应用程序,以便大多数SELECT
查询转到本地只读副本,而INSERT
,DELETE
,UPDATE
和{{1} (更新数据的存储过程)被发送到全局主服务器。那么,您最担心的事实是,您只有eventual consistency个读取副本。通过适当大小的服务器和编写良好的查询,这非常快(受光学和电子信号全球旅行的物理定律约束)但不是瞬时的。要完成此任务,您需要做的是最近对数据库进行更改的会话,其读取可能需要命中全局主数据 - 如果您下订单,则需要立即查看订单,因此主数据库可能是马上最好看的地方。后来,查看本地副本将起作用。由于存在跨区域问题,你仍然没有RDS的范围......但EC2上的MySQL非常合适。
只读副本在主服务器上施加非常小的负载,但是通过将单个只读副本连接到主服务器,然后将下游只读副本连接到该中间服务器,可以减轻此负载。
在主服务器和副本服务器上设置CALL
= 1将使计算机能够使用压缩连接来传输复制事件。根据所复制数据的性质,压缩和解压缩数据的延迟似乎无关紧要,我发现这个数据从3:1到10:1不等。
此外,您可以设置第二个主服务器,与主服务器相邻(可能在不同的A / Z中),将这两个服务器与主服务器重新链接相链接,将读取副本链接到第二个主服务器,使用自动增量适当增加和偏移,但在正常条件下不写入或读取到第二个主设备。你为什么要这样做?这样,您就拥有了第二个全局主服务器,可以通过重定向您的应用程序来访问它,以便在主服务器出现故障时立即投入使用。
当然,应用程序的性质在实际需要多少全局集成方面起着很大的作用。解决此问题需要您重新考虑应用程序的工作方式,以确定是否需要进行体系结构更改。
作为一名DBA,我不喜欢RDS对我施加的一些限制和灵活性限制。所有我真正得到的失控是一个相对容易的备份和时间点恢复...我喜欢...但是,对我来说,这些不能弥补限制。
脚注:在第3段中,我说"事务按照提交顺序在每台服务器上复制。"但这并不一定意味着它们被提交的真实世界的挂钟实际顺序......它实际上意味着它们相对于其提交的其他事务所提交给每个服务器的顺序。 server ...所以Server#1上的一个事务在Server#3上的另一个事务之前实际提交可能在#3之后而不是之前到达服务器#4,具体取决于事务通过服务器传播的时间长度#2并在服务器#3上提交。但是,这仍然足够真实"原则上,因为如果在服务器#3上感知#1上的事务与#3上发生的事件冲突,它实际上不会复制到#4,因为#3将停止复制。