Files
ai-security-xdr/haobang-security-dm/upgrade-doc/v5/03-syslog-wal-diagnostics.md
王绍宏 8f1a8b6283 feat(syslog): 增加 WAL 与分 IP 接入诊断
- 每分钟保存 WAL 全局状态和分 IP 接收统计,历史保留 7 天
- 记录接收、WAL 落盘、Kafka ACK、过滤、背压及丢弃数量
- 增加 wal_max_pending_bytes 和 wal_admission_unavailable 指标
- 增加 TCP pending 当前值及进程内峰值统计
- 网络异常后同一 IP 恢复接收时打印恢复日志
- 提供当前状态及按日期查询诊断历史的接口
- 连接关闭时清理 TCP pending 计数并停止无效重试
- 增加相关单元测试和现场排查文档
2026-09-16 17:32:08 +08:00

143 lines
5.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Syslog WAL 与分 IP 诊断历史
## 功能范围
`syslog-serve` 每分钟保存一次全局 WAL 状态,并按来源 IP 保存接收、WAL 持久化、Kafka ACK、过滤、背压、丢弃和 TCP 异常计数。网络异常发生时立即写入事件文件。
某个来源 IP 抛出网络接入异常后,如果后续重新收到该 IP 的数据,服务会打印一次
`Syslog 网络接入异常后已恢复接收` 日志,并包含异常时间、恢复时间和两者间隔。该机制不根据无数据时长推断断网,也不生成离线统计;连续正常数据不会重复打印恢复日志。
诊断文件不经过 Kafka 和数据库,默认写入容器目录 `/app/logs/syslog-monitor`。生产编排已将 `/app/logs` 映射到宿主机 `/home/syslog/logs`,因此容器重启不会删除历史。文件按自然日生成,保留今天及此前 6 天,共 7 天。
诊断记录不包含日志正文、凭据或 Kafka 消息内容。
## 文件目录
```text
/home/syslog/logs/syslog-monitor/
├── snapshots/syslog-status-YYYY-MM-DD.jsonl
├── ip-snapshots/syslog-ip-status-YYYY-MM-DD.jsonl
└── events/syslog-events-YYYY-MM-DD.jsonl
```
- `snapshots`:全局 WAL、磁盘和 Kafka 投递状态,每分钟一行。
- `ip-snapshots`:每个来源 IP 每分钟一行,包含进程累计值与相邻快照增量 `delta`。
- `events`:`TOO_LONG_FRAME`、`CONNECTION_RESET`、超长消息和最终设备过滤等即时事件。
每次进程启动生成新的 `instance_id`,并记录 `process_start_time`。对累计值进行跨重启分析时必须按 `instance_id` 分段。
## 部署配置
生产默认值:
```yaml
environment:
- SYSLOG_DIAGNOSTICS_DIRECTORY=/app/logs/syslog-monitor
- SYSLOG_DIAGNOSTICS_RETENTION_DAYS=7
```
可选参数:
```text
SYSLOG_DIAGNOSTICS_ENABLED=true
SYSLOG_DIAGNOSTICS_SNAPSHOT_INTERVAL_MS=60000
SYSLOG_DIAGNOSTICS_MAX_SOURCE_IPS=10000
SYSLOG_DIAGNOSTICS_EVENT_QUEUE_CAPACITY=10000
```
来源 IP 超过上限后,新 IP 的指标汇总到 `__OTHER__`,避免伪造 UDP 来源导致内存无限增长。事件队列满时不会阻塞 Netty 接入线程,丢弃的诊断事件数量通过 `event_queue_dropped` 暴露。
## 现场查询
### 第一步:检查诊断持久化是否正常
```bash
docker exec syslog-serve-dm sh -c \
"curl -fsS http://127.0.0.1:8189/syslogserve/api/syslog/wal/diagnostics/current"
```
确认以下字段:
```text
persistence.enabled = true
persistence.active = true
persistence.retention_days = 7
persistence.initialization_failures = 0
persistence.snapshot_write_failures = 0
persistence.event_write_failures = 0
persistence.event_queue_dropped = 0
persistence.last_write_error = null
```
### 第二步:查询单个来源 IP
```bash
docker exec syslog-serve-dm sh -c \
"curl -fsS 'http://127.0.0.1:8189/syslogserve/api/syslog/wal/diagnostics/current?source_ip=10.56.170.107'"
```
主要字段:
```text
network_received
wal_appended
wal_admission_backpressure
wal_admission_unavailable
kafka_acked
invalid_device_dropped
oversized_dropped
udp_dropped
tcp_pause_total
tcp_pending_frames_current
tcp_pending_frames_max
network_exception_total
tcp_network_exception_total
udp_network_exception_total
tcp_connection_reset_total
tcp_too_long_frame_total
dispatch_terminal_dropped
dispatch_retry
last_receive_time
last_exception_time
```
`wal_appended` 只在 WAL 完成持久化后增加;`kafka_acked` 只在 Kafka 明确 ACK 后增加。
全局状态还包含 `wal_pending_bytes`、`wal_max_pending_bytes`。前者是当前待落盘字节数,后者是配置上限,配置为 `0` 表示不限制。`wal_admission_unavailable` 表示 WAL 因未运行、致命错误或磁盘进入 `CRITICAL` 而拒绝接入尝试的次数;TCP 会保留并重试待处理帧,因此该值不等于 TCP 丢失消息数。`tcp_pending_frames_current` 是当前在 TCP Handler 内等待进入 WAL 的帧数,`tcp_pending_frames_max` 是当前进程启动以来的峰值;连接关闭时未处理帧会从 current 中回减。
### 第三步:查询当天历史
直接在宿主机按 IP 查询:
```bash
grep -F '"source_ip":"10.56.170.107"' \
/home/syslog/logs/syslog-monitor/ip-snapshots/syslog-ip-status-2026-09-16.jsonl
```
查询该 IP 的异常事件:
```bash
grep -F '"source_ip":"10.56.170.107"' \
/home/syslog/logs/syslog-monitor/events/syslog-events-2026-09-16.jsonl
```
也可以通过 HTTP 下载:
```text
GET /syslogserve/api/syslog/wal/diagnostics/history?date=2026-09-16&type=snapshots
GET /syslogserve/api/syslog/wal/diagnostics/history?date=2026-09-16&type=ip
GET /syslogserve/api/syslog/wal/diagnostics/history?date=2026-09-16&type=events
```
## 计数对账
同一 `instance_id` 下:
```text
有效设备 WAL 持久化量 ≈ wal_appended
成功发往 Kafka 的数量 = kafka_acked
当前实例尚未 ACK 的近似数量 = wal_appended - kafka_acked - dispatch_terminal_dropped
```
重启后可能重放旧 WAL,因此分 IP 的 `kafka_acked` 可能暂时大于本实例的 `wal_appended`。此时以全局 `wal_pending_approx`、WAL 序号以及 `instance_id` 为准,不应把负差值解释为异常。