Skip to content

Neo4j 集群故障

节点故障

症状

  • 集群成员状态显示节点为离线
  • 复制延迟增加
  • 写入操作可能受影响(如果是核心节点故障)
  • 监控告警触发

诊断步骤

bash
# 1. 检查节点状态
cypher-shell -u neo4j -p password -c "CALL dbms.cluster.overview();"

# 2. 检查节点日志
ssh <failed-node> "tail -f /var/log/neo4j/neo4j.log | grep -i error"
ssh <failed-node> "tail -f /var/log/neo4j/debug.log | grep -i error"

# 3. 检查节点进程
ssh <failed-node> "ps aux | grep neo4j"

# 4. 检查节点资源使用情况
ssh <failed-node> "top -n 1"
ssh <failed-node> "df -h"
ssh <failed-node> "free -h"

# 5. 检查网络连接
ping <failed-node>
ssh <failed-node> "netstat -tuln | grep -E '5000|7687|7474'"

恢复步骤

核心节点故障

bash
# 1. 尝试重启故障节点
ssh <failed-node> "systemctl restart neo4j"

# 2. 验证节点是否重新加入集群
cypher-shell -u neo4j -p password -c "CALL dbms.cluster.overview();"

# 3. 监控复制状态,确保数据同步
cypher-shell -u neo4j -p password -c "CALL dbms.cluster.routing.getRoutingTable({});"

# 4. 如果节点无法重启,替换故障节点
# 准备新节点,配置与原节点相同
# 启动新节点,自动加入集群
ssh <new-node> "systemctl start neo4j"

# 5. 验证新节点加入集群
cypher-shell -u neo4j -p password -c "CALL dbms.cluster.overview();"

只读副本故障

bash
# 1. 尝试重启故障节点
ssh <failed-node> "systemctl restart neo4j"

# 2. 验证节点是否重新加入集群
cypher-shell -u neo4j -p password -c "CALL dbms.cluster.overview();"

# 3. 如果节点无法重启,替换故障节点
# 准备新节点,配置为只读副本
# 启动新节点,自动加入集群
ssh <new-node> "systemctl start neo4j"

# 4. 验证新节点加入集群
cypher-shell -u neo4j -p password -c "CALL dbms.cluster.overview();"

网络分区

症状

  • 集群分裂成多个子集群
  • 部分节点无法通信
  • 写入操作可能失败
  • 复制延迟持续增加

诊断步骤

bash
# 1. 检查集群状态
cypher-shell -u neo4j -p password -c "CALL dbms.cluster.overview();"

# 2. 检查网络连接
# 在不同节点上执行
ping <other-node>
ssh <other-node> "hostname"

# 3. 检查防火墙规则
ssh <node> "iptables -L -n"
ssh <node> "firewall-cmd --list-all"

# 4. 检查网络接口状态
ssh <node> "ip addr show"
ssh <node> "netstat -i"

# 5. 检查集群日志
ssh <node> "tail -f /var/log/neo4j/neo4j.log | grep -i 'network'"

恢复步骤

bash
# 1. 修复网络问题
# 检查网络线缆、交换机、路由器等硬件
# 检查防火墙规则和网络配置
# 重启网络服务
ssh <node> "systemctl restart network"

# 2. 验证网络连接恢复
ping <node>
ssh <node> "hostname"

# 3. 检查集群状态,等待自动恢复
cypher-shell -u neo4j -p password -c "CALL dbms.cluster.overview();"

# 4. 如果集群未自动恢复,重启故障节点
ssh <node> "systemctl restart neo4j"

# 5. 验证集群完整性
cypher-shell -u neo4j -p password -c "CALL dbms.cluster.overview();"

脑裂

症状

  • 集群分裂成多个独立的子集群
  • 每个子集群都有自己的领导者
  • 数据出现不一致
  • 写入操作在不同子集群中产生冲突

诊断步骤

bash
# 1. 检查集群状态
cypher-shell -u neo4j -p password -c "CALL dbms.cluster.overview();"

# 2. 在不同节点上执行,检查领导者状态
ssh <node1> "cypher-shell -u neo4j -p password -c 'CALL dbms.cluster.overview() YIELD role RETURN role;'"
ssh <node2> "cypher-shell -u neo4j -p password -c 'CALL dbms.cluster.overview() YIELD role RETURN role;'"

# 3. 检查Raft状态
ssh <node> "cypher-shell -u neo4j -p password -c 'CALL dbms.queryJmx("org.neo4j:name=Raft,instance=raft-0") YIELD attributes RETURN attributes;'"

# 4. 检查数据一致性
# 在不同节点上执行相同查询,比较结果
cypher-shell -u neo4j -p password -c "MATCH (n:Test) RETURN count(n);"

恢复步骤

bash
# 1. 停止所有节点
for node in node1 node2 node3 node4 node5; do
  ssh $node "systemctl stop neo4j"
done

# 2. 选择一个权威节点(数据最新、状态最完整)
authoritative_node="node1"

# 3. 清理其他节点的集群数据
for node in node2 node3 node4 node5; do
  ssh $node "rm -rf /var/lib/neo4j/data/cluster/"
done

# 4. 启动权威节点
ssh $authoritative_node "systemctl start neo4j"

# 5. 逐个启动其他节点,重新加入集群
for node in node2 node3 node4 node5; do
  ssh $node "systemctl start neo4j"
  sleep 30  # 等待节点加入
  cypher-shell -u neo4j -p password -c "CALL dbms.cluster.overview();"
done

# 6. 验证集群状态
cypher-shell -u neo4j -p password -c "CALL dbms.cluster.overview();"

# 7. 验证数据一致性
cypher-shell -u neo4j -p password -c "MATCH (n) RETURN count(n);"

复制延迟

症状

  • 只读副本数据落后于核心节点
  • 复制延迟监控指标增加
  • 读取操作可能返回过时数据
  • 监控告警触发

诊断步骤

bash
# 1. 检查复制状态
cypher-shell -u neo4j -p password -c "CALL dbms.cluster.routing.getRoutingTable({});"

# 2. 检查复制延迟指标
cypher-shell -u neo4j -p password -c "CALL dbms.queryJmx('org.neo4j:name=Transaction%20Puller,*') YIELD attributes RETURN attributes;"

# 3. 检查核心节点写入负载
cypher-shell -u neo4j -p password -c "CALL dbms.listQueries() YIELD query, elapsedTime WHERE elapsedTime > 1000 RETURN query, elapsedTime ORDER BY elapsedTime DESC;"

# 4. 检查网络带宽使用情况
ssh <node> "iftop -t -s 5"

# 5. 检查磁盘I/O性能
ssh <node> "iostat -x 1 5"

恢复步骤

bash
# 1. 检查并优化写入负载
# 识别并优化慢查询
cypher-shell -u neo4j -p password -c "CALL dbms.listQueries() YIELD queryId, query, elapsedTime WHERE elapsedTime > 10000 RETURN queryId, query, elapsedTime ORDER BY elapsedTime DESC;"

# 2. 增加复制线程数
# 修改neo4j.conf
server.cluster.pullers=4

# 3. 重启Neo4j服务
systemctl restart neo4j

# 4. 检查网络带宽
# 增加网络带宽或优化网络配置

# 5. 优化磁盘I/O
# 确保使用SSD/NVMe存储
# 调整磁盘调度器
ssh <node> "echo deadline > /sys/block/sda/queue/scheduler"

# 6. 监控复制延迟恢复情况
cypher-shell -u neo4j -p password -c "CALL dbms.queryJmx('org.neo4j:name=Transaction%20Puller,*') YIELD attributes RETURN attributes;"

磁盘故障

症状

  • 节点无法启动
  • 日志中出现磁盘I/O错误
  • 磁盘空间不足告警
  • 写入操作失败

诊断步骤

bash
# 1. 检查磁盘空间
ssh <node> "df -h"

# 2. 检查磁盘健康状态
ssh <node> "smartctl -a /dev/sda"

# 3. 检查磁盘I/O错误
ssh <node> "dmesg | grep -i error"
ssh <node> "dmesg | grep -i io"

# 4. 检查Neo4j日志中的磁盘错误
ssh <node> "tail -f /var/log/neo4j/neo4j.log | grep -i disk"
ssh <node> "tail -f /var/log/neo4j/debug.log | grep -i disk"

恢复步骤

bash
# 1. 如果是磁盘空间不足
# 清理不必要的文件
ssh <node> "rm -rf /var/log/neo4j/*.log.*"

# 2. 如果是磁盘I/O错误
# 停止节点
ssh <node> "systemctl stop neo4j"

# 3. 更换故障磁盘
# 硬件更换操作

# 4. 恢复数据
# 从备份恢复
ssh <node> "neo4j-admin restore --from=/path/to/backup --database=neo4j --force"

# 或从其他节点复制数据
# 仅适用于只读副本
scp -r <healthy-node>:/var/lib/neo4j/data/databases/neo4j /var/lib/neo4j/data/databases/
scp -r <healthy-node>:/var/lib/neo4j/data/transactions/neo4j /var/lib/neo4j/data/transactions/

# 5. 修复权限
ssh <node> "chown -R neo4j:neo4j /var/lib/neo4j/data/"

# 6. 启动节点
ssh <node> "systemctl start neo4j"

# 7. 验证节点加入集群
cypher-shell -u neo4j -p password -c "CALL dbms.cluster.overview();"

内存不足

症状

  • JVM OutOfMemoryError
  • 节点进程崩溃
  • 性能下降
  • 监控告警触发

诊断步骤

bash
# 1. 检查JVM日志
ssh <node> "tail -f /var/log/neo4j/debug.log | grep -i outofmemory"

# 2. 检查内存使用情况
ssh <node> "free -h"
ssh <node> "top -n 1 | grep java"

# 3. 检查Neo4j内存配置
ssh <node> "grep -E 'server.memory' /etc/neo4j/neo4j.conf"

# 4. 分析堆转储文件(如果有)
# 使用MAT或VisualVM分析

恢复步骤

bash
# 1. 调整JVM内存配置
# 修改neo4j.conf
server.memory.heap.initial_size=16g
server.memory.heap.max_size=16g
server.memory.pagecache.size=32g

# 2. 重启Neo4j服务
ssh <node> "systemctl restart neo4j"

# 3. 优化查询,减少内存占用
# 识别并优化大查询
cypher-shell -u neo4j -p password -c "CALL dbms.listQueries() YIELD queryId, query, elapsedTime WHERE elapsedTime > 10000 RETURN queryId, query, elapsedTime ORDER BY elapsedTime DESC;"

# 4. 增加硬件内存
# 如果经常出现内存不足,考虑升级服务器内存

# 5. 监控内存使用情况
cypher-shell -u neo4j -p password -c "CALL dbms.queryJmx('org.neo4j:name=MemoryPool,*') YIELD attributes RETURN attributes;"

配置错误

症状

  • 节点无法启动
  • 集群无法形成
  • 服务运行异常
  • 日志中出现配置错误信息

诊断步骤

bash
# 1. 检查Neo4j启动日志
ssh <node> "tail -f /var/log/neo4j/neo4j.log | grep -i config"

# 2. 验证配置文件语法
ssh <node> "neo4j admin check-config"

# 3. 检查集群配置
ssh <node> "grep -E 'dbms.mode|dbms.cluster' /etc/neo4j/neo4j.conf"

# 4. 比较不同节点的配置
# 确保核心配置一致
diff <(ssh node1 "cat /etc/neo4j/neo4j.conf") <(ssh node2 "cat /etc/neo4j/neo4j.conf")

恢复步骤

bash
# 1. 修复配置文件
# 恢复正确的配置
scp /path/to/correct/neo4j.conf <node>:/etc/neo4j/neo4j.conf

# 2. 重启Neo4j服务
ssh <node> "systemctl restart neo4j"

# 3. 验证配置生效
cypher-shell -u neo4j -p password -c "CALL dbms.listConfig() YIELD name, value WHERE name CONTAINS 'cluster' RETURN name, value;"

# 4. 验证集群状态
cypher-shell -u neo4j -p password -c "CALL dbms.cluster.overview();"

集群故障预防

1. 监控与告警

核心监控指标

txt
# 节点状态监控
neo4j_cluster_member_count

# 复制延迟监控
neo4j_transaction_puller_delay_seconds

# 磁盘空间监控
disk_usage_percent{mountpoint="/var/lib/neo4j"}

# 内存使用率监控
jvm_memory_used_bytes / jvm_memory_max_bytes * 100

# CPU使用率监控
system_cpu_usage

告警规则示例

yaml
# Prometheus告警规则
- alert: Neo4jClusterNodeDown
  expr: neo4j_cluster_member_count < 3
  for: 5m
  labels:
    severity: critical
  annotations:
    summary: "Neo4j集群节点离线"
    description: "Neo4j集群节点数量不足3个,当前数量: {{ $value }}"

- alert: Neo4jReplicationDelayHigh
  expr: neo4j_transaction_puller_delay_seconds > 30
  for: 5m
  labels:
    severity: warning
  annotations:
    summary: "Neo4j复制延迟过高"
    description: "Neo4j复制延迟超过30秒,当前延迟: {{ $value }}秒"

- alert: Neo4jDiskSpaceLow
  expr: disk_usage_percent{mountpoint="/var/lib/neo4j"} > 80
  for: 5m
  labels:
    severity: warning
  annotations:
    summary: "Neo4j磁盘空间不足"
    description: "Neo4j磁盘使用率超过80%,当前使用率: {{ $value }}%"

2. 定期维护

  • 定期备份:每天至少进行一次全量备份
  • 定期检查:每周检查集群状态、日志和性能
  • 定期更新:及时应用补丁和更新
  • 定期演练:每季度进行一次故障恢复演练

3. 架构优化

  • 冗余设计:核心节点数量为奇数(3,5,7)
  • 跨可用区部署:分布在不同可用区,提高可用性
  • 读写分离:减轻核心节点负载
  • 负载均衡:使用Neo4j Router或第三方负载均衡器

4. 配置优化

txt
# neo4j.conf 优化建议

# 集群配置
dbms.mode=CORE
dbms.cluster.initial_discovery_members=node1:5000,node2:5000,node3:5000
dbms.cluster.pullers=4
dbms.cluster.timeout=10s

# 网络配置
dbms.connectors.default_listen_address=0.0.0.0
dbms.connector.bolt.listen_address=:7687
dbms.connector.http.listen_address=:7474
dbms.connector.https.listen_address=:7473

# 事务配置
dbms.tx_state.memory_allocation=ON_HEAP
dbms.tx_state.max_off_heap_memory=2g

# 日志配置
dbms.logs.query.enabled=true
dbms.logs.query.threshold=100ms
dbms.logs.debug.enabled=true

常见问题(FAQ)

Q1: 核心节点故障会导致集群不可用吗?

A1: 这取决于核心节点的数量和故障节点的数量。Neo4j Causal Clustering使用Raft协议,需要超过半数的核心节点正常运行才能保持集群可用。例如:

  • 3个核心节点:最多允许1个节点故障
  • 5个核心节点:最多允许2个节点故障
  • 7个核心节点:最多允许3个节点故障

Q2: 如何判断集群是否发生脑裂?

A2: 判断集群脑裂的方法包括:

  1. 检查集群状态,是否出现多个领导者
  2. 在不同节点上执行相同查询,比较结果是否一致
  3. 检查Raft状态,是否存在多个Raft组
  4. 检查网络连接,是否存在网络分区

Q3: 复制延迟过高会影响读取操作吗?

A3: 是的,复制延迟过高会导致只读副本返回过时数据。对于需要强一致性的读取操作,建议直接查询核心节点或使用因果一致性读取。

Q4: 如何防止集群脑裂?

A4: 防止集群脑裂的措施包括:

  1. 使用奇数个核心节点
  2. 配置合理的超时时间
  3. 确保网络稳定可靠
  4. 实现跨可用区部署
  5. 加强监控和告警

Q5: 节点故障后如何恢复数据?

A5: 节点故障后的数据恢复方法包括:

  1. 从备份恢复(适用于核心节点)
  2. 从其他节点复制数据(适用于只读副本)
  3. 等待节点自动重新加入集群(如果是临时故障)

Q6: 如何优化集群性能?

A6: 优化集群性能的方法包括:

  1. 合理配置内存(堆内存和页缓存)
  2. 使用SSD/NVMe存储
  3. 优化查询和索引
  4. 配置合适的复制线程数
  5. 实现读写分离
  6. 增加只读副本数量

Q7: 集群配置需要注意哪些事项?

A7: 集群配置需要注意:

  1. 所有节点的配置保持一致
  2. 配置合理的超时时间
  3. 确保网络端口开放
  4. 配置正确的集群发现地址
  5. 使用合适的认证和加密机制

Q8: 如何监控集群健康状态?

A8: 监控集群健康状态的方法包括:

  1. 使用Prometheus + Grafana监控核心指标
  2. 配置告警规则,及时发现问题
  3. 定期执行集群状态检查
  4. 监控日志中的错误信息
  5. 定期进行性能测试