在集群间复制数据库

预览功能

跨集群数据库复制功能按“原样”(AS-IS)提供,具体如您与 Neo4j 的协议中所述,且仅应将其用于内部开发目的。

当此功能正式发布(Generally Available)后,您将需要升级到最新的 Neo4j 版本(可能需要停机)才能将该功能用于非开发用途。

在预览期内,拥有有效合同的客户可通过标准支持渠道联系 Neo4j 支持部门。请注意,根据支持条款,任何与此预览功能相关的案例默认将被归类为严重性 4 (Severity 4)。

概述

2026.03 版本引入了跨集群数据库复制 (CCDR)。它提供了将一个集群中的数据库复制到另一个集群的功能。原始数据库称为上游 (upstream)源 (source),而复制数据的数据库称为副本 (replica)。副本会持续轮询上游数据库以获取新事务,并在新事务可用时立即应用它们(参见图 1)。

replication
图 1. 跨集群复制数据库的架构

创建副本数据库的先决条件

假设您有两个独立运行的集群:集群 A集群 B

确保集群运行相同的 Neo4j 版本,且版本必须为 2026.03 或更高。

Cypher 的两个版本(Cypher 5 和 Cypher 25)均支持创建和提升副本数据库的过程。

在预览版本中,仅上游数据库和副本数据库支持 block 存储格式。

配置集群间加密

首先,确保每个集群都已使用集群内加密。为了确保集群 A集群 B 能够相互认证,每个集群都必须信任签署对方集群证书的证书颁发机构 (CA)。

如果集群使用不同的 CA,则必须将集群 A 的 CA 证书安装到集群 Btrusted/ 目录中,反之亦然。

例如,以下是一种可能的证书文件夹配置

ClusterA

cluster/
├── private.key                 ← clusterA node private key
├── public.crt                  ← clusterA node certificate
├── trusted/
│   └── clusterB-ca.crt         ← CA that signs ClusterB node certs
└── revoked/


ClusterB

cluster/
├── private.key                 ← ClusterB node private key
├── public.crt                  ← ClusterB node certificate
├── trusted/
│   └── clusterA-ca.crt         ← CA that signs ClusterA node certs
└── revoked/

创建副本数据库

使用以下步骤创建副本数据库。

表 1. internal.dbms.createReplicaDatabase()

语法

internal.dbms.createReplicaDatabase(databaseName, numPrimaries, numSecondaries, {remote: upstreamDatabaseName, addresses: remoteAddresses})

描述

创建一个具有主节点和从节点拓扑的副本数据库。

输入参数

名称

类型

描述

数据库名称 (databaseName)

STRING

当前集群中副本的名称。注意,databaseName 可以与 upstreamDatabaseName 相同。

numPrimaries

INTEGER(整数)

副本主节点的数量。这些主节点将符合服务器上设置的模式限制,但因为它们仍是副本,所以不可写入。

numSecondaries

INTEGER(整数)

副本从节点的数量。

upstreamDatabaseName

STRING

远程集群中上游数据库的名称。

remoteAddresses

LIST<STRING>

远程集群中服务器的集群端点列表。

模式

写入 (WRITE)

集群 A 上,数据库 foo 正在运行,并且有三台服务器,集群地址分别为:server01.example.com:6000, server02.example.com:6000, server03.example.com:6000

要在集群 B 上创建副本数据库 foo-replica(包含三个主节点和两个从节点),并从集群 A 的上游数据库 foo 进行复制,请运行以下过程

CALL internal.dbms.createReplicaDatabase("foo-replica", 3, 2, {remote: "foo", addresses:["server01.example.com:6000","server02.example.com:6000","server03.example.com:6000"]});

所有副本数据库均为只读。副本数据库可以拥有遵循服务器模式限制的主节点和从节点拓扑。然而,无论主节点还是从节点都保持只读状态。

只有当副本数据库能够联系到集群 A 的服务器,且上游数据库 foo 存在并正在运行时,该命令才能成功执行。否则,命令将报错。

验证 foo-replica 数据库是否在预期的服务器数量上以预期的角色在线。请注意,类型被标记为 replica

SHOW DATABASE foo-replica;
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| name          | type      | aliases | access       | address          | role         | writer | requestedStatus | currentStatus | statusMessage | default | home  | constituents|
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| "foo-replica" | "replica" | []      | "read-write" | "localhost:7687" | "primary"    | FALSE  | "online"        | "online"      | ""            | FALSE   | FALSE | []          |
| "foo-replica" | "replica" | []      | "read-write" | "localhost:7688" | "primary"    | FALSE  | "online"        | "online"      | ""            | FALSE   | FALSE | []          |
| "foo-replica" | "replica" | []      | "read-write" | "localhost:7689" | "primary"    | FALSE  | "online"        | "online"      | ""            | FALSE   | FALSE | []          |
| "foo-replica" | "replica" | []      | "read-write" | "localhost:7690" | "secondary"  | FALSE  | "online"        | "online"      | ""            | FALSE   | FALSE | []          |
| "foo-replica" | "replica" | []      | "read-write" | "localhost:7691" | "secondary"  | FALSE  | "online"        | "online"      | ""            | FALSE   | FALSE | []          |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

5 rows available after 3 ms, consumed after another 1 ms

通过驱动程序或 Cypher Shell 访问副本数据库

鉴于副本数据库是只读的,您必须确保驱动程序的 "AccessMode" 设置为 "READ",或者仅执行 executeRead。尝试向副本数据库写入数据将会失败。

此外,通过 Cypher Shell 访问数据库时,请确保在连接时将 --access-mode 也设置为 read

bin/cypher-shell --access-mode=read -a neo4j://:7684 -d foo-replica

这是必要的,因为我们所有的副本都是只读的。否则会导致无法找到 WRITE 服务器。

通过 Neo4j Browser 访问数据库时,请确保访问模式 (Access mode) 设置为 Read。这可以在 Browser 设置 (Settings) 抽屉中找到。

设置路由策略

副本数据库遵循内置的路由策略

示例 1

例如,如果您没有设置路由策略,查询 CALL dbms.routing.getRoutingTable({}, "foo-replica"); 将返回所有五台服务器作为读取器,且没有写入器。

+-------------------------------------------------------------------------------------------------------------------------------+
| ttl | servers                                                                                                                 |
+-------------------------------------------------------------------------------------------------------------------------------+
| 300 | [{addresses: ["localhost:7687", "localhost:7688", "localhost:7689", "localhost:7690", "localhost:7691"], role: "READ"}  |
+-------------------------------------------------------------------------------------------------------------------------------+
示例 2

如果您在 neo4j.conf 文件中设置 dbms.routing.reads_on_primaries_enabled=false 以禁用主节点上的读取,则路由策略会导致以下路由表,其中只有两个具有从节点角色的副本是读取器。

+-------------------------------------------------------------------------+
| ttl | servers                                                           |
+-------------------------------------------------------------------------+
| 300 | [{addresses: ["localhost:7690", "localhost:7691"], role: "READ"}  |
+-------------------------------------------------------------------------+

管理用户角色和权限

复制数据库时,不会复制用户权限和角色。

权限和基于角色的访问控制必须在集群 A集群 B 上单独设置,因为它们无法被复制。您应该将这两个集群视为独立的实体,仅在它们之间进行标准数据库复制。此外,system 数据库无法被复制。

监控副本数据库

副本从上游数据库异步复制数据。因此,跟踪上游数据库和副本数据库之间的复制延迟非常重要。为此,请绘制上游和副本数据库的 <prefix>.database.<db>.transaction.last_committed_tx_id 指标。此差异有效地体现了上游和副本之间的延迟。

灾难恢复场景

建议在两个不同的云区域中设置两个独立的集群。如果主区域发生故障,您可以提升灾难恢复集群 (DR-cluster) 中的复制数据库,并将数据流量重定向到提升后的数据库。

disaster step 1
图 2. 灾难
disaster step 2
图 3. 提升副本数据库
disaster step 3
图 4. 重定向数据流量

提升副本数据库

如果源集群变得不可用,您可以提升副本数据库以接受写入。

提升是一个单向操作。一旦副本被提升,它就无法再重新连接到原始源。要恢复复制,您需要创建一个新的副本。

可以通过两种方式提升副本:保留其拓扑或修改其拓扑。

在不修改拓扑的情况下提升副本数据库
表 2. internal.dbms.promoteReplicaDatabase()

语法

internal.dbms.promoteReplicaDatabase(replicaDatabaseName)

描述

将副本数据库转换为标准数据库,同时保留其当前拥有的数据和拓扑。

输入参数

名称

类型

描述

replicaDatabaseName

STRING

当前集群中即将被提升的副本名称。

模式

写入 (WRITE)

集群 B 上,要提升副本数据库 foo-replica(采用现有拓扑,即三个主节点和两个从节点),请调用此过程

CALL internal.dbms.promoteReplicaDatabase('foo-replica');

该数据库将变为可写入状态。

验证 foo-replica 数据库是否在预期的服务器数量上在线,且类型为 standard

SHOW DATABASE foo-replica;
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| name          | type       | aliases | access       | address          | role         | writer | requestedStatus | currentStatus | statusMessage | default | home  | constituents|
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| "foo-replica" | "standard" | []      | "read-write" | "localhost:7687" | "primary"    | TRUE   | "online"        | "online"      | ""            | FALSE   | FALSE | []          |
| "foo-replica" | "standard" | []      | "read-write" | "localhost:7688" | "primary"    | FALSE  | "online"        | "online"      | ""            | FALSE   | FALSE | []          |
| "foo-replica" | "standard" | []      | "read-write" | "localhost:7689" | "primary"    | FALSE  | "online"        | "online"      | ""            | FALSE   | FALSE | []          |
| "foo-replica" | "standard" | []      | "read-write" | "localhost:7690" | "secondary"  | FALSE  | "online"        | "online"      | ""            | FALSE   | FALSE | []          |
| "foo-replica" | "standard" | []      | "read-write" | "localhost:7691" | "secondary"  | FALSE  | "online"        | "online"      | ""            | FALSE   | FALSE | []          |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

5 rows available after 3 ms, consumed after another 1 ms

现在,其中一个主数据库已变为可写入,因为 writer 等于 TRUE。此时,我们的路由表将根据标准数据库返回写入器和读取器。

在修改拓扑的同时提升副本数据库

您可以使用以下过程在提升过程中更改副本的拓扑

Table 3. internal.dbms.promoteReplicaDatabaseWithTopology()

语法

internal.dbms.promoteReplicaDatabaseWithTopology(replicaDatabaseName, numPrimaries, numSecondaries)

描述

将副本数据库转换为具有新拓扑的标准数据库,同时保留其当前拥有的数据。

输入参数

名称

类型

描述

replicaDatabaseName

STRING

当前集群中即将被提升的副本名称。

numPrimaries

INTEGER(整数)

新的主节点数量。这些主节点将符合服务器上设置的模式限制,并将变为可写状态。

numSecondaries

INTEGER(整数)

新的副本从节点数量。

模式

写入 (WRITE)

您必须指定主节点或从节点的数量

CALL internal.dbms.promoteReplicaDatabaseWithTopology('foo-replica', 3, 4);

这将以三个主节点和四个从节点提升副本数据库。

故障恢复 (Failback)

故障恢复是在灾难恢复场景后使主集群恢复运行的过程。这假设提升后的数据库当前正在 DR 集群中运行。

要恢复之前的源数据库,请遵循以下步骤

  1. 在当前示例中,副本数据库的上游是 DR 集群(集群 B)中提升后的数据库 foo-replica(参见图 3)。
    在主集群(集群 A)中创建一个副本数据库 foo

    recovery
    图 5. 灾难后的恢复
  2. 停止集群 B 中提升后的数据库 foo-replica 的写入操作。

  3. 检查指标以确保提升后的数据库和复制数据库的 tx_id 完全相同。

  4. 提升集群 A 中的副本数据库 foo,这意味着该数据库开始处理写入操作,并再次成为处理流量的主数据库。

  5. 停止并删除 DR 集群中的数据库 foo-replica。创建一个新的副本 foo-new-replica,其上游指向主集群中的主数据库 foo(参见图 5)。

    replication restored
    图 6. 恢复主集群中的上游数据库