故障排除

以下信息可以帮助您诊断并解决问题。

定位并调查 Neo4j Helm Chart 的问题

在 Kubernetes 中部署 Neo4j Helm Chart 的过程可以大致分为以下步骤

  1. 创建 Neo4j Pod

  2. Neo4j Pod 被调度到特定的 Kubernetes 节点上运行。

  3. 创建 Neo4j Pod 中的所有 容器 (Containers)

  4. 运行 Neo4j Pod 中的 InitContainers

  5. 运行 Neo4j Pod 中的 容器 (Containers)

  6. 检查 Startup(启动)和 Readiness(就绪)探针。

当所有步骤顺利完成后,Neo4j StatefulSet、Pod 和服务必须处于 ready(就绪)状态。此时,您应该能够连接并使用您的 Neo4j 数据库。

如果 Neo4j Helm chart 安装成功,但 Neo4j 未能启动并在 Kubernetes 中达到 ready 状态,则故障排查分为以下两个步骤:

  1. 使用 kubectl get 命令检查 Kubernetes 中资源的状态。这将确定哪一步失败了。

  2. 收集与该步骤相关的信息。

根据失败的步骤,您可以从 Kubernetes(例如使用 kubectl describe)以及 Neo4j 进程(例如检查 Neo4j 调试日志)中收集信息。

下表提供了调查 Neo4j Helm Chart 部署问题的入门简易步骤。有关如何在 Kubernetes 中调试应用程序的更多信息,请参阅 Kubernetes 文档

表 1. 调查 Neo4j Helm Chart 部署问题

步骤

诊断

深入调查

Neo4j Pod 已创建

如果 kubectl get pod <release-name>-0 没有返回单个 Pod 结果,则 Pod 创建存在问题。

描述 Neo4j StatefulSet — 检查 kubectl describe statefulset <release-name> 的输出。

Neo4j Pod 已调度

如果 kubectl get pod <release-name>-0 显示的状态停留在 Pending,则 Pod 调度存在问题。

描述 Neo4j Pod — 执行 kubectl describe pod <release-name>-0 并检查输出。

Neo4j Pod 中的容器已创建

如果 kubectl get pod <release-name>-0 显示的状态停留在 Waiting,则容器创建或启动存在问题。

描述 Neo4j Pod — 检查 kubectl describe pod <release-name>-0 的输出,特别注意 Events

Neo4j Pod 中的 InitContainers

如果 kubectl get pod <release-name>-0 显示的状态停留在 Init:(例如 Init:CrashLoopBackOff, Init:Error 等),则 InitContainers 存在问题。
请注意,如果 Pod 的 StatusPodInitializingRunning,则说明 InitContainers 已成功完成。

描述 Neo4j Pod — 检查 kubectl describe pod <release-name>-0 的输出,特别注意 InitContainer(注意 InitContainer 名称)和 Events。使用 kubectl logs <pod-name> -c <init-container-name> 获取 InitContainer 日志。

Neo4j Pod 中的容器正在运行

如果 kubectl get pod <release-name>-0 显示的状态与上述任何状态都不匹配,但 Pod 仍未达到 Running,则 Neo4j Pod 中的容器运行存在问题。

描述 Neo4j Pod — 检查 kubectl describe pod <release-name>-0 的输出,特别注意 Container 状态(注意 Container 名称)和 Events。使用 kubectl logs <pod-name> -c <init-container-name> 获取 Container 日志。如果 Neo4j Container 启动后意外退出(例如状态为 CrashLoopBackOff),请遵循 Neo4j 崩溃或意外重启 的指南。

启动和就绪探针 (Startup and Readiness Probes)

如果 kubectl get pod <release-name>-0 显示的状态为 Running,但 Pod 未能达到 ready,则 StartupReadiness 探针存在问题。

描述 Neo4j Pod — 检查 kubectl describe pod <release-name>-0 的输出,特别注意 Events 和探针。检查 Pod 日志 kubectl logs <release-name>-0,Neo4j 日志 kubectl exec <release-name>-0 -- tail -n 100 /logs/neo4j.log,以及 Neo4j 调试日志 kubectl exec <release-name>-0 -- tail -n 500 /logs/debug.log

Neo4j 崩溃或意外重启

如果 Neo4j Pod 启动后崩溃或意外重启,原因可能有多种。已知原因包括:

  • Neo4j 配置无效或不正确,导致容器启动后不久即关闭。

  • Neo4j Java 进程内存溢出并退出,报错 OutOfMemoryException

  • 调度 Neo4j Pod 的 Kubernetes 节点受到干扰,例如正在进行驱逐或已经关机。

  • Neo4j Pod 中的容器因使用内存超过容器配置的资源限制而被操作系统关闭 (OOMKilled)。

  • 过长的垃圾回收 (GC) 暂停导致 Neo4j Pod LivenessProbe 失败,从而导致 Kubernetes 重启 Neo4j。

OOMKILLEDOutOfMemoryException 看起来非常相似,但它们出现的位置和修复方法不同。了解这一点并明确您正在处理的问题非常重要。

以下是一些有助于排查崩溃和意外重启的检查步骤:

描述 Neo4j Pod

使用 kubectl 描述 Neo4j Pod

kubectl describe pod <release-name>-0

检查 Neo4j 容器状态

检查容器的 StateLast State。这显示了在被 OOMKilled 后重启的容器的 Last State 情况:

$ kubectl describe pod neo4j-0
State:          Running
  Started:      Mon, 1 Jan 2021 00:02:00 +0000
Last State:     Terminated
  Reason:       OOMKilled
  Exit Code:    137
  Started:      Mon, 1 Jan 2021 00:00:00 +0000
  Finished:     Mon, 1 Jan 2021 00:01:00 +0000

如果此处或其他日志中出现 Exit Code: 137,即使没有 "OOMKilled" 字符串,也表明发生了 OOMKilled

检查最近的 Events

kubectl describe 的输出显示较旧的事件在顶部,较新的事件在底部。通常,您可以忽略较旧的事件。

一个显示 Neo4j 容器被 Kubernetes kubelet 杀死的 Killing 事件。
$ kubectl describe pod neo4j-0
Events:
Type    Reason       Age      From                  Message
----    ------       ----     ----                  -------
Normal  Scheduled    6m30s    default-scheduler     Successfully assigned default/neo4j-0 to k8s-node-a
...
Normal  Killing        56s    kubelet, k8s-node-a   Killing container with id docker://neo4j-0-neo4j:Need to kill Pod

仅凭此事件日志,尚不清楚 Kubernetes 为何决定杀死 Neo4j 容器。

此示例中的后续步骤可以是检查:

  • 容器是否被 OOMKilled

  • 容器是否未通过 LivenessStartup 探针检查。

  • 调查节点,查看是否存在杀死容器的原因,例如执行 kubectl describe node <k8s node>

检查 Neo4j 日志和指标

Neo4j Helm Chart 将 Neo4j 配置为将日志和指标持久化到提供的卷中。如果没有为日志或指标显式配置卷,它们将持久存储在 Neo4j 数据 (data) 卷上。这确保了崩溃或意外关闭的 Neo4j 实例产生的日志和指标输出得以保留。

从运行中的 Neo4j Pod 收集数据

  • 使用 kubectl cp 命令从 Pod 下载所有 Neo4j 日志。

    kubectl cp <neo4j-pod-name>:/logs neo4j-logs/
  • 如果为 Neo4j 启用了 CSV 指标收集(默认设置),请使用以下命令从 Pod 下载所有 Neo4j 指标:

    kubectl cp <neo4j-pod-name>:/metrics neo4j-metrics/

从非运行状态的 Neo4j Pod 收集数据

如果 Neo4j Pod 未运行或因频繁崩溃导致 kubectl cp 不可行,则应将 Neo4j 部署置于 离线维护模式 以收集日志和指标。

检查容器日志

主要的 Neo4j DBMS 进程日志会持久化到磁盘,并可按照 检查 Neo4j 日志和指标 中的说明进行访问。但是,Neo4j 启动日志以及 Neo4j Pod 中其他容器的日志会发送到容器的 stdoutstderr 流。可以使用 kubectl logs <pod name> -c <container name> 查看这些容器日志。

遗憾的是,如果容器在崩溃或意外关闭后重启,通常 kubectl logs 只显示新容器实例的日志(重启后),而前一个容器实例(意外关闭的那个)的日志无法通过 kubectl logs 获取。

要捕获崩溃容器的日志,您可以尝试:

  • 在连接到 Kubernetes 集群的日志收集器/聚合器(例如 Stackdriver, Cloudwatch Logs, Logstash 等)中查看容器日志。如果您使用托管 Kubernetes 平台,这通常默认启用。

  • 使用 kubectl logs --follow 持续流式传输正在运行的容器的日志,直到其再次崩溃。