一个轻量级变更感知 SaaS 的设计与实现

一个轻量级变更感知 SaaS 的设计与实现


github: https://github.com/TongTsing/cmdb_watch_service

一、项目背景

在传统运维和 CMDB(配置管理数据库)体系中,数据通常具备以下特点:

  • CMDB 是被动数据源
  • 下游系统依赖定时轮询(Polling)
  • 变更缺乏统一抽象与表达

这带来的直接问题是:

  • 变更无法实时感知
  • 自动化能力弱(只能“查”,不能“响应”)
  • 审计链路不完整
  • 系统之间高度耦合

从架构视角看,本质问题是:

系统围绕“数据”构建,而不是围绕“变化”构建

因此,本项目的核心目标是:

将 CMDB 从“数据源”升级为“事件源”


二、设计目标

我们希望构建一个轻量但具备演进能力的系统,实现:

  • 变更自动检测(Diff)
  • 变更事件化(Event)
  • 事件驱动处理(Handler)
  • 模块解耦(EventBus)

最终达到:

变更 → 事件 → 自动处理


三、核心功能

1️⃣ CMDB 数据监听(Watcher)

Watcher 负责周期性拉取 CMDB 数据,并根据规则筛选目标资源:

  • 按 Model(资源模型)监听
  • 按 Rule(规则)过滤
  • 支持多个 Watcher 并行运行

Watcher 本质是:

数据采集器(Pull)


2️⃣ 数据差异检测(Diff Engine)

系统通过对比:

旧数据(历史快照) vs 新数据(当前数据)

识别三类变化:

  • 新增(Create)
  • 修改(Update)
  • 删除(Delete)

并生成字段级差异:

FieldChange(
    field="ip",
    old_value="1.1.1.1",
    new_value="2.2.2.2"
)

这一步的关键价值在于:

将“数据变化”转化为“结构化语义”


3️⃣ 领域事件(Domain Events)

系统将变更抽象为领域事件:

CreatedEvent
UpdatedEvent
DeletedEvent

每个事件具备完整业务语义:

  • watcher_id(来源)
  • model(资源模型)
  • instance_id(实例 ID)
  • changes(仅 Update 具备)


为什么不使用统一 ChangedEvent?

我们曾考虑:

ChangedEvent(event_type=CREATE/UPDATE/DELETE)

但最终选择拆分为多个事件类型,原因是:

  1. 消除 handler 中的 if/else 分支
  2. 不同事件具备不同语义(如 Update 才有 changes)
  3. 支持类型驱动路由(EventBus)

这一步是从:

数据建模 → 行为建模

的关键跃迁。



4️⃣ 事件总线(EventBus)

EventBus 负责事件分发与路由:

EventBus
   ↓
UpdatedEvent → AuditHandler
              → EmailHandler
              → LogHandler

核心能力:

  • 按事件类型路由
  • 支持多个 Handler
  • 异常隔离(单个 handler 失败不影响整体)


EventBus 的本质

EventBus 并不是一个“工具类”,而是:

系统解耦的边界

它将系统从:

A → B(直接调用)

转变为:

A → Event ← B

这意味着:

  • 发布者不再关心消费者
  • 系统耦合度显著降低
  • 功能扩展无需修改核心逻辑


5️⃣ Handler 机制(可扩展处理)

Handler 用于消费事件,实现具体业务逻辑:

Handler功能
EmailHandler发送通知
AuditHandler记录审计
LogHandler输出日志
WebhookHandler对接外部系统


Handler 模式的工程价值

在实际工程中,Handler 带来的优势非常明显:

  • 新增功能 = 新增 Handler(无需修改已有代码)
  • 避免 WatchService 膨胀(不变成“上帝类”)
  • 支持多策略并行演进

例如:

  • 通知系统可以独立优化
  • 审计系统可以独立存储
  • 外部集成可以按需扩展


四、系统架构设计

系统采用简化版 DDD 分层:

Domain(领域层)
 └── Event(事件定义)

Application(应用层)
 └── WatchService(编排逻辑)

Infrastructure(基础设施层)
 └── WatchClient(CMDB 接口)

Shared(通用层)
 └── EventBus(事件分发)


分层职责说明

  • Domain定义业务语义(Event)不依赖任何外部系统
  • Application编排流程(Watcher → Diff → Event)触发事件发布
  • Infrastructure负责获取外部数据(CMDB API)
  • Shared提供通用能力(EventBus)


一个关键原则

Event 是三层之间的唯一桥梁


五、核心设计思想

1️⃣ 事件驱动(Event-Driven)

系统流程:

CMDB变化
   ↓
Watcher检测
   ↓
生成事件
   ↓
EventBus分发
   ↓
Handler处理


2️⃣ 类型驱动(Type-based Routing)

传统方式:

event_type + if/else

当前设计:

事件类型 = 类本身

优势:

  • 无分支判断
  • 强类型约束
  • 易扩展


3️⃣ 单一职责原则

  • WatchService:发现变化
  • Event:表达变化
  • Handler:处理变化


4️⃣ 不可变事件(Immutable Event)

事件使用:

@dataclass(frozen=True)

带来:

  • 不可变性(安全)
  • 可追溯性
  • 易调试


六、系统优势

✅ 1. 高扩展性

新增能力无需修改核心代码:

  • 新事件类型
  • 新 Handler
  • 新通知方式


✅ 2. 解耦设计

模块完全独立:

Watcher ≠ EventBus ≠ Handler


✅ 3. 精细变更感知

通过 FieldChange 实现:

  • 字段级 diff
  • 精准通知
  • 审计支持


✅ 4. 支持架构演进(Evolutionary Architecture)

系统可以平滑升级:

阶段1(当前):

  • 内存 EventBus(同步)

阶段2:

  • AsyncEventBus(线程池/协程)

阶段3:

  • Kafka / Redis Stream(分布式)

👉 上层业务无需修改



七、典型应用场景

  • CMDB 变更通知
  • 运维自动化触发
  • 审计日志系统
  • 安全合规监控
  • 外部系统联动(Webhook)


八、当前限制与演进方向

当前系统仍有一些工程限制:

  • EventBus 为同步调用(阻塞)
  • 无事件持久化(不可回放)
  • 无失败重试机制
  • 无幂等保障

下一阶段优化方向:

  • 引入异步 EventBus
  • 增加事件存储(Event Store)
  • 引入消息中间件(Kafka)
  • 增强可靠性(重试 / DLQ)



文章标签:

评论(0)