知识库

如何解决集群实例上的不一致问题

(如果您使用的是 HA (高可用性),请阅读并将 MasterSlave 分别理解为 LeaderFollower)

有时,在运行 Neo4j 集群环境时,从库 (slave) 的存储可能会出现不一致。在正常的日常操作中,如果 slave 变得不一致,它会自动尝试通过从 master 实例获取数据来解决该问题。然而,有时这可能无法实现。例如,如果 slave 离线时间过长,可能导致 master 实例上的事务日志文件缺失,从而无法在 slave 实例上重放所有事务,导致其无法追赶进度。这将导致 slave 因存储不一致而无法加入集群。如果发生这种情况,可以使用以下步骤利用来自 master 实例的完整备份来完全恢复 slave 的存储。

由于此操作具有风险,我们建议在执行前务必先提交技术支持工单。

步骤

  1. 识别日志文件中的错误

  2. 识别主库 (master) 实例

  3. 在 master 上运行备份

  4. 将备份移动到故障 slave

  5. 停止实例

  6. 备份旧存储 [可选]

  7. 恢复备份

  8. 启动实例

  9. 清理旧文件 [可选]

1. 识别日志文件中的错误

2017-02-12 15:33:37.334+0000 INFO  [o.n.k.h.c.SwitchToSlaveBranchThenCopy] The store is inconsistent. Will treat it as branched and fetch a new one from the master
2017-02-12 15:33:37.334+0000 WARN  [o.n.k.h.c.SwitchToSlaveBranchThenCopy] Current store is unable to participate in the cluster; fetching new store from master The master is missing the log required to complete the consistency check

2. 识别主库 (master) 实例

如果您运行的是高可用性 (HA) 集群

我们可以使用 HTTP 端点来发现哪个实例是 master:/db/manage/server/ha/master。从命令行来看,查询这些端点的一种常用方法是使用 curl。如果不加参数,curl 将对提供的 URI 执行 HTTP GET 请求并输出响应主体文本(如果有)。如果您还想获取响应代码,只需添加 -v 标志即可获得详细输出。

$ curl -v localhost:7474/db/manage/server/ha/master
*   Trying 127.0.0.1
* Connected to localhost (127.0.0.1) port 7474 (#0)
> GET /db/manage/server/ha/master HTTP/1.1
> Host: localhost:7474
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Fri, 17 Feb 2017 16:38:37 GMT
< Content-Type: text/plain
< Access-Control-Allow-Origin: *
< Transfer-Encoding: chunked
< Server: Jetty(6.1.25)
<
* Connection #0 to host localhost left intact
true

表 1. HA HTTP 端点响应

端点 实例状态 返回代码 主体文本

/db/manage/server/ha/master

Master

200 OK

true

Slave

404 Not Found

False

未知

404 Not Found

UNKNOWN

(如果 Neo4j 服务器启用了基础安全性,HA 状态端点也将需要身份验证凭据。如果需要身份验证,请使用 --user 开关运行 curl 命令:curl -v localhost:7474/db/manage/server/ha/master --user <用户名>:<密码>)

有关 HA HTTP 端点的更多信息,请参阅此处: /docs/operations-manual/current/clustering/high-availability/http-endpoints/

如果您运行的是因果集群 (CC) (Neo4j v3.1.x 及更高版本)

使用 CC 时有两种获取实例角色的方法:存储过程或 HTTP 端点

1) 存储过程 dbms.cluster.role()dbms.cluster.overview()
CALL dbms.cluster.role()

可以在因果集群的每个实例上调用存储过程 dbms.cluster.role() 来返回该实例的角色。它将返回一个包含当前实例角色的字符串。

CALL dbms.cluster.overview()

存储过程 dbms.cluster.overview() 通过返回集群中所有实例的详细信息来提供集群拓扑的概览。它返回集群实例的 ID、地址和角色(此过程只能从核心实例 Core 实例调用,因为它们是唯一拥有集群完整视图的实例)。

2) CC 的 HTTP 端点

与 HA 一样,我们可以使用 HTTP 端点来发现哪个实例是 master:/db/manage/server/core/writable。从命令行来看,查询这些端点的一种常用方法是使用 curl。如果不加参数,curl 将对提供的 URI 执行 HTTP GET 请求并输出响应主体文本(如果有)。如果您还想获取响应代码,只需添加 -v 标志即可获得详细输出。

$ curl -v localhost:7474/db/manage/server/core/writable
*   Trying ::127.0.0.1
* Connected to localhost (127.0.0.1) port 7474 (#0)
> GET /db/manage/server/core/writable HTTP/1.1
> Host: localhost:7474
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Fri, 17 Feb 2017 16:38:37 GMT
< Content-Type: text/plain
< Access-Control-Allow-Origin: *
< Transfer-Encoding: chunked
< Server: Jetty(9.2.9 v20150224)
<
* Connection #0 to host localhost left intact
true

表 2. CC HTTP 端点响应

端点 实例状态 返回代码 主体文本

/db/manage/server/core/writable

主节点 (Leader)

200 OK

true

从节点 (Follower)

404 Not Found

False

未知

404 Not Found

UNKNOWN

(如果 Neo4j 服务器启用了基础安全性,CC 状态端点也将需要身份验证凭据。如果需要身份验证,请使用 --user 开关运行 curl 命令:curl -v localhost:7474/db/manage/server/ha/master --user <用户名>:<密码>)

3. 在 master 上运行备份

执行完整备份:创建一个空目录(例如:/mnt/backup)并运行备份命令

v3.0.x
$ neo4j-backup -host <address> -to <backup-path>
v3.1.x+
$ neo4j-admin backup --backup-dir=<backup-path> --name=<graph.db-backup> [--from=<address>] [--fallback-to-full[=<true|false>]] [--check-consistency[=<true|false>]] [--cc-report-dir=<directory>] [--additional-config=<config-file-path>] [--timeout=<timeout>]
neo4j-home> mkdir /mnt/backup
neo4j-home> bin/neo4j-admin backup --from=192.168.1.34 --backup-dir=/mnt/backup --name=graph.db-backup
Doing full backup...
2017-02-01 14:09:09.510+0000 INFO  [o.n.c.s.StoreCopyClient] Copying neostore.nodestore.db.labels
2017-02-01 14:09:09.537+0000 INFO  [o.n.c.s.StoreCopyClient] Copied neostore.nodestore.db.labels 8.00 kB
2017-02-01 14:09:09.538+0000 INFO  [o.n.c.s.StoreCopyClient] Copying neostore.nodestore.db
2017-02-01 14:09:09.540+0000 INFO  [o.n.c.s.StoreCopyClient] Copied neostore.nodestore.db 16.00 kB
...
...
...

如果您列出 /mnt/backup 目录中的内容,将会看到一个名为 graph.db-backup 的 Neo4j 备份。

有关执行备份的更多信息,请参阅此处: /docs/operations-manual/current/backup/perform-backup/

4. 将备份移动到故障 slave

在登录到 master 后,将文件从 master 复制到 slave

$ scp -r /path/to/neo4j/backup username@<SLAVE_ADDRESS>:/path/to/destination

5. 停止实例

$ $NEO4J_HOME/bin/neo4j stop

6. 备份旧存储 [可选]

建议保留当前的 slave 存储,以便在需要时回滚操作。为此,我们只需重命名当前的存储目录。

$ mv $NEO4J_HOME/data/databases/graph.db $NEO4J_HOME/data/databases/graph.db-old

7. 恢复备份(对于 Neo4j 3.0 及更早版本,只需将备份目录复制到 graph.db 中)

基于在 master 实例上创建的备份来恢复(假设备份位置为 /mnt/backup,数据库备份名称为 graph.db-backup,请根据实际情况更改)

$ $NEO4J_HOME/bin/neo4j-admin restore --from=/mnt/backup --database=graph.db-backup --force

有关恢复备份的更多信息,请参阅此处: /docs/operations-manual/current/backup/restore-backup/

8. 启动实例

$ $NEO4J_HOME/bin/neo4j start

slave 现在应该可以正常启动。它将追赶 master 的进度,以获取从备份创建之时到恢复时刻之间错过的所有事务。

9. 清理旧文件 [可选]

此步骤仅在您在 slave 实例上备份了旧存储(第 6 步)时才适用。

一旦确认系统健康,且 slave 已恢复在线并与 master 实例达到一致,我们就可以移除旧的存储。

$ rm -rf $NEO4J_HOME/data/databases/graph.db-old
© . This site is unofficial and not affiliated with Neo4j, Inc.