2. 分层审计架构概述:三层架构模型

服务接口的审计,可不是随便写个日志就完事了。我自己做过几个大型平台,一开始都栽在「日志堆成山,查问题像大海捞针」这个坑里。说白了,审计数据需要一套清晰的骨架,把它分层拆开,每一层只干一件事。这样系统才扛得住高流量,也方便后续维护。今天我们就聊聊这套骨架——三层架构模型。

2.1 为什么需要分层?

你想想看,审计数据从产生到最终被分析,中间要经历好几个步骤:收集 → 解析 → 过滤 → 计算 → 存储 → 查询。如果所有逻辑都揉在一起,改一个细节就得重启整个服务,而且一扩容就要把计算和存储一起扩,浪费资源。

我的经验:曾经有个项目把审计处理写在一个大函数里,连 SQL 查询都在采集线程中干。线上流量一上来,数据库直接被打满,排查了半小时才发现是审计逻辑拖垮了业务。从那以后,我再也不敢把采集和存储混着写。

分层之后,每层独立部署、独立扩容、独立优化。采集层只管收数据,分析层只管算指标,存储层只管持久化和查询。谁有问题就修谁,不互相牵连。

2.2 三层架构总览

下面这张图展示了我最常用的三层结构。你可能在别的文档里见过类似的,但里面每个节点的职责,我会结合踩过的坑跟你拆开讲。

服务接口审计三层架构示意图 采集层 API 网关拦截器 · 应用侧 Agent · 消息总线生产者 职责:无侵入捕获请求上下文,原始日志统一输出 分析层 流计算引擎 · 规则引擎 · 聚合 & 脱敏模块 职责:解析协议字段、过滤噪声、计算审计指标、打标签 存储层 时序数据库 · 列式存储 · 冷热分层归档 职责:持久化审计记录,支撑高性能检索与长期保存

关键词:各层解耦、单向数据流、可独立扩缩容

2.3 采集层:第一道关卡

采集层是审计数据的入口。它要做的事,说白了就是在不影响业务的前提下,把请求的「原貌」完整抓下来。

  • 无侵入捕获:我推荐用 API 网关的 Filter 或 Spring 的 Interceptor,不要改业务代码。我在一个老项目里试过埋点 SDK,结果每次升级业务库都得跟着改,维护成本翻倍。
  • 原始日志输出:采集层只做「追加」不做「解析」。把 HTTP method、URL、header、body、响应状态、耗时、时间戳一股脑写到统一格式(比如 JSON 行),然后推到消息队列。
  • 限流与降级:审计不能拖垮主业务。采集层如果推消息队列超时,应该直接抛弃数据而不是阻塞请求。我曾经因为审计采集超时导致上游调用链雪崩,后来加了超时熔断才解决问题。

注意:采集层不要做任何聚合、过滤或数据清洗。这些应该交给分析层。在采集层做计算,既增加延迟又容易丢失原始凭证。

2.4 分析层:真正的「审计脑」

分析层拿到原始数据后,开始干活。它是三层里最复杂的,也是我花最多时间调优的地方。

子模块职责常见实现
协议解析器自动识别 HTTP/RPC/DB 协议字段正则、protobuf 反射、Avro schema
规则引擎匹配审计策略(如敏感操作、频率异常)Drools、自研 DSL、状态机
聚合器按用户/接口/时间窗口统计次数、流量Flink 窗口、Spark Streaming
脱敏模块将密码、身份证等敏感字段自动替换影子字段、掩码算法(保留格式)

一定要保证分析层是可重入的。什么意思?同一个审计记录因为网络延迟被消费两次,最终结果不能翻倍。我在 Flink 中设置过幂等性标识,用 requestId 做去重,虽然牺牲了一点吞吐,但规避了重复审计的麻烦。

我的一个避坑指南:规则引擎的规则不要硬编码在代码里。曾经我把某个接口的审计阈值写死在 if 语句中,后来业务改了阈值,我们得发版才能生效。改成配置中心 + 热加载后,改规则只需要在管理后台点一下。

2.5 存储层:让数据看得见、查得快

分析层产出的审计记录,最终要落到存储层。存储层的设计直接影响审计查询的体验。

  • 时序数据库首选:审计数据天然带时间戳,按时间范围查询频率极高。用 InfluxDB 或 TimescaleDB,比 MySQL 快一个数量级。
  • 列式存储冗余:对于需要「全量回溯」的场景(比如安全事件调查),我会把原始审计记录同步一份到 ClickHouse 或 Parquet 文件,利用列存的高压缩比节省空间。
  • 冷热分层:90% 的审计查询集中在最近 7 天。更旧的数据自动迁移到 S3 或廉价 HDD,按天分表。查询时用视图透明访问,用户无感知。

重要:别忘了给存储层加「写入限流」。审计量可能在业务大促时飙升 5 倍,如果存储层扛不住直接 OOM,所有审计记录都丢了。我一般会在写入端放一个令牌桶,超过 80% CPU 的请求直接降级为本地文件缓冲。

2.6 层间交互:单向流水线

三层之间的数据流动必须是单向的:采集层 → 分析层 → 存储层。不允许分析层直接往回写采集层,也不允许存储层调用分析层的接口。这样每层都可以独立升级、独立压测。

交互的「媒介」我通常会选消息队列(Kafka / Pulsar)。

  1. 采集层写入 Kafka topic「raw-audit」
  2. 分析层消费「raw-audit」,处理后写入 Kafka topic「processed-audit」
  3. 存储层消费「processed-audit」并落库

这种异步解耦还有一个好处:分析层挂了一台机器,不会影响采集层的写入速度。存储层瞬时写入压力大,消息队列也能帮忙削峰填谷。

一句话总结:采集层负责「快」,分析层负责「准」,存储层负责「稳」。各层各司其职,审计系统才能真正扛住千万级 QPS 的考验。