我有几个服务器在运行它们自己的特定MySQL
数据库实例,不幸的是,这些数据库无法在复制/集群中设置。每个服务器将数据插入到几个用户相关的表中,这些表之间具有外键约束(例如user
、user_vote
)。这个过程是这样进行的:
- 所有服务器都以相同的数据启动
- 每个服务器独立于其他服务器增长自己的数据集
- 周期性地,来自所有服务器的数据被手动合并在一起,并应用回每个服务器(因此,该过程从步骤1开始重复)
之所以能够做到这一点,是因为除了主键之外,user
表还包含一个唯一的email
字段,该字段允许识别每个数据库中已经存在的用户,并在更改主键和外键时合并新用户,以避免冲突并保持正确的外键约束。这是可行的,但这需要付出相当大的努力,因为必须更改主键和外键以避免冲突,因此我的问题是:
是否有一种方法可以让每个服务器使用不与其他服务器冲突的主键来促进合并
我最初想使用复合主键(例如server_id
、id
),但我使用的Doctrine
不支持由多个外键组成的主键,所以我的外键约束会有问题。
我曾想过使用VARCHAR
作为id
,并使用字符串的一部分作为前缀(SERVER1-1、SERVER1-2、SERVER2-1、SERVER2-2…),但我认为这会使DB变慢,因为我必须对id进行一些操作(例如,在插入时,我必须解析现有id并提取最高id,递增id,将其与服务器id连接…)。
PS:另一个选项是通过从机读取和向主机写入来实现复制,但由于复制滞后和主机上的单点故障等问题,该选项已被放弃,目前无法解决
您可以确保每个服务器使用不同的自动增量增量和不同的起始偏移量:
通过更改步骤自动增量字段
(假设您使用的是加密货币)
我只在两台服务器上使用过这个,所以我的设置有一台ID为偶数,一台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
。
预混合ID就可以了。至于DB的速度较慢,这取决于那里的流量有多大。您还可以将"前缀id"拆分为两列,"前缀"one_answers"id",它们可以是任何类型。需要一些逻辑来处理请求,但可能值得评估