监控集群端点以获取状态信息

集群公开了一些 HTTP 端点,可用于监控集群的运行状况。本节介绍这些端点并解释其语义。

调整集群端点安全设置

如果在 Neo4j 中启用了身份验证和授权,则集群状态端点也需要身份验证凭据。设置 dbms.security.auth_enabled 控制是否启用本机身份验证提供者。对于某些负载均衡器和代理服务器,在请求中提供身份验证凭据不是一个选项。对于这些情况,请考虑通过在 neo4j.conf 中设置 dbms.security.cluster_status_auth_enabled=false 来禁用集群状态端点的身份验证。

统一端点

一组统一的端点存在于主服务器和辅助服务器上,具有以下行为

  • /db/<databasename>/cluster/writable — 用于将 write 流量定向到特定实例。

  • /db/<databasename>/cluster/read-only — 用于将 read 流量定向到特定实例。

  • /db/<databasename>/cluster/available — 适用于将任意请求类型定向到可用于处理读取事务的实例的通用情况。

  • /db/<databasename>/cluster/status — 详细描述此实例对给定数据库中其在集群中的状态的视图。

  • /dbms/cluster/status — 详细描述此实例对所有数据库中其在集群中的状态的视图。对监控和协调滚动升级很有用。有关更多详细信息,请参见 状态端点

每个 /db/<databasename>/* 端点都针对一个特定的数据库。databaseName 路径参数代表数据库的名称。默认情况下,一个全新的 Neo4j 安装带有两个数据库 systemneo4j,它们有以下集群端点。

https://127.0.0.1:7474/dbms/cluster/status

https://127.0.0.1:7474/db/system/cluster/writable
https://127.0.0.1:7474/db/system/cluster/read-only
https://127.0.0.1:7474/db/system/cluster/available
https://127.0.0.1:7474/db/system/cluster/status

https://127.0.0.1:7474/db/neo4j/cluster/writable
https://127.0.0.1:7474/db/neo4j/cluster/read-only
https://127.0.0.1:7474/db/neo4j/cluster/available
https://127.0.0.1:7474/db/neo4j/cluster/status

尝试访问不在服务器上托管的数据库的端点会导致 404 响应。

表 1. 统一 HTTP 端点响应
端点 实例状态 返回代码 主体文本

/db/<databasename>/cluster/writable

领导者

200 OK

true

跟随者

404 Not Found

false

辅助

404 Not Found

false

/db/<databasename>/cluster/read-only

领导者

404 Not Found

false

跟随者

200 OK

true

辅助

200 OK

true

/db/<databasename>/cluster/available

领导者

200 OK

true

跟随者

200 OK

true

辅助

200 OK

true

/db/<databasename>/cluster/status

领导者

200 OK

JSON - 请参阅 状态端点 获取详细信息。

跟随者

200 OK

JSON - 请参阅 状态端点 获取详细信息。

辅助

200 OK

JSON - 请参阅 状态端点 获取详细信息。

/dbms/cluster/status

领导者

200 OK

JSON - 请参阅 状态端点 获取详细信息。

跟随者

200 OK

JSON - 请参阅 状态端点 获取详细信息。

辅助

200 OK

JSON - 请参阅 状态端点 获取详细信息。

示例 1. 使用集群监控端点

从命令行访问这些端点的常用方法是使用 curl。在没有参数的情况下,curl 会对提供的 URI 执行 HTTP GET 操作并输出主体文本(如果有)。如果需要响应代码,只需添加 -v 标志以获取详细输出。以下是一些示例。

  • 在当前选为领导者的主服务器上请求 writable 端点,并使用详细输出

#> curl -v localhost:7474/db/neo4j/cluster/writable
* About to connect() to localhost port 7474 (#0)
*   Trying ::1...
* connected
* Connected to localhost (::1) port 7474 (#0)
> GET /db/neo4j/cluster/writable HTTP/1.1
> User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5
> Host: localhost:7474
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/plain
< Access-Control-Allow-Origin: *
< Transfer-Encoding: chunked
< Server: Jetty(9.4.17)
<
* Connection #0 to host localhost left intact
true* Closing connection #0

状态端点

状态端点位于 /db/<databasename>/cluster/status,用于协助滚动升级。有关更多信息,请参阅 升级和迁移指南 → 集群

通常,在将主服务器从集群中移除之前,需要确保每个数据库的主服务器都安全关闭。与直觉相反的是,主服务器安全关闭意味着大多数 **其他** 主服务器都处于健康状态、同步并最近收到了该数据库领导者的消息。状态端点提供以下信息,以帮助解决此类问题。

状态端点响应中的几个字段指的是 Raft 的细节,Raft 是 Neo4j 集群中用于提供高可用性事务的算法。在 Neo4j 集群中,每个数据库都有自己独立的 Raft 组。因此,leaderraftCommandsPerSecond 等详细信息是特定于数据库的。

示例 2. 状态响应示例
{
  "lastAppliedRaftIndex":0,
  "votingMembers":["30edc1c4-519c-4030-8348-7cb7af44f591","80a7fb7b-c966-4ee7-88a9-35db8b4d68fe","f9301218-1fd4-4938-b9bb-a03453e1f779"],
  "memberId":"80a7fb7b-c966-4ee7-88a9-35db8b4d68fe",
  "leader":"30edc1c4-519c-4030-8348-7cb7af44f591",
  "millisSinceLastLeaderMessage":84545,
  "participatingInRaftGroup":true,
  "core":true,
  "isHealthy":true,
  "raftCommandsPerSecond":124
}
表 2. 状态端点描述
字段 类型 可选 示例 描述

core

boolean

true

用于区分服务器是在主服务器(核心)模式还是辅助模式下托管数据库。

lastAppliedRaftIndex

number

4321

集群中的每个事务都与一个 Raft 索引相关联。

指示最新的应用 Raft 日志索引。

participatingInRaftGroup

boolean

false

参与的成员可以投票。当主服务器是投票者成员的一部分并跟踪了领导者时,它被认为是参与的。

votingMembers

string[]

[]

当领导者一直在接收来自成员的通信时,该成员被认为是投票者成员。

被此主服务器视为投票集一部分的成员的 memberId 列表。

isHealthy

boolean

true

反映此成员的本地数据库是否遇到阻止本地写入的关键错误。

memberId

string

30edc1c4-519c-4030-8348-7cb7af44f591

集群中的每个成员都有自己的唯一成员 ID 来标识它。使用 memberId 区分主服务器和辅助服务器。

leader

string

80a7fb7b-c966-4ee7-88a9-35db8b4d68fe

遵循与 memberId 相同的格式,但如果它为空或缺失,则领导者未知。

millisSinceLastLeaderMessage

number

1234

自上次类似心跳的领导者消息以来的毫秒数。与辅助服务器无关,因此不包括在内。

raftCommandsPerSecond 已弃用

number

124

在可配置的采样窗口内(通过 clustering.status_throughput_window 设置),对 Raft 状态机吞吐量的平均估计。raftCommandsPerSecond 不是监控服务器是否在更新方面落后的有效方式,因此已弃用,将在 Neo4j 的下一个主要版本中删除。建议使用每个服务器上的度量 <prefix>.clustering.core.commit_index 并查找差异。

在实例开启后,可以访问状态端点,以确保满足以下表格中列出的所有保证。

为了获得对集群最准确的视图,强烈建议访问所有主成员的状态端点并比较结果。下表说明如何比较结果。

表 3. 通过状态端点访问的测量值
检查名称 计算方法 描述

allServersAreHealthy

每个主服务器的状态端点都指示 isHealthy==true

确保整个集群中的数据都是健康的。当任何主服务器为假时,表明存在更大的问题。

allVotingSetsAreEqual

对于任何两个主服务器(A 和 B),状态端点 A 的 votingMembers== 状态端点 B 的 votingMembers

当投票开始时,所有主服务器都彼此相等,并且所有成员都同意成员资格。

allVotingSetsContainAtLeastTargetCluster

对于所有主服务器 (S),除了要关闭的主服务器 Z,S 中的每个成员都包含 S 在其投票集中。成员资格是使用状态端点中的 memberIdvotingMembers 确定的。

有时网络状况并非完美,关闭与最初要关闭的服务器不同的主服务器可能是有意义的。如果对所有主服务器运行此检查,则可以关闭符合此条件的主服务器(前提是满足其他条件)。

hasOneLeader

对于任何两个主服务器(A 和 B),A.leader == B.leader && leader!=null

如果领导者不同,则可能存在分区(或者,这也可能由于时间问题而发生)。如果领导者未知,则意味着领导者消息实际上已超时。

noMembersLagging

对于 lastAppliedRaftIndex = min 的主服务器 A,以及 lastAppliedRaftIndex = max 的主服务器 B,B.lastAppliedRaftIndex-A.lastAppliedRaftIndex<raftIndexLagThreshold

如果主服务器之间应用索引存在较大差异,则关闭主服务器可能是危险的。

raftIndexLagThreshold 帮助您监控跨集群应用 Raft 日志条目的延迟并设置适当的阈值。您应该选择适合您的特定集群和工作负载的 raftIndexLagThreshold。在正常情况下测量报告的延迟,并选择略高于该延迟的阈值将是选择适当值的一种好方法。例如,您观察到在所有工作负载阶段的度量(最大 lastAppliedRaftIndex 和最小 lastAppliedRaftIndex 之间的差异),发现它在所有工作日都保持在 100 或更低,但在周六,它会在几个小时内飙升到 5,000。然后,根据您的监控需求或功能,您要么设置工作日阈值为 120,周末阈值为 6,000,要么只设置总体阈值为 6,000。这些阈值可以帮助识别性能问题。

组合状态端点

在使用状态端点支持滚动升级时,需要评估主服务器是否安全关闭 **所有** 数据库。为了避免对每个 /db/<databasename>/cluster/status 端点发出单独的请求,请使用 /dbms/cluster/status

此端点返回一个 JSON 数组,该数组的元素包含与 单个数据库版本 相同的字段,以及 databaseNamedatabaseUuid 的字段。

示例 3. 组合状态响应示例
[
  {
    "databaseName": "neo4j",
    "databaseUuid": "f4dacc01-f88a-4512-b3bf-68f7539c941e",
    "databaseStatus": {
      "lastAppliedRaftIndex": -1,
      "votingMembers": [
        "0cff51ad-7cee-44cc-9102-538fc4544b95",
        "90ff5df1-f5f8-4b4c-8289-a0e3deb2235c",
        "99ca7cd0-6072-4387-bd41-7566a98c6afc"
      ],
      "memberId": "90ff5df1-f5f8-4b4c-8289-a0e3deb2235c",
      "leader": "90ff5df1-f5f8-4b4c-8289-a0e3deb2235c",
      "millisSinceLastLeaderMessage": 0,
      "raftCommandsPerSecond": 0.0,
      "core": true,
      "participatingInRaftGroup": true,
      "healthy": true
    }
  },
  {
    "databaseName": "system",
    "databaseUuid": "00000000-0000-0000-0000-000000000001",
    "databaseStatus": {
      "lastAppliedRaftIndex": 7,
      "votingMembers": [
        "0cff51ad-7cee-44cc-9102-538fc4544b95",
        "90ff5df1-f5f8-4b4c-8289-a0e3deb2235c",
        "99ca7cd0-6072-4387-bd41-7566a98c6afc"
      ],
      "memberId": "90ff5df1-f5f8-4b4c-8289-a0e3deb2235c",
      "leader": "90ff5df1-f5f8-4b4c-8289-a0e3deb2235c",
      "millisSinceLastLeaderMessage": 0,
      "raftCommandsPerSecond": 0.0,
      "core": true,
      "participatingInRaftGroup": true,
      "healthy": true
    }
  }
]