【问题标题】:Replicate Master DB to Different Slaves将主数据库复制到不同的从站
【发布时间】:2017-02-15 22:58:32
【问题描述】:

我有一个主数据库,它是由不同学校组成的云服务器。

具有每所学校详细信息的仪表板类型。可以编辑他们的信息和其他数据。

现在这些学校被部署到他们相应的学校位置,这将是本地服务器。

只能编辑部署在本地服务器中的特定学校的仪表板类型。可以编辑他们的信息和其他数据。

现在我想要发生的事情是,如果有变化,在他们对应的学校同步cloud to local serverlocal to cloud server 也是如此。

注意:如果你们曾经尝试过 Evernote,它可以在您使用的任何设备上编辑笔记信息,并且仍然可以 当你有互联网或手动点击同步时同步。

当本地服务器没有互联网连接并在学校编辑了一些数据时。一旦互联网启动,本地和云服务器的数据应该同步。

这就是我追求的逻辑。

谁能告诉我从哪里开始?我想不出任何适合我的问题的解决方案。

我还考虑使用 php 来遍历整个表和与当前日期和时间相对应的数据的循环。但我知道那会很糟糕。

已编辑:我删除了有关此问题的其他 SO 问题的引用/帖子。

我找到的应用程序挂钩是

  • 印象笔记
  • Todoist

服务器:

  • 本地服务器计算机:Windows 10(学校部署)
  • 云服务器:可能是一些使用phpmyadmin的专用主机

不要挑剔,但希望答案是您正在与新手交谈以掌握从数据库过程。我没有这方面的经验。

【问题讨论】:

标签: php mysql phpmyadmin database-replication


【解决方案1】:

当我们过去这样做时,我们会:

  1. 确保我们要同步的每个表都有 Created 的日期时间列;修改的; & 已删除。他们还将有一个布尔 isDeleted 列(因此,我们不会物理删除记录,而是将其标记为 true 并在查询中忽略它)。这意味着我们可以查询自特定时间以来已删除的任何记录,并返回这些已删除 ID 的数组。
  2. 在每个数据库(主从)中创建一个表来存储上次成功同步的日期时间。在 master 中,此表存储多条记录:每所学校 1 条,但在 slave 中只需要 1 条记录 - 它最后一次与 master 同步。

在你的情况下,每个奴隶经常会:

  1. 调用主服务器的 Web 服务(URL),可以说是“helloMaster”。它将传递学校名称(或某些特定标识符)、他们最后一次与主服务器成功同步的时间、身份验证详细信息(出于安全考虑)并期望主服务器响应自该日期时间以来主服务器是否有任何学校更新假如。真的,这里的重点只是寻找一个确认主人可用并正在收听(即互联网仍在运行)。

  2. 然后,slave 会调用另一个 web 服务,比如说“sendUpdates”。它将再次传递学校名称、上次成功同步、(加上安全身份验证详细信息)和三个数组,用于自上次同步以来添加、更新和删除的记录。主人只是确认收到。如果收到确认,则从站移动到步骤 3,否则从站将在暂停一段时间后再次尝试步骤 1。所以现在主服务器有来自从服务器的更新。注意:如果与其挂起的从属更新发生冲突,则由主控决定如何合并任何记录。

  3. slave 然后调用一个 web 服务,比如说“getUpdates”。它传入学校名称、上次成功同步、安全认证详细信息和主服务器,然后返回三个数组,以获取它所拥有的任何添加、更新和删除的记录,从服务器预计将应用于其数据库。

  4. 最后,一旦从站尝试更新其记录,它将通过另一个 Web 服务通知主站成功/失败,例如“updateStatus”。如果成功,则主服务器将返回一个新的同步日期供从服务器存储(这将与主服务器存储在其表中的日期完全匹配)。如果失败,则错误会记录在 master 中,我们会在暂停后返回第 1 步。

我遗漏了一些关于错误处理的细节,在所有设备上获得准确的时间(可能涉及不同的时区),以及其他一些细节,但这就是要点。

我可能会在考虑更多之后进行改进(或者其他人可能会编辑我的帖子)。

希望至少能有所帮助。

【讨论】:

  • 如果您确实需要关注时钟差异(您可能会关注),那么当从服务器从掌握。然后,在学校数据库中搜索更新记录时,您的查询可以包含这两次之间的任何偏移量。
【解决方案2】:

我会建议你使用简单的解决方案,根据我的说法是:

  1. 在本地服务器中创建 SQLlite 或任何数据库(MySQL 或您的选择)
  2. 保持一个始终运行的线程,该线程将每 5 分钟 ping 一次(进行 API 调用)您的 Master 数据库(取决于接受的延迟时间)
  3. 使用该线程,您可以检测您是否已连接到互联网。
  4. 如果连接到互联网

    a) 将本地更改与请求一起发送到主服务器,该主服务器是一个应用服务器,它能够将学校本地机器的更改(您通过 API 调用收到此更改)更新到主数据库根据您的应用程序使用情况进行某些验证。

    b) 在 API 调用后从服务器接收更新的更改,这些更改在解决冲突后提供(例如,如果学校服务器中的数据更新早于主数据库中的数据更新,那么您将根据您的要求接受哪一个) .

  5. 如果未连接到互联网,请继续将更改存储在本地数据库中,并将这些更改反映在学校运行的应用程序中,但是当您连接时,将这些更改推送到主服务器并拉出 实际更改,即适用从主服务器。


你自己做这件事很复杂,但如果规模很小,我更愿意为将以这种方式连接的数据库应用程序实现你自己的 API。


更好的解决方案是使用 Google Firebase,它是一个实时数据库,只要任何机器发生变化,它就会异步更新,但如果真的不需要,它的成本可能会更高。但是是的,它真的会为您的数据库系统提供 Evernote 类型的实时编辑功能。

【讨论】:

    【解决方案3】:

    无需任何复杂的设置或 API。 MySQL 允许您轻松复制数据库。 MySQL 将确保在互联网可用时正确及时地完成复制。 (而且速度也很快)

    有:

    1. 主 - 从:主编辑从读取,或者换句话说,从主到从的单向同步。
    2. Master - Master:Master1 编辑 master2 读取和编辑,或者换句话说,双向同步。两台服务器都会推送和拉取更新。

    假设您的云服务器具有每个学校的架构,并且每个架构都可以通过其自己的用户名和密码访问。即 db_school1, db_school2

    现在您可以选择仅将选定的数据库架构从您的云复制到本地主机。在你的情况下,学校的本地主人只会“复制db_school1”

    如果您只想复制特定的表,MySQL 也有该选项“replicate-do-table”

    实际的复制过程非常简单,但当您有不同的场景时可能会变得非常深入。

    您需要注意的几件事、服务器 ID、每台服务器上不同的自动增量值,以避免与新记录发生冲突。即 Master1 生成奇数记录,Master 2 生成偶数记录,因此不会出现重复的主键问题。服务器停机警报/监控、错误跳过

    我不确定您使用的是 linux 还是 windows,我编写了简单的 c# 应用程序,它检查是否有任何 master 没有复制或因任何原因停止并发送电子邮件。监控至关重要!

    这里有一些主主复制的链接: https://www.howtoforge.com/mysql_master_master_replication

    https://www.digitalocean.com/community/tutorials/how-to-set-up-mysql-master-master-replication

    还值得一读这个优化的表级复制信息: https://dba.stackexchange.com/questions/37015/how-can-i-replicate-some-tables-without-transferring-the-entire-log

    希望这会有所帮助。

    【讨论】:

      【解决方案4】:

      编辑:

      这个答案的原始版本提出了 MongoDB;但是通过进一步阅读,MongoDB 在互联网连接不可靠的情况下并不那么可靠。 CouchDB 是为离线文档而设计的,这正是您所需要的——尽管不幸的是,它比 MongoDB 更难获得。


      原文:

      我建议不要使用 MySQL,而是部署一个专为复制而设计的文档存储,例如 CouchDB - 除非您使用商业 MySQL 集群服务。

      作为 MySQL 强大功能的爱好者,我发现很难建议您使用其他东西,但在这种情况下,您确实应该这样做。

      这就是为什么 -

      使用 MySQL 复制的问题

      为什么 MySQL 具有良好的复制能力(如果您正在同步 MySQL 数据库,这很可能是您应该使用的 - 正如其他人所推荐的那样)有一些事情需要注意。

      • “唯一键”冲突会让你头疼;最多 可能的原因是“自动递增”ID 在 MySQL 应用程序(不要将它们用于同步操作,除非有 是一个明确的“读+写”->“只读”关系——没有 在你的情况下。)
      • 主键必须由每个服务器生成,但在所有服务器中是唯一的。可能通过添加服务器标识符和该服务器的唯一 ID 的组合(Server1_1、Server1_2、Server1_3 等不会与 Server2_1 冲突)
      • 除非您查看他们的集群解决方案 (https://www.mysql.com/products/cluster/),否则 MySQL 同步仅支持 on-way。

      “手动”为记录添加时间戳时存在问题。

      另一个答案建议保留“时间更新”记录。虽然我采用了这种方法,但仍有一些大问题需要小心。

      使用日记“手动”执行此操作存在问题。

      日志会单独记录更改的内容和时间。 “数据库 X、表 Y、字段 Z 在时间 B 已更新为值 A”或“表 A 添加了带有这些详细信息的新记录 [...]”。这使您可以更好地控制要更新的内容。

      • 如果您查看数据库同步技术,这实际上是在后台发生的;在 MySQL 的情况下,它会保存更新的二进制日志
      • 您只共享日志,绝不共享原始记录。
      • 当另一台服务器收到日志条目时,如果能够更全面地了解之前/之后发生的事情,并且可以重播更新并确保您获得正确的详细信息。
      • 当日志/数据库不同步时会出现问题(发生这种情况时,MySQL 实际上很痛苦!)。您需要准备好一个“刷新”脚本,该脚本位于将数据库同步到主数据库的日志之外。
      • 这很复杂。所以...

      解决方案:使用专为复制而设计的文档存储,例如MongoDB

      考虑到这一切,为什么不使用已经为您完成所有这些工作的文档存储呢? CouchDB 支持并处理所有日志和同步 (http://docs.couchdb.org/en/master/replication/protocol.html)。

      还有其他解决方案,但我相信与其他解决方案相比,您最终会遇到更少的麻烦和错误。

      【讨论】:

        【解决方案5】:

        这不是数据库复制可以解决的问题。

        一般来说,数据库复制可以以两种模式之一运行:

        • 主/从复制,这是 MySQL 使用的。在这种模式下,所有写入都必须路由到单个“主”服务器,并且所有副本数据库都接收来自主服务器的更改馈送。

          这不适合您的需求,因为只能对主服务器进行写入。 (直接修改其中一个副本会导致它与主副本永久不同步。)

        • 基于仲裁的复制,被一些较新的数据库使用。所有数据库副本相互连接。只要至少有一半的副本已连接(即集群已达到“法定人数”),就可以对任何活动数据库进行写入,并将传播到所有其他数据库。未连接的数据库将在加入仲裁时更新。

          这也不适合您的需求,因为无法写入断开连接的副本。更糟糕的是,超过一半的副本与主服务器断开连接会阻止其余数据库被写入其中一个!

        您需要某种数据同步解决方案。任何解决方案都需要一些逻辑——你必须编写! ——解决冲突。 (例如,如果在学校的本地副本断开连接的情况下在主数据库中修改了一条记录,并且在那里也修改了相同的记录,您将需要一些方法来协调这些差异。)

        【讨论】:

        • 是的,我也是这么想的。这里用主从不符合我的标准,想澄清一下是否有这种功能。但我想知道师父对师父。正在寻找可以帮助我使用可以提供其功能的服务的答案。但如果一切都失败了,就像你说的那样,我必须写它。似乎@KScandrett 的回答对我来说似乎是合乎逻辑的并且在短时间内可行。
        【解决方案6】:

        在使用 auto_increment 时,可以在 MySQL 中完成主到主复制而不会发生密钥冲突。这是一个解释方法的链接。

        如果您的表没有主键,我不确定会发生什么(我总是在表中包含 auto_increment 主键)

        http://brendanschwartz.com/post/12702901390/mysql-master-master-replication

        auto-increment-offset 和 auto-increment-increment 影响 auto_increment 值,如文章中的配置示例中所示...

        server_id           = 1
        log_bin             = /var/log/mysql/mysql-bin.log
        log_bin_index       = /var/log/mysql/mysql-bin.log.index
        relay_log           = /var/log/mysql/mysql-relay-bin
        relay_log_index     = /var/log/mysql/mysql-relay-bin.index
        expire_logs_days    = 10
        max_binlog_size     = 100M
        log_slave_updates   = 1
        auto-increment-increment = 2
        auto-increment-offset = 1
        
        server_id           = 2
        log_bin             = /var/log/mysql/mysql-bin.log
        log_bin_index       = /var/log/mysql/mysql-bin.log.index
        relay_log           = /var/log/mysql/mysql-relay-bin
        relay_log_index     = /var/log/mysql/mysql-relay-bin.index
        expire_logs_days    = 10
        max_binlog_size     = 100M
        log_slave_updates   = 1
        auto-increment-increment = 2
        auto-increment-offset = 2
        

        【讨论】:

        • 嗨,欢迎来到 Stack Overflow。虽然始终欢迎提供有用的外部资源的链接,但也请引用您要链接到的页面的关键摘录。这样一来,如果网站出现故障或页面被(重新)移动,那么这个答案就不会变得无用
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多