知识库

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

(如果您使用的是 HA (高可用性),请阅读并将 Master 和 Slave 分别理解为 Leader 和 Follower)

有时,在运行 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.