将主数据库复制到不同的从数据库

Replicate Master DB to Different Slaves

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

Dashboard type that has the details of each school. Can edit their information and other data.

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

Dashboard type that can only edit the specific school deployed in the local server. Can edit their information and other data.

现在我想要发生的是,如果有什么改变,在他们相应的学校同步 cloud to local server。这也适用于 local to cloud server.

Note: If you guys ever tried Evernote, that can edit the notes information on whatever device you're using and still be able to synchronize when you have internet or manually clicked synchronize.

When the local server doesn't have internet connection and edited some data in school. Once the internet is up, the data from local and cloud server should be synchronize.

That's the logic that I'm pursuing to have.

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

我还考虑使用 php 在整个 table 和与当前日期和时间相对应的数据中进行 foreach 循环。但我知道那会很糟糕。

已编辑: 我删除了关于此事的其他 SO 问题的参考/帖子。

我找到的应用挂钩是

服务器:

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

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

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

在你的例子中,每个奴隶经常会:

  1. 调用 master 的 web 服务(URL),比方说叫 'helloMaster'。它将传递学校名称(或某些特定标识符)、上次与主人成功同步的时间、身份验证详细信息(出于安全考虑),并期望主人回应自该日期以来主人是否对学校有任何更新假如。真的,这里的重点只是寻找确认主人可用并正在收听(即互联网仍然在线)。

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

  3. slave 然后调用一个网络服务,比方说 'getUpdates'。它传入学校名称、上次成功同步、安全身份验证详细信息和主机,然后将 return 传递给它三个数组,用于添加、更新和删除它拥有的任何记录,而这些记录是从属设备希望应用于其数据库的。

  4. 最后,一旦从服务器尝试更新其记录,它将通过另一个网络服务通知主服务器 success/failure,比如 'updateStatus'。如果成功,那么 master 将 return 一个新的同步日期供 slave 存储(这将与 master 在其 table 中存储的日期完全匹配)。如果失败,则错误将记录在主服务器中,暂停后我们返回步骤 1。

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

我可能会考虑再改进(或者其他人可能会编辑我的post)。

希望至少有所帮助。

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

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

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

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

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


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


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

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

有:

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

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

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

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

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

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

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

这里是主控复制的一些链接: 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

希望这对您有所帮助。

编辑:

原版本回答提出MongoDB;但是进一步阅读 MongoDB 对于不可靠的互联网连接来说并不是那么可靠。 CouchDB 专为离线文档而设计,这正是您所需要的——虽然它比 MongoDB 更难获得 gong,不幸的是。


原文:

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

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

原因如下 -

使用 MySQL 复制时出现问题

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

  • "Unique Key" 冲突会让你很头疼;最多 可能的原因是 "Auto Incrementing" 中常见的 ID MySQL 个应用程序(不要将它们用于同步操作,除非有 是一个明确的 "read+write"->"read-only" 关系 - 没有 在你的情况下。)
  • 主键必须由每台服务器生成,但在所有服务器中都是唯一的。可能通过添加服务器标识符和该服务器的唯一 ID 的组合(Server1_1、Server1_2、Server1_3 等不会与 Server2_1 冲突)
  • MySQL sync只支持on-way,除非你看看他们的集群解决方案(https://www.mysql.com/products/cluster/)。

执行时遇到问题 "manually" 为记录添加时间戳。

另一个答案建议保留 "Time Updated" 记录。虽然我采用了这种方法,但仍有一些大问题需要注意。

做日记时遇到问题"manually"。

日记会单独记录更改的内容和更改时间。 "Database X, Table Y, Field Z was updated to value A at time B" 或 "Table A had new record added with these details [...]"。这使您可以更好地控制要更新的内容。

  • 如果你看一下数据库同步技术,这实际上就是后台发生的事情;在 MySQL 的情况下,它保留更新的二进制日志
  • 您只会分享日记,绝不会分享原始记录。
  • 当另一台服务器收到日志条目时,如果对所发生的事情有更清晰的了解 before/after 并且可以重播更新并确保您获得正确的详细信息。
  • 当 journalling/database 失去同步时会出现问题(MySQL 发生这种情况时实际上很痛苦!)。您需要准备好一个 "refresh" 脚本,该脚本位于将数据库同步到主服务器的日志记录之外。
  • 这很复杂。所以...

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

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

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

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

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

  • Master/slave 复制,这是 MySQL 使用的。在这种模式下,所有写入都必须路由到单个 "master" 服务器,并且所有副本数据库都从主服务器接收更改提要。

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

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

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

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

MySQL 中的主控复制可以在使用 auto_increment 时在不违反密钥的情况下完成。这是一个 link 解释如何。

如果您的表没有主键,我不确定会发生什么(我总是在表上包含 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