巡检系统架构:组件、数据流与定时机制
一个成熟的盲索引审计日志巡检系统,背后是一整套组件协作。我见过不少团队把巡检简单看作“写个脚本跑定时任务”,结果日志一多就崩、告警乱飞。说白了,架构设计不到位,后面排查问题会非常痛苦。
核心组件拆解
系统主要由四个模块组成:
| 组件 | 职责 | 常见实现 |
|---|---|---|
| 采集器 | 从数据库审计日志文件中拉取增量数据 | Filebeat、自定义tail-alike、JDBC轮询 |
| 解析器 | 将原始日志行拆成结构化字段 | 正则匹配、SQL语法树解析、JSON日志直接映射 |
| 存储引擎 | 缓冲并持久化解析后的索引数据 | Elasticsearch、ClickHouse、本地RocksDB |
| 告警引擎 | 比对阈值、聚合规则,触发通知 | Prometheus Alertmanager、自建规则引擎 |
| 调度器 | 驱动整个巡检周期的轮询节奏 | Linux cron、Quartz、Kubernetes CronJob |
这里要注意:采集器和解析器往往耦合在一起,除非日志格式异常复杂。我个人习惯把解析器单独抽成一个微服务,方便后续适配不同厂家的审计日志。
数据流:从日志行到告警消息
一次完整的巡检数据流是这样的:
- 采集 —— 调度器触发,采集器读取上一次检查点之后的增量日志。
- 解析 —— 逐行解析出操作语句、用户、时间、影响行数等关键字段。
- 盲索引标记 —— 对每条SQL判断是否涉及缺少合适索引的查询,打上“盲索引”标签。
- 汇总聚合 —— 按时间窗口(比如5分钟)统计每个数据库/用户的盲索引次数。
- 阈值比对 —— 如果聚合值超过预设阈值,生成告警事件。
- 通知 —— 通过邮件、钉钉、Webhook将告警推送给DBA。
关键点:检查点(checkpoint)必须落盘且持久化。我曾见过采集器重启后丢失检查点,导致重复分析大量历史日志,把Elasticsearch干挂了。
技巧:数据流中容易忽略的是“元信息传递”。比如解析器应该把原始日志行号也传到下游,方便定位具体出问题的SQL。我踩过这个坑,光告警说‘盲索引增多’,找不到是哪条SQL,排查效率极低。
定时机制:别让巡检变成黑夜里的定时炸弹
调度器决定了巡检周期的开始和结束。常见模式有:
- 固定间隔轮询:每5分钟跑一次,检查过去5分钟的增量。
- 定点触发:每天凌晨2点跑一次全量检查(用于统计昨日的离线分析)。
- 事件驱动+补采:收到数据库日志轮转信号后立即采集,若失败则回退定时重试。
我个人偏向采用“固定轮询 + 防抖”。为什么呢?因为数据库审计日志的生成往往存在延迟,尤其是主从架构下,从库的日志有时会晚几十秒。如果轮询间隔太短,每次都读不到新数据,浪费资源;太长又会导致告警滞后。我一般设置轮询周期为日志生成延迟的2倍,再配合一个“最小间隔”兜底。
警告:千万不要把调度器时间设成精确到秒,而且同时所有采集任务都在整点启动。我曾经见过一个系统,每分钟的00秒启动1000个任务的定时扫描,导致数据库服务器IO飙到100%。建议加随机偏移量,比如在每个周期内均匀撒开启动时间。
生产环境经验浓缩
最后总结几个我亲手排过的坑:
- 检查点只存内存 —— 进程重启后重新扫描过去所有日志,造成重复告警。
对策:用本地文件或数据库记录每次采集的最大日志偏移量。 - 解析器正则回溯 —— 一条超长SQL导致解析耗时从毫秒级变成秒级,阻塞后续采集。
对策:设置解析超时,超时后跳过该条,记录异常行号后台人工处理。 - 告警风暴 —— 某个表结构变更后大量查询变成全表扫描,阈值触达后连续告警几百条。
对策:实现告警静默期(比如同一类型告警5分钟内只发一次)。 - 存储引擎写入积压 —— 采集速度远超写入速度,内存队列溢出丢数据。
对策:加入背压机制,当存储引擎响应变慢时,采集器自动降频。
嗯,差不多就是这些。巡检系统架构看起来简单,但每个环节都可能藏着让你半夜爬起来的问题。下次遇到异常,先从组件存活、数据流顺序、定时配置三个方向捋一遍,大部分问题都能定位。