一个轻量级变更感知 SaaS 的设计与实现
已于 2026年03月26日 21:05 修改
访问次数:0
一个轻量级变更感知 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)
但最终选择拆分为多个事件类型,原因是:
- 消除 handler 中的 if/else 分支
- 不同事件具备不同语义(如 Update 才有 changes)
- 支持类型驱动路由(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)