管理集群中的数据库

在创建数据库或在创建后进行修改时,您可以为其选择 primary(主)和 secondary(从)的分配数量,即定义数据库的拓扑结构。要指定初始数据库拓扑,请使用 Cypher 命令 CREATE DATABASE。要在数据库创建后更改拓扑,请运行 ALTER DATABASE 命令。请注意,数据库角色必须与服务器的 modeConstraint 保持一致,该值可以是 PRIMARYSECONDARYNONE

如果不再需要某个数据库,可以使用 DROP DATABASE 命令将该数据库从集群中删除。

集群中的 system 数据库

system 数据库包含有关 DBMS 的元数据和安全配置。连接到此数据库时,您只能执行特定的管理任务,例如管理数据库、服务器和访问控制。

在集群环境中,system 数据库可以处于主模式或从模式。要配置其模式,请在 neo4j.conf 文件中使用 server.cluster.system_database_mode 设置。这必须在启动 Neo4j 进程之前完成。有关如何为 system 数据库选择模式的指南,请参阅 简介 → system 数据库的主从配置

首次部署集群时,请考虑配置 dbms.cluster.minimum_initial_system_primaries_count。此设置的默认值为 3。有关详细信息,请参阅 部署基础集群

有关如何恢复 system 数据库的信息,请参考 灾难恢复指南

创建数据库

在集群中创建标准数据库的命令与在非集群环境中创建数据库的命令没有太大区别。有关非集群环境中数据库管理的更多信息,请参阅 创建数据库

集群环境的区别在于可以指定数据库拓扑,即希望为数据库分配多少个主节点和从节点。有关建议的主从节点数量的更多详细信息,请参阅 简介:Neo4j 集群架构

要创建一个拥有三个主节点和两个从节点的数据库 foo,请运行以下 Cypher 命令

CREATE DATABASE foo TOPOLOGY 3 PRIMARIES 2 SECONDARIES

或者,您可以使用 参数 来提供主节点和从节点的数量

参数
{
  "dbname": "foo",
  "primary": 3,
  "secondary": 2
}
查询
CREATE DATABASE $dbname TOPOLOGY $primary PRIMARIES $secondary SECONDARIES

只有当集群中的服务器能够满足指定的拓扑结构时,该命令才能成功执行。如果不满足,命令将导致错误。例如,如果只有四台服务器,命令会因为错误而失败。同样,如果两台服务器被设置为仅限主模式(primary constraint),而三台服务器被设置为仅限从模式(secondary constraint),也会导致失败。

如果未指定 TOPOLOGY,数据库将根据 neo4j.conf 中指定的 initial.dbms.default_primaries_countinitial.dbms.default_secondaries_count 进行创建。集群启动后,您可以使用 dbms.setDefaultAllocationNumbers() 过程覆盖这些值。

CREATE DATABASE 命令会分配数据库,因此不需要运行 REALLOCATE DATABASES(在 在新增服务器上托管数据库 中有描述)。

但是,随着时间的推移,或者在执行了多次 CREATE DATABASE 命令后,数据库的分布可能会变得不平衡。此时,您可以运行 REALLOCATE DATABASES,让集群在属于该集群的所有服务器之间重新平衡数据库。

修改数据库拓扑和读/写访问权限

要在数据库创建后更改其拓扑或读/写访问权限,请使用 ALTER DATABASE 命令。

有关命令语法的详细信息,请参阅 修改数据库

修改数据库拓扑

要从之前的示例更改数据库 foo 的拓扑,请运行以下命令

ALTER DATABASE foo SET TOPOLOGY 2 PRIMARIES 1 SECONDARY

或者,您可以使用 参数 来提供主节点和从节点的数量

参数
{
  "dbname": "foo",
  "primary": 2,
  "secondary": 1
}
查询
ALTER DATABASE $dbname SET TOPOLOGY $primary PRIMARIES $secondary SECONDARIES

CREATE DATABASE 命令一样,如果集群中没有足够的服务器来满足请求的拓扑结构,ALTER DATABASE 命令会导致错误。

此外,ALTER DATABASE 是可选幂等的,如果数据库不存在,也会报错。可以在命令后添加 IF EXISTS,以确保在数据库不存在时不返回错误。

当指定的拓扑结构存在多种可能的排列组合时,Neo4j 会使用分配器来决定如何在集群中分散数据库。请注意,与 CREATE DATABASE 一样,ALTER DATABASE 命令会分配数据库,除非您希望在属于集群的所有服务器之间重新平衡数据库,否则无需执行 REALLOCATE DATABASES

这种情况通常发生在集群配置的服务器数量多于任何一个数据库的主节点和从节点数量之和时。

无法自动转换为仅具有一个主主机(primary host)的拓扑。尝试这样做会导致错误。

但是,可以手动进行此转换

  1. 第一步是备份数据库,有关详细信息,请参阅 备份与恢复

  2. 备份数据库后,下一步是删除该数据库。有关更多详细信息,请参阅 删除数据库

  3. 最后一步是从备份中以新拓扑结构引导集群,或者在单台服务器上恢复备份。有关引导的信息,请参阅下文的 引导集群

此外,可以自动仅有一个主主机的拓扑结构过渡到多个主主机的拓扑结构。请记住,在此类转换过程中,数据库会在短时间内不可用。

如果 ALTER DATABASE 命令减少了数据库的分配数量,则会优先移除 隔离服务器(cordoned servers) 上的分配。

查询
ALTER DATABASE nonExisting IF EXISTS SET TOPOLOGY 1 PRIMARY 0 SECONDARY

修改数据库访问权限

要修改对数据库 foo 的访问权限,语法如下

ALTER DATABASE foo SET ACCESS {READ ONLY | READ WRITE}

默认情况下,新创建的数据库同时具有读写访问权限。

取消分配数据库

为了减轻特定服务器的负载,您可以使用以下过程之一来取消分配数据库,从而将数据库从承受压力的服务器中移除

您必须拥有 SERVER MANAGEMENT 权限才能执行这些过程。

例如,server01 托管了两个小型数据库 foobar,以及一个非常大的数据库 baz,而其他服务器包含的数据库较少或较小,且 server01 负载过重。

您可以使用以下方法之一将 bazserver01 取消分配,或者从 server01 取消分配一定数量的数据库

从一台服务器取消分配数据库
// With dry run
neo4j@system> CALL dbms.cluster.deallocateDatabaseFromServer("server01", "baz", true);

// Without dry run
neo4j@system> CALL dbms.cluster.deallocateDatabaseFromServer("server01", "baz");
从多台服务器取消分配数据库
// With dry run
neo4j@system> CALL dbms.cluster.deallocateDatabaseFromServers(["server01", "server02"], "baz", true);

// Without dry run
neo4j@system> CALL dbms.cluster.deallocateDatabaseFromServers(["server01", "server02"], "baz");
从一台服务器取消分配三个数据库
// With dry run
neo4j@system> CALL dbms.cluster.deallocateNumberOfDatabases("server01", 3, true);

// Without dry run
neo4j@system> CALL dbms.cluster.deallocateNumberOfDatabases("server01", 3);

重新分配数据库

要重新平衡整个集群的数据库分配(例如,因为您添加了新服务器),请使用过程或 Cypher 命令将数据库重新分配到新服务器上。

使用过程重新分配数据库

您可以使用过程 dbms.cluster.reallocateDatabase 在集群中重新平衡特定数据库,或使用 dbms.cluster.reallocateNumberOfDatabases 在集群中重新平衡多个数据库分配并减轻超载服务器的压力。请注意,如果集群已经处于平衡状态,执行这些过程时不会进行重新分配。这些过程不需要服务器名称,并且可以在有或没有干运行(dry run)的情况下执行。

您必须拥有 SERVER MANAGEMENT 权限才能执行这些过程。

例如,您添加了三台新服务器,并希望将一个非常大的数据库 baz 从包含它的所有服务器移动到新服务器上。

将一个数据库重新分配到新服务器
// With dry run
neo4j@system> CALL dbms.cluster.reallocateDatabase("baz", true);

// Without dry run
neo4j@system> CALL dbms.cluster.reallocateDatabase("baz");
将多个数据库重新分配到新服务器
// With dry run
neo4j@system> CALL dbms.cluster.reallocateNumberOfDatabases(3, true);

// Without dry run
neo4j@system> CALL dbms.cluster.reallocateNumberOfDatabases(3);

使用 Cypher 命令重新分配数据库

您可以使用 Cypher 命令 REALLOCATE DATABASES 来重新平衡集群中的所有数据库分配并减轻超载服务器的压力。此命令也可以与 DRYRUN 一起使用,以预览新的数据库分配情况。

在拥有许多数据库的大型集群上运行 REALLOCATE DATABASES 可能会一次移动大量分配,这可能会给集群带来压力。建议从更有限的重新分配开始,例如使用较小数值的 dbms.cluster.reallocateNumberOfDatabases,并在再次调用之前等待数据库完成其重新分配,直到不再需要进行任何重新分配为止。

neo4j@neo4j> DRYRUN REALLOCATE DATABASES;
+----------------------------------------------------------------------------------------------------------------------------------------+
| database | fromServerName | fromServerId                           | toServerName | toServerId                             | mode      |
+----------------------------------------------------------------------------------------------------------------------------------------+
| "bar"    | "server-1"     | "00000000-27e1-402b-be79-d28047a9418a" | "server-5"   | "00000003-b76c-483f-b2ca-935a1a28f3db" | "primary" |
| "bar"    | "server-3"     | "00000001-7a21-4780-bb83-cee4726cb318" | "server-4"   | "00000002-14b5-4d4c-ae62-56845797661a" | "primary" |
+----------------------------------------------------------------------------------------------------------------------------------------+

引导集群

有两种不同的方法可以向集群中注入数据

  • 第一种选择是使用指定引导服务器(designated seeder),即将一台指定的服务器用于在集群中的其他服务器上创建备份数据库。

  • 另一种选择是从 URI 引导集群,即所有要托管数据库的服务器都会使用由该 URI 指定的外部来源中相同的种子进行引导。有关更多详细信息,请参阅 从 URI 创建数据库

请记住,在某些情况下使用指定引导服务器可能会出现问题,因为事先不知道数据库将如何分配给集群中的服务器。此外,此方法依赖于种子已经存在于其中一台服务器上。

指定引导服务器

为了将集群中的一台服务器指定为引导服务器,使用 neo4j-admin database restore 命令将数据库备份传输到该服务器。随后,该服务器将用作其他集群成员复制备份数据库的源。

此示例创建一个名为 foo 的用户数据库,托管在三台主模式服务器上。foo 数据库之前不应存在于集群中的任何服务器上。

如果已存在与备份同名的数据库,请使用 DROP DATABASE 命令将其及其关联的所有用户和角色删除。

  1. 在一台服务器上恢复 foo 数据库。在此示例中,使用 server01 成员。

    bin/neo4j-admin database restore --from-path=/path/to/foo-backup-dir foo
  2. 登录到 Cypher Shell 并运行 SHOW SERVERS 来查找 server01 的服务器 ID。对照地址找到服务器 ID。可以使用任何数据库进行连接。

    SHOW SERVERS YIELD serverId, name, address, state, health, hosting;
    +-----------------------------------------------------------------------------------------------------------------------------------------------------+
    | serverId                               | name                                   | address          | state     | health      | hosting              |
    +-----------------------------------------------------------------------------------------------------------------------------------------------------+
    | "25a7efc7-d063-44b8-bdee-f23357f89f01" | "25a7efc7-d063-44b8-bdee-f23357f89f01" | "localhost:7689" | "Enabled" | "Available" | ["system",  "neo4j"] |
    | "782f0ee2-5474-4250-b905-4cd8b8f586ba" | "782f0ee2-5474-4250-b905-4cd8b8f586ba" | "localhost:7688" | "Enabled" | "Available" | ["system",  "neo4j"] |
    | "8512c9b9-d9e8-48e6-b037-b15b0004ca18" | "8512c9b9-d9e8-48e6-b037-b15b0004ca18" | "localhost:7687" | "Enabled" | "Available" | ["system",  "neo4j"] |
    +-----------------------------------------------------------------------------------------------------------------------------------------------------+

    在这种情况下,server01 的地址为 localhost:7687,因此服务器 ID 为 8512c9b9-d9e8-48e6-b037-b15b0004ca18

  3. 在其中一台服务器上,使用 system 数据库并使用 server01 的服务器 ID 创建数据库 foofoo 的拓扑存储在 system 数据库中,创建时它将按照默认拓扑进行分配(可以通过 CALL dbms.showTopologyGraphConfig 查看)。这可能与 foo 备份时的拓扑不同。如果您想确保集群范围内的特定分配,可以在 CREATE DATABASE 命令中使用 TOPOLOGY 子句指定所需的拓扑。有关详细信息,请参阅 CREATE DATABASE

    CREATE DATABASE foo
    TOPOLOGY [desired number of primaries] PRIMARIES [desired number of secondaries] SECONDARIES
    OPTIONS {existingData: 'use', existingDataSeedServer: '8512c9b9-d9e8-48e6-b037-b15b0004ca18'};
  4. 验证 foo 数据库是否在所需的服务器数量上且以所需角色在线。如果 foo 数据库体积较大,命令执行可能需要一些时间。

    SHOW DATABASE foo;
    +------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | name  | type       | aliases | access       | address          | role      | writer | requestedStatus | currentStatus | statusMessage | default | home  | constituents |
    +------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | "foo" | "standard" | []      | "read-write" | "localhost:7687" | "primary" | FALSE  | "online"        | "online"      | ""            | FALSE   | FALSE | []           |
    | "foo" | "standard" | []      | "read-write" | "localhost:7688" | "primary" | FALSE  | "online"        | "online"      | ""            | FALSE   | FALSE | []           |
    | "foo" | "standard" | []      | "read-write" | "localhost:7689" | "primary" | TRUE   | "online"        | "online"      | ""            | FALSE   | FALSE | []           |
    +------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    
    9 rows available after 3 ms, consumed after another 1 ms

通过允许/拒绝数据库控制位置

默认情况下,数据库可以分配给集群中的任何服务器运行。但是,可以限制特定数据库托管的服务器。这可以通过 管理集群中的服务器 中描述的 ENABLE SERVERALTER SERVER 来实现。可以使用以下选项

  • allowedDatabases - 允许在服务器上托管的数据库集合。

  • deniedDatabases - 禁止在服务器上托管的数据库集合。允许和拒绝是互斥的。请注意,从 2025.12 开始,支持数据库名称模式(通配符),且最小字符数从 3 减少为 1

  • modeConstraint - 控制数据库可以在服务器上以何种模式(主、从或无)托管。如果未设置,则服务器上没有模式约束。

集群中的默认数据库

initial.dbms.default_database 定义的默认数据库在 DBMS 首次启动时自动创建。这提供了一个用户数据库供立即实验。但是,由于以下原因,这种创建是“尽力而为”的,我们鼓励用户为生产使用创建自己的默认数据库。如果您创建自己的默认数据库,即使只是运行 DROP DATABASE neo4jCREATE DATABASE neo4j,也不必了解以下的复杂性。

自动创建默认数据库

初始默认数据库在 DBMS 首次启动时创建。它使用以下设置

但是,它将默认的主从数量(拓扑)作为最大值,而不是硬性要求。这与普通数据库创建不同,后者如果无法满足请求的拓扑结构,创建将失败。仅对于默认数据库的自动创建,如果无法满足请求的拓扑,您将获得当前集群所能满足的尽可能多的主机类型数量。这意味着,尽管默认值较高,您最终可能得到一个仅有一个主节点且没有从节点的默认数据库。也可以配置一个集群,使得在 DBMS 启动时无法自动创建默认数据库。在这种情况下,创建失败,会记录一条警告,并且不会再尝试创建

初始默认数据库的自动创建过程如下

  • 当集群首次启动时,存在一个创建 DBMS 所需服务器数量的配置阈值 - dbms.cluster.minimum_initial_system_primaries_count

  • 一旦至少这么多服务器相互发现,system 数据库就会引导,从而允许创建 DBMS。

  • 初始默认数据库将以这些服务器作为可能的宿主进行创建。

  • 如果有任何服务器阻止托管默认数据库(请参阅 initial.server.denied_databases),它们将不会被使用。

  • 如果有任何服务器限制了其托管数据库的模式,则会遵守该限制(请参阅 initial.server.mode_constraint)。

  • 如果服务器数量太少,无法分配请求的主节点数量,则会使用所有可用的服务器。如果没有可用的主节点,则自动创建失败。

  • 如果在主节点分配后剩余的服务器不足以满足请求的从节点数量,则会使用所有可用的服务器。

由于上述方法,可能会观察到一些行为

  • 如果 initial.dbms.default_primaries_count 大于 dbms.cluster.minimum_initial_system_primaries_count,您很可能会得到一个初始默认数据库,其主节点数量少于默认值。这是因为 DBMS 初始化只等待最小数量的系统主节点。

  • 如果 initial.dbms.default_secondaries_count 加上 initial.dbms.default_primaries_count 大于 dbms.cluster.minimum_initial_system_primaries_count,您很可能会得到一个初始默认数据库,其从节点数量少于默认值。这是因为 DBMS 初始化只等待最小数量的系统主节点。

  • 如果您使用 initial.server.denied_databases 来防止将默认数据库分配给您的任何初始服务器,您最终得到的数据库副本数量可能会少于默认请求,甚至可能没有默认数据库。

  • 如果您对任何初始服务器使用 initial.server.mode_constraint=SECONDARY,您最终得到的主数据库副本数量可能会少于默认请求,甚至可能没有默认数据库。

更改默认数据库拓扑

如果默认数据库最初创建时的拓扑结构不是您想要的,您可以像对待任何数据库一样更新它,请参阅 修改拓扑

更改默认数据库

您可以使用过程 dbms.setDefaultDatabase("newDefaultDatabaseName") 来更改 DBMS 的默认数据库。从 Neo4j 2025.04 开始,默认数据库也可以设置为本地或远程数据库别名。

  1. 确保要设置为默认的数据库已经存在,否则请使用 CREATE DATABASE <database-name> 命令创建它。从 2025.04 开始,这不是强制性的,因为默认数据库可以设置为尚不存在的数据库。

  2. 使用 SHOW DEFAULT DATABASE 命令显示当前默认数据库的名称和状态。

  3. 使用 STOP DATABASE <database-name> 命令停止当前默认数据库。

  4. 针对 system 数据库运行 CALL dbms.setDefaultDatabase("newDefaultDatabaseName") 以设置新的默认数据库。

  5. (可选)您可以使用 START DATABASE <database-name> 将之前的默认数据库作为非默认数据库启动。

处理错误

数据库可能会进入错误状态。通常您可以使用 SHOW DATABASES 命令观察到这一点,并使用 错误处理指南 来获得帮助。

在更严重的情况下,您可能面临灾难情况,即整个 DBMS 可能无法正确响应,或者某些特定数据库在没有停机的情况下无法恢复。针对这些情况,请参阅 灾难恢复指南