2. SDK架构设计原则:分层架构、模块划分、扩展点设计、与业务系统的解耦方法

好,我们正式开始第二章。上一章我们聊了审计SDK的价值和整体定位,这一章要深入到具体的设计层面。

说白了,架构设计决定了这个SDK的生命力。我见过太多“一次性”SDK——刚交付时挺好,半年后业务一改,SDK就得大动干戈重构。为什么会这样?因为架构上没想清楚。

今天我要把这几年在数据安全领域摸爬滚打的经验拆开来讲。核心就四个词:分层、模块、扩展、解耦。

2.1 分层架构:从底层到上层的“仪表盘思维”

我个人习惯,设计任何SDK都先画三层:接入层、审计层、存储层。为什么要这么分?你想想看,三层之间互相隔离,每一层出了问题不影响其他层。

层级 职责 关键关注点
接入层 拦截/采集业务系统的数据访问请求 性能损耗最小化、API兼容性
审计层 解析、过滤、格式化、策略匹配 规则引擎的灵活性、实时性
存储层 日志写入、缓存、重试、离线归档 数据不丢失、写入性能、存储成本

核心原则:上层只能依赖下层,下层绝不能反过来调用上层。这就像仪表盘的指针——上层知道下层做了什么,下层只管做好自己的事。

2.2 模块划分:四个核心模块

每一层里要做什么?我习惯把功能拆成四个核心模块:

  1. 事件采集模块 —— 管“怎么拿到数据”
  2. 策略引擎模块 —— 管“哪些该记,哪些不该记”
  3. 数据持久化模块 —— 管“记在哪里,多久能取”
  4. 结果上报模块 —— 管“记完之后怎么通知外部”

嗯,这里要注意。四个模块之间也是松耦合的。我在一个项目中遇到过,业务方要求“策略引擎必须在50微秒内返回结果”,如果我们把策略引擎跟持久化绑在一起,50微秒根本做不到。

我的经验:每个模块都只暴露接口,不暴露实现。这样替换、升级、测试都方便。比如持久化模块,今天用MySQL,明天换成Elasticsearch,上层模块不需要改任何代码。

2.3 扩展点设计:给别人留一条路

我相信每个SDK都会面临一个尴尬:你设计的规则,永远覆盖不了业务的全部场景。怎么办?留扩展点。

常见的扩展点有三种:

  • 策略扩展:允许业务方自定义过滤/脱敏/报警策略
  • 输出扩展:允许业务方自定义日志输出格式或目标
  • 上下文扩展:允许业务方注入自定义的业务上下文信息

我曾经遇过一个金融客户,要求审计日志里必须包含“交易渠道”和“风控等级”这两个字段。标准SDK没有,但因为我们设计了上下文扩展点,他们只需要实现一个接口,注入一个JSON对象,就搞定了。

// 上下文扩展点接口示例
public interface AuditContextExtender {
    Map<String, Object> extend(AuditEvent event);
}

说白了,扩展点的设计是“给别人留一条路,也给自己留一条后路”。

2.4 与业务系统的解耦方法

这是我最想强调的一点。SDK一旦集成到业务系统,如果解耦没做好,业务改一点,SDK就要重来。这不是我们要的。

我总结三个解耦方法:

  1. 异步化:采集和上报必须异步。业务线程只管产生事件,不要把审计挂到业务流程里。
  2. 配置化:所有策略、开关、目标地址,全从配置文件或配置中心拿,不硬编码。
  3. 错误隔离:SDK内部出错,绝不抛到业务线程。日志记到自己的异常日志里就好。

避坑提醒:我曾经在一家电商公司看到,SDK在同步写日志时抛了异常,直接导致下单接口500。这就是典型的耦合过深。记住——SDK只能“锦上添花”,绝不能“雪中送炭”。

2.5 一张图看懂整体架构

好,理论讲了不少,我画一张图把这些关系串起来。

SDK分层架构与解耦关系 业务系统(业务线程) 接入层 事件采集模块 · 上下文扩展点 异步队列 · 非阻塞采集 审计层 策略引擎模块 · 过滤 · 脱敏 · 格式化 策略扩展点 · 规则热更新 存储与输出层 数据持久化模块 · 结果上报模块 输出扩展点 · 批处理 · 重试 · 离线归档 关键解耦点:异步采集 | 错误隔离 | 配置化驱动 | 扩展点注入 | 上下层不反向依赖

2.6 落地建议:先从最简单的分层开始

我不建议一上来就追求完美。如果你刚开始设计审计SDK,先做到接入层和审计层分开,把存储层用最简单的文件日志先跑起来。等业务稳定了,再考虑扩展点和多策略引擎。

我在一个创业项目里就是这么干的。第一版只有接入层+文件输出,一共2000行代码。三个月后加了策略引擎,六个月后加了ES输出。因为架构是分层的,每次加东西都很顺。

记住一个原则:分层决定骨架,模块决定肌肉,扩展点决定弹性,解耦决定寿命。

小结:这一章我们讲了分层架构(接入、审计、存储)、四个核心模块、三类扩展点、三种解耦方法。下一轮你拿到任何业务场景,先画这三层,再往里填模块,准没错。