4

我有几台服务器运行自己的特定MySQL数据库实例,遗憾的是无法在复制/集群中设置。每个服务器将数据插入到几个与用户相关的表中,这些表之间有外键约束(例如useruser_vote)。以下是该过程的进行方式:

  1. 所有服务器都以相同的数据开始
  2. 每个服务器独立于其他服务器增长自己的数据集
  3. 定期地,来自所有服务器的数据手动合并在一起并应用回每个服务器(因此该过程从步骤 1 开始重复)。

这之所以成为可能,是因为除了其主键之外,该user表还包含一个唯一email字段,该字段允许识别每个数据库中已经存在哪些用户,并在更改主键和外键时合并新用户以避免冲突并维护正确的外键约束。它可以工作,但需要付出很大的努力,因为必须更改主键和外键以避免冲突,因此我的问题是:

有没有办法让每个服务器使用不与其他服务器冲突的主键来促进合并?

我最初想使用复合主键(例如server_idid),但我使用Doctrine的不支持由多个外键组成的主键,所以我的外键约束会出现问题。

我考虑过使用 aVARCHAR作为 anid并使用字符串的一部分作为前缀 (SERVER1-1,SERVER1-2, SERVER2-1, SERVER2-2 ...) 但我认为它会使数据库变慢我会必须对 id 进行一些操作(例如,在插入时,我必须解析现有 id 并提取最高值,增加它,将它与服务器 id 连接......)。

PS:另一种选择是通过从从属读取并写入到主控来实现复制,但由于复制滞后和主控上的单点故障等问题目前无法解决,因此该选项被丢弃。

4

2 回答 2

3

您可以确保每个服务器使用不同的自动增量增量和不同的起始偏移量:

将步骤 auto_increment 字段增量更改为

(假设您使用 auoincrements)

我只在两台服务器上使用过它,所以我的设置有一个带有偶数 ID,一个带有奇数。

当它们重新合并在一起时,只要您确保所有表都遵循上述想法,就不会发生冲突。

为了实现4台服务器

您会说,设置以下偏移量:

  • 服务器 1 = 1
  • 服务器 2 = 2
  • 服务器 3 = 3
  • 服务器 4 = 4

您可以这样设置增量(我使用 10 为额外的服务器留出空间):

  • 服务器 1 = 10
  • 服务器 2 = 10
  • 服务器 3 = 10
  • 服务器 4 = 10

然后在合并之后,在复制回每个服务器之前,您只需要更新每个表的 autoinc 值以再次获得正确的偏移量。假设每台服务器创建了 100 行,autoincs 将是:

  • 服务器 1 = 1001
  • 服务器 2 = 1002
  • 服务器 3 = 1003
  • 服务器 4 = 1004

由于有四台服务器,这确实变得棘手。假设某些表可能没有从特定服务器插入任何行。因此,您最终可能会得到一些表的最后一个 autoinc id 不是来自服务器 4,而是来自服务器 2。这将使计算任何特定表的下一个 autoinc 应该是什么变得非常棘手。

出于这个原因,最好在每个表中还包括一列,以记录插入任何行时的服务器编号。

id | field1 | field2 | ... | server

这样,您可以通过在任何表上选择以下内容轻松找出特定服务器的最后一个 autoinc 值:

SELECT MAX(id) FROM `table` WHERE `server`=4 LIMIT 0,1

使用此值,您可以在将合并的数据集滚动到相关服务器之前,重置每个服务器上每个表所需的下一个 autoinc 值。

UPDATE information_schema.tables SET Auto_increment = (
  SELECT MAX(id) FROM `table` WHERE `server`=s LIMIT 0,1
)+n WHERE table_name='table' AND table_schema = DATABASE();

s服务器编号在哪里并n设置为偏移量,所以在我的示例中它将是10.

于 2012-11-24T12:20:03.067 回答
1

前缀 ID 可以解决问题。至于数据库速度较慢 - 取决于那里提供的流量有多大。您还可以将“prefixed id”分成两列,“prefix”和“id”,它们可以是任何类型。需要一些逻辑来处理请求,但可能值得评估

于 2012-11-24T12:19:50.753 回答