Files
ai-security-xdr/haobang-security-dm/upgrade-doc/v3/README.md
T
王绍宏 c868e3befd feat(syslog): 优化大日志通道并增加异常连续消费兜底
- 128 KiB 及以上日志默认进入大日志 Topic
- InfluxDB 原文及达梦大字段超过 256 KiB 时截断保存
- 截断内容追加 HB_XDR_TRUNCATED 标记
- InfluxDB 写入失败时继续执行规则解析和达梦写入
- 未知或系统性异常优先写入普通/大日志 DLT
- DLT 写入失败时记录特殊告警并提交 offset,避免阻塞后续消息
- DLT 失败等待时间默认限制为 1 秒
- 增加连续性放行、DLT 成功及失败监控指标
- 更新 Docker Compose、v3 升级文档及相关测试
2026-09-12 19:24:58 +08:00

203 lines
7.4 KiB
Markdown
Raw 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.
# v3 日统计异步投影与大日志通道升级说明
## 升级内容
v3 将以下统计表的热点更新移出 `syslog-consumer-rule` 事实事务:
- `device_daily_stats`
- `normalize_rule_daily_stats`
- `device_collect_stats`
事实事务只批量写事实表并追加一条聚合 Outbox。独立的 Kafka 投影消费者串行更新日统计,之后继续通过
已有的 `STATS.MATERIALIZE` Topic 刷新 `device_device`、`dm_normalize_rule` 和
`device_collect_task`。这样三台 `syslog-consumer-rule` 可以并行写事实,不再同时争抢相同日统计行锁。
v3 同时增加大日志独立处理链路:
- `syslog-serve` 在进入 WAL 前执行单条硬上限检查;超过上限明确拒绝,不把原文写入应用日志;
- 接纳后的消息仍先进入 `syslog-serve` 本地 WAL,WAL 入队和 Kafka 投递同时受条数、字节数约束;
- 达到分流阈值的消息进入独立 `.large` Topic,其 Retry、DLT、Replay 也使用独立 Topic;
- `syslog-consumer-rule` 使用独立的大日志 listener、消费组、ConsumerFactory、poll 批量和规则计算线程池;
- 规则解析使用完整内容,写 InfluxDB 和达梦前才按 UTF-8 字节数截断,结尾带
`HB_XDR_TRUNCATED` 标记;InfluxDB 另存原长度、保存长度和原文 SHA-256。
- 消费端默认采用连续性优先策略:无法理解或系统性异常先尝试写入 DLT;即使 DLT 失败,也记录
`[SYSLOG_CONTINUITY_LOSS]` 后推进 offset,避免单条异常永久阻塞整个分区。
## 文件与执行顺序
| 顺序 | 文件 | 作用 |
| --- | --- | --- |
| 1 | `database/01-stats-async-projection-precheck.sql` | 只读预检 |
| 2 | `database/02-stats-async-projection-upgrade.sql` | 创建 Outbox 和消费幂等表 |
| 3 | `database/03-stats-async-projection-verify.sql` | 只读验证表、约束和索引 |
| 4 | `kafka/01-create-stats-projection-topic.sh` | 创建独立统计投影 Topic |
| 5 | `kafka/02-create-large-log-topics.sh` | 创建大日志主 Topic 及独立 Retry、DLT、Replay Topic |
| 6 | `config/01-new-environment-variables.md` | 升级应用前配置新增环境变量,并核对 Kafka Broker 参数 |
数据库脚本必须使用 `syslog-consumer-rule` 实际连接的达梦用户执行。
如果现场已经执行过早期 v3 日统计异步投影升级,只执行 `kafka/02-create-large-log-topics.sh` 和本页的
大日志应用配置、验证步骤;不要重复执行数据库升级脚本。
## 第一步:达梦
依次执行:
```text
01-stats-async-projection-precheck.sql
02-stats-async-projection-upgrade.sql
03-stats-async-projection-verify.sql
```
预检判断:
- 第一组应返回 `DEVICE_DAILY_STATS`、`NORMALIZE_RULE_DAILY_STATS`、`DEVICE_COLLECT_STATS` 三行;
- 后面三组必须为空;
- 如果目标表、约束或索引已经存在,不要执行 `02`,先执行 `03` 判断是否已经升级完成。
验证判断:
- 返回两张新表;
- 三个约束状态为 `ENABLED`;
- 两个索引状态为 `VALID`;
- 首次建表时两张表的行数都是 0。
## 第二步:Kafka
### 统计投影 Topic
在 Kafka 主机的 `kafka_2.13-3.6.1/bin` 目录执行:
```bash
bash /脚本所在路径/01-create-stats-projection-topic.sh
```
默认创建:
```text
agent-01-syslog-topic.STATS.PROJECTION
```
新建时为 1 个分区,副本数沿用 `agent-01-syslog-topic`。如果现场此前已经建成 6 个分区,脚本只告警,
不会修改或删除;应用使用固定 Kafka key,投影事件仍然只落入其中一个稳定分区。
必须看到:
```text
PASS: agent-01-syslog-topic.STATS.PROJECTION 已创建/确认。
```
`STATS.PROJECTION` 不能与已有的 `STATS.MATERIALIZE` 配成同一个 Topic。
### 大日志 Topic
先确认所有 Kafka Broker 的 `replica.fetch.max.bytes` 不小于 `33554432`,并按现场 Kafka 版本要求使
配置生效。然后执行:
```bash
bash /脚本所在路径/02-create-large-log-topics.sh
```
脚本默认从 `agent-01-syslog-topic` 读取分区数和副本数,并创建:
```text
agent-01-syslog-topic.large
agent-01-syslog-topic.large.RETRY.1M
agent-01-syslog-topic.large.RETRY.10M
agent-01-syslog-topic.large.RETRY.1H
agent-01-syslog-topic.large.DLT
agent-01-syslog-topic.large.REPLAY
```
必须看到:
```text
PASS: 大日志 Topic 已创建并统一配置。
```
## 第三步:升级应用
升级 `syslog-serve` 和三台 `syslog-consumer-rule`;`syslog-consumer` 不需要因为本次改造升级。
升级前先按 [新增变量配置清单](./config/01-new-environment-variables.md) 修改现场实际使用的 Compose 文件。
三台 `syslog-consumer-rule` 的 Topic、消费组和截断上限必须保持一致。
统计投影默认已经启用。确认现场没有显式配置:
```text
STATS_PROJECTION_ASYNC_ENABLED=false
```
先逐台升级 `syslog-consumer-rule`,可以启动一台观察后再升级另外两台;确认大日志 listener 正常后再
升级 `syslog-serve`。新旧版本滚动期间,同一条原始 Kafka 消息只会被消费组中的一个实例处理,不会因为
滚动升级重复统计。
## 升级后验证
查看处理日志:
```bash
docker logs --since 2m syslog-consumer-rule-dm 2>&1 \
| grep -E 'Syslog批次完成|统计投影批次完成|统计物化批次完成|Outbox|Deadlock' \
| tail -100
```
查看 Outbox 状态:
```sql
SELECT status, COUNT(*)
FROM stats_projection_outbox
GROUP BY status
ORDER BY status;
```
正常表现:
- 日志持续出现 `统计投影批次完成`;
- `APPLIED` 持续增长;
- `PENDING`、`PUBLISHED` 只短暂停留,不持续增长;
- `FAILED` 不持续增长;
- `Syslog批次完成` 中 `dmWriteMs` 明显下降;
- 不再出现 daily stats 相关死锁。
查看新消费组积压:
```bash
./kafka-consumer-groups.sh \
--bootstrap-server 10.141.121.35:9092,10.141.121.50:9092,10.141.121.59:9092 \
--group agent-01-syslog-group-dm-stats-projection \
--describe
```
验证大日志链路:
- `GET /syslogserve/api/syslog/wal/status`:检查 `wal_admission_oversized`、`wal_pending_bytes`、
`dispatch_inflight_bytes`、`kafka_large_dispatched`;
- `GET /xdrrule/api/syslog/raw-storage/metrics`:检查 `raw_message_truncated_total` 及截断前后字节累计值;
- `GET /xdrrule/api/syslog/storage-limits/metrics`:检查达梦正常/非标字段截断计数;
- 发送一条不小于 128 KiB、但小于 6 MiB 的测试消息,确认 `.large` Topic 有数据且普通 Topic 无该事件;
- 查询 InfluxDB/达梦,确认被截断值以 `...[HB_XDR_TRUNCATED original_utf8_bytes=...]` 结尾。
连续性指标也位于 `GET /xdrrule/api/syslog/raw-storage/metrics`:
- `raw_write_bypassed_messages_total`:InfluxDB 原文写失败后仍继续标准化的消息数;
- `continuity_dlt_published_total`:特殊异常成功写入 DLT 的消息数;
- `continuity_dlt_publish_failed_total`:DLT 写失败但仍放行的消息数。该值增加时应立即检查 Kafka/DLT,
对应消息可能无法自动重放。
## 回滚
回滚最后一台新版本前,先确认 Outbox 没有未应用事件:
```sql
SELECT status, COUNT(*)
FROM stats_projection_outbox
WHERE status <> 'APPLIED'
GROUP BY status;
```
查询为空后再回滚最后一台。两张新表、Kafka Topic 和消费组 offset 全部保留,不要删除或重置。
回滚旧版本前,还要先停止新生产者并排空 `.large` 主 Topic;大日志 Topic 和消费组 offset 同样保留,
不要删除或重置。