VictoriaMetrics 完全指南 / 15 - 故障排查
15 · 故障排查
本章目标
- 掌握常见问题的诊断方法
- 学会分析 VictoriaMetrics 日志
- 了解关键 API 用于故障排查
- 建立系统化的排错思路
15.1 排错流程
遇到问题
│
▼
检查服务状态 ──▶ 是否在运行?
│ │
│ 是 │ 否
▼ ▼
检查日志 查看 systemd 日志
│ journalctl -u victoria-metrics
▼
检查 API ──▶ /health /metrics /api/v1/status/*
│
▼
检查资源 ──▶ CPU / 内存 / 磁盘
│
▼
检查网络 ──▶ 端口 / 防火墙 / DNS
│
▼
定位问题 ──▶ 查阅对应章节
15.2 常见问题速查
15.2.1 服务启动失败
问题:VictoriaMetrics 无法启动
# 查看日志
journalctl -u victoria-metrics -n 100 --no-pager
# 常见原因:
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
bind: address already in use | 端口被占用 | lsof -i :8428 查看并停止冲突进程 |
permission denied | 权限不足 | 检查数据目录权限 |
not enough memory | 内存不足 | 减少 -memory.allowedPercent |
storageDataPath is empty | 未指定数据路径 | 添加 -storageDataPath 参数 |
invalid flag | 参数拼写错误 | 检查配置文件或启动参数 |
# 排查端口冲突
sudo lsof -i :8428
# 或
sudo ss -tlnp | grep 8428
# 排查权限问题
ls -la /var/lib/victoria-metrics/
# 确保用户与 systemd 服务配置一致
# 排查内存问题
free -h
cat /proc/$(pgrep victoria-metrics)/status | grep VmRSS
15.2.2 数据查询返回空结果
问题:查询表达式正确但无数据返回
# 1. 检查数据是否写入成功
curl -s 'http://localhost:8428/api/v1/label/__name__/values' | python3 -m json.tool
# 2. 检查时间范围
# 确认查询的时间范围覆盖数据的时间戳
curl -s 'http://localhost:8428/api/v1/status/tsdb' | python3 -c "
import json, sys
data = json.load(sys.stdin)
print(f\"Total series: {data['data']['totalSeries']}\")
for m in data['data']['seriesCountByMetricName'][:5]:
print(f\" {m['name']}: {m['value']}\")
"
# 3. 检查时间戳是否合理
curl -s 'http://localhost:8428/api/v1/query?query=my_metric&time=0' | python3 -m json.tool
# 如果时间戳是 0 或很旧,数据可能在查询范围之外
# 4. 检查 stale 数据
# VictoriaMetrics 默认 staleness 为 5 分钟
# 如果最后一次写入超过 staleness 窗口,查询可能返回空
curl -s "http://localhost:8428/api/v1/query?query=my_metric&step=1m"
15.2.3 查询超时
问题:查询执行超时
# 1. 检查并发查询数
curl -s 'http://localhost:8428/metrics' | grep concurrent_select
# 2. 减少查询复杂度
# - 缩短时间范围
# - 增加标签过滤
# - 使用聚合减少序列数
# 3. 增加超时限制
# 单节点版
victoria-metrics -search.maxQueryDuration=60s
# 集群版
vmselect -search.maxQueryDuration=60s
# 4. 查看慢查询日志
journalctl -u victoria-metrics | grep "slow query" | tail -20
15.2.4 写入被拒绝
问题:客户端收到 429 Too Many Requests 或写入失败
# 1. 检查并发写入数
curl -s 'http://localhost:8428/metrics' | grep concurrent_insert
# 2. 增加并发限制
victoria-metrics -maxConcurrentInserts=64
# 3. 检查磁盘空间
df -h /var/lib/victoria-metrics/
# 低于 -storage.minFreeDiskSpaceBytes 会拒绝写入
# 4. 检查内存使用
free -h
# 内存接近 -memory.allowedPercent 限制时可能降速
# 5. 检查集群版 vminsert 到 vmstorage 的连接
curl http://vminsert:8480/health
15.2.5 磁盘空间不足
问题:磁盘即将耗尽
# 1. 查看磁盘使用详情
du -sh /var/lib/victoria-metrics/data/*
# 2. 查看活跃序列数
curl -s 'http://localhost:8428/api/v1/status/tsdb' | python3 -c "
import json, sys
data = json.load(sys.stdin)
total = data['data']['totalSeries']
print(f'Active series: {total}')
"
# 3. 减少保留期(临时应急)
# 需要重启服务
# -retentionPeriod=30d (原来是 90d)
# 4. 清理高基数标签
# 查看 label 基数
curl -s 'http://localhost:8428/api/v1/status/tsdb' | python3 -c "
import json, sys
data = json.load(sys.stdin)
print('Top labels by cardinality:')
for item in data['data']['seriesCountByLabelName'][:10]:
print(f\" {item['name']:30s} {item['value']}\")
"
# 5. 查看高基数指标
curl -s 'http://localhost:8428/api/v1/status/tsdb' | python3 -c "
import json, sys
data = json.load(sys.stdin)
print('Top metrics by series:')
for item in data['data']['seriesCountByMetricName'][:10]:
print(f\" {item['name']:40s} {item['value']}\")
"
15.2.6 集群组件通信故障
问题:vminsert 或 vmselect 无法连接 vmstorage
# 1. 检查各组件健康状态
curl http://vminsert:8480/health
curl http://vmselect:8481/health
curl http://vmstorage:8482/health
# 2. 检查网络连通性
telnet vmstorage 8400
telnet vmstorage 8401
# 3. 检查防火墙规则
sudo iptables -L -n | grep 840
# 4. 查看 vmstorage 日志
journalctl -u vmstorage | grep "connection refused"
# 5. 检查 vminsert 的 storageNode 配置
# 确保所有 vmstorage 地址正确且可达
15.3 日志分析
15.3.1 日志级别配置
# 日志级别设置
# -loggerLevel: INFO, WARN, ERROR, FATAL
victoria-metrics -loggerLevel=INFO
# 日志输出到文件
victoria-metrics -loggerOutput=file -loggerFilePath=/var/log/victoria-metrics/vm.log
# 日志格式
victoria-metrics -loggerFormat=json # JSON 格式(便于 ELK 等收集)
victoria-metrics -loggerFormat=default # 文本格式
15.3.2 关键日志信息
| 日志关键字 | 含义 | 排查方向 |
|---|---|---|
slow query | 慢查询 | 优化查询或增加资源 |
slow insert | 慢写入 | 检查磁盘 I/O 或减少写入量 |
out of memory | 内存不足 | 增加内存或减少活跃序列 |
disk space | 磁盘空间 | 清理空间或增加存储 |
connection refused | 连接被拒 | 检查目标服务状态 |
too many open files | fd 耗尽 | 增加文件描述符限制 |
permission denied | 权限问题 | 检查文件/目录权限 |
15.3.3 日志分析命令
# 查看最近的错误日志
journalctl -u victoria-metrics -p err -n 50
# 按时间范围查看
journalctl -u victoria-metrics --since "2024-01-15 10:00" --until "2024-01-15 11:00"
# 实时跟踪日志
journalctl -u victoria-metrics -f
# 搜索慢查询
journalctl -u victoria-metrics | grep "slow query" | tail -20
# 搜索 OOM
journalctl -u victoria-metrics | grep -i "memory\|oom" | tail -20
# 统计错误数量
journalctl -u victoria-metrics -p err --since today | wc -l
# JSON 格式日志分析(如果启用了 JSON 格式)
journalctl -u victoria-metrics -o json | python3 -c "
import json, sys
for line in sys.stdin:
entry = json.loads(line)
msg = entry.get('MESSAGE', '')
if 'error' in msg.lower():
print(entry.get('__REALTIME_TIMESTAMP', ''), msg[:200])
"
15.4 诊断 API
15.4.1 健康检查
# 基础健康检查
curl http://localhost:8428/health
# 返回: {"status":"ok"}
# 集群版健康检查
curl http://vminsert:8480/health
curl http://vmselect:8481/health
curl http://vmstorage:8482/health
15.4.2 状态 API
# 构建信息(版本等)
curl -s http://localhost:8428/api/v1/status/buildinfo | python3 -m json.tool
# TSDB 状态(序列数、标签基数等)
curl -s http://localhost:8428/api/v1/status/tsdb | python3 -m json.tool
# 活跃查询列表
curl -s http://localhost:8428/api/v1/status/active_queries | python3 -m json.tool
# 运行时内存统计
curl -s http://localhost:8428/metrics | grep -E "^go_memstats_"
15.4.3 详细指标查询
# 写入速率
curl -s 'http://localhost:8428/api/v1/query?query=rate(vm_rows_inserted_total[5m])' | \
python3 -c "
import json, sys
data = json.load(sys.stdin)
for r in data.get('data', {}).get('result', []):
print(f\"{r['metric']}: {r['value'][1]}\")
"
# 活跃序列数
curl -s 'http://localhost:8428/api/v1/query?query=vm_active_timeseries' | \
python3 -c "
import json, sys
data = json.load(sys.stdin)
for r in data.get('data', {}).get('result', []):
print(f\"Active series: {r['value'][1]}\")
"
# 慢查询速率
curl -s 'http://localhost:8428/api/v1/query?query=rate(vm_slow_queries_total[5m])' | \
python3 -c "
import json, sys
data = json.load(sys.stdin)
for r in data.get('data', {}).get('result', []):
print(f\"Slow query rate: {r['value'][1]}/s\")
"
# 缓存命中率
curl -s 'http://localhost:8428/api/v1/query?query=vm_cache_hits_total/(vm_cache_hits_total+vm_cache_misses_total)' | \
python3 -c "
import json, sys
data = json.load(sys.stdin)
for r in data.get('data', {}).get('result', []):
cache_type = r['metric'].get('type', 'unknown')
hit_rate = float(r['value'][1]) * 100
print(f\"Cache {cache_type}: {hit_rate:.1f}% hit rate\")
"
15.5 性能问题排查
15.5.1 高 CPU 使用
# 1. 查看 CPU 使用率
top -b -n 1 | grep victoria-metrics
# 2. 查看并发查询数
curl -s http://localhost:8428/metrics | grep vm_concurrent
# 3. 限制查询并发
# 添加参数: -search.maxConcurrentRequests=8
# 4. 查看查询统计
curl -s 'http://localhost:8428/api/v1/status/active_queries'
15.5.2 高内存使用
# 1. 查看进程内存
ps aux | grep victoria-metrics
cat /proc/$(pgrep victoria-metrics)/status | grep -E "VmRSS|VmSize"
# 2. 查看活跃序列数(主要内存消耗)
curl -s 'http://localhost:8428/api/v1/status/tsdb' | python3 -c "
import json, sys
data = json.load(sys.stdin)
print(f\"Total series: {data['data']['totalSeries']}\")
print(f\"Label values: {data['data']['totalLabelValuePairs']}\")
"
# 3. 找出高基数标签
curl -s 'http://localhost:8428/api/v1/status/tsdb' | python3 -c "
import json, sys
data = json.load(sys.stdin)
for item in data['data']['seriesCountByLabelName']:
if item['value'] > 10000:
print(f\"WARNING: Label '{item['name']}' has {item['value']} values\")
"
# 4. 调整内存限制
# -memory.allowedPercent=50 (降低允许的内存百分比)
15.5.3 高磁盘 I/O
# 1. 检查磁盘 I/O 使用
iostat -x 1 5
# 2. 查看 Part 数量(过多会导致 I/O 压力)
ls /var/lib/victoria-metrics/data/big/ | wc -l
ls /var/lib/victoria-metrics/data/small/ | wc -l
# 3. 检查合并状态
curl -s http://localhost:8428/metrics | grep merge
# 4. 优化措施
# - 使用 SSD
# - 减少活跃序列数
# - 增加采集间隔(减少写入频率)
15.6 集群问题排查
15.6.1 数据不一致
# 检查各 vmstorage 节点的序列数
for port in 8482 8483 8484; do
echo "vmstorage :${port}:"
curl -s "http://localhost:${port}/api/v1/status/tsdb" | python3 -c "
import json, sys
data = json.load(sys.stdin)
print(f\" Series: {data['data']['totalSeries']}\")
"
done
# 如果某个节点序列数明显不同,可能是:
# 1. 分片不均匀(check vminsert 路由)
# 2. 某个节点曾经不可用
# 3. 数据删除(retention)进度不同
15.6.2 vmstorage 节点不可用
# 1. 检查 vmstorage 健康状态
curl http://vmstorage1:8482/health
# 2. 查看 vminsert 的路由日志
journalctl -u vminsert | grep "unavailable" | tail -20
# 3. 检查 vmstorage 磁盘空间
# 低于 -storage.minFreeDiskSpaceBytes 时 vmstorage 会拒绝写入
# 4. 重启 vmstorage(如果有副本)
sudo systemctl restart vmstorage
# 新加入的节点会自动同步数据
15.7 数据恢复
15.7.1 从损坏中恢复
# 如果数据目录部分损坏
# 1. 停止 VictoriaMetrics
sudo systemctl stop victoria-metrics
# 2. 删除损坏的 Part
# 识别损坏的 Part(通常日志中会有报错)
ls /var/lib/victoria-metrics/data/big/
# 删除包含损坏 Part 的目录
# 3. 重启(VictoriaMetrics 会跳过损坏的 Part)
sudo systemctl start victoria-metrics
# 4. 从备份恢复丢失的数据
vmrestore \
-src=s3://my-bucket/vm-backup/latest/ \
-storageDataPath=/var/lib/victoria-metrics/data
15.7.2 强制合并
# 强制触发 Part 合并(通常不需要手动操作)
# 可以通过临时调整参数实现
# 注意:强制合并会增加 I/O 和 CPU 负载
# 查看当前合并状态
curl -s http://localhost:8428/metrics | grep merge
15.8 排错检查清单
| # | 检查项 | 命令 | 期望结果 |
|---|---|---|---|
| 1 | 服务运行 | curl localhost:8428/health | {"status":"ok"} |
| 2 | 版本 | victoria-metrics --version | 最新稳定版 |
| 3 | 日志 | journalctl -u vm -n 50 | 无 ERROR |
| 4 | 磁盘 | df -h /var/lib/vm/ | > 20% 剩余 |
| 5 | 内存 | free -h | 可用 > 10% |
| 6 | CPU | top -b -n 1 | < 80% |
| 7 | 序列数 | curl /api/v1/status/tsdb | 稳定 |
| 8 | 写入速率 | rate(vm_rows_inserted[5m]) | 正常 |
| 9 | 慢查询 | rate(vm_slow_queries[5m]) | 接近 0 |
| 10 | 缓存 | 缓存命中率 | > 80% |
本章小结
| 要点 | 内容 |
|---|---|
| 排错流程 | 服务状态 → 日志 → API → 资源 → 网络 |
| 日志分析 | journalctl + 关键字过滤 |
| 诊断 API | /health、/api/v1/status/*、/metrics |
| 性能问题 | CPU → 查询并发;内存 → 序列数;I/O → 磁盘/Part |
| 数据恢复 | 从备份恢复,或删除损坏的 Part |