3. 事件驱动架构基础:Event、Event Bus、Event Sourcing 与 CQRS 简介

在分布式系统与微服务架构中,服务间的通信方式决定了系统的耦合度、扩展性与容错能力。事件驱动架构(Event-Driven Architecture, EDA)通过将状态变更封装为不可变的事件,实现了服务间的异步、松耦合通信。本章将系统梳理 EDA 的四个核心概念:Event、Event Bus、Event Sourcing 与 CQRS,为后续跨服务熔断传播与隔离设计奠定理论基础。

3.1 核心概念:Event(事件)

事件是 EDA 中最基本的通信单元,代表“已经发生的事情”。在微服务中,事件通常由某个服务在完成业务操作后发布,其他服务通过订阅来感知并做出响应。

特性 说明 示例
不可变性 事件一旦生成,内容不可修改 OrderCreated 事件生成后,订单 ID 与金额固定
自描述性 事件包含足够上下文,消费者无需查询源服务 事件体中携带 orderId、userId、totalAmount
时间戳 记录事件发生的精确时间 occurredAt: 2025-03-21T10:30:00Z
幂等键 唯一标识,用于消费者去重 eventId: uuid-v4
设计原则:事件应使用过去时态命名(如 PaymentProcessed、InventoryReserved),避免使用命令式(如 ProcessPayment)。事件是事实记录,而非请求指令。

3.2 事件通道:Event Bus(事件总线)

Event Bus 是事件在服务间传递的中介层,负责事件的接收、路由、过滤与投递。它解耦了事件发布者与订阅者,使双方无需感知彼此的网络地址与生命周期。

3.2.1 核心功能

  • 发布/订阅(Pub/Sub):支持一对多的消息分发模式。
  • 路由规则:基于事件类型、标签或内容进行精确或模糊匹配。
  • 持久化与重试:确保事件在消费者故障时不丢失,支持死信队列。
  • 顺序保证:在分区(Partition)级别维持事件顺序。

3.2.2 常见实现对比

实现 模型 顺序保证 持久化 适用场景
Apache Kafka 分区日志 分区内严格有序 磁盘持久化 高吞吐、事件溯源、日志聚合
RabbitMQ 队列/交换器 单队列有序 可选持久化 任务分发、RPC 转异步
NATS 轻量 Pub/Sub 无严格顺序 内存/文件 低延迟、云原生环境
云服务(EventBridge) 事件总线 依赖规则 托管持久化 Serverless、跨账户事件
Event Bus 架构:发布者 → 路由 → 订阅者 订单服务 发布: OrderCreated 支付服务 发布: PaymentProcessed Event Bus 路由规则 持久化队列 重试 & 死信 顺序保证 过滤 & 分发 库存服务 订阅: OrderCreated 通知服务 订阅: OrderCreated 审计服务 订阅: 所有事件

3.3 事件溯源(Event Sourcing)

传统持久化模式只保存实体的当前状态,而事件溯源将每个状态变更都记录为不可变事件。实体的当前状态由事件序列通过重放(Replay)计算得出。

3.3.1 核心优势

  • 完整审计轨迹:所有变更均可追溯,满足合规要求。
  • 时间旅行:可重建任意历史时刻的实体状态。
  • 事件驱动原生:事件存储天然支持异步发布。
  • 消除对象-关系阻抗:无需复杂的 ORM 映射。

3.3.2 典型事件存储结构

-- 事件表结构示例(PostgreSQL)
CREATE TABLE event_store (
    event_id        UUID PRIMARY KEY,
    aggregate_type  VARCHAR(100) NOT NULL,      -- 聚合类型,如 "Order"
    aggregate_id    VARCHAR(64) NOT NULL,       -- 聚合 ID
    event_type      VARCHAR(100) NOT NULL,      -- 事件类型,如 "OrderCreated"
    event_data      JSONB NOT NULL,             -- 事件载荷
    version         INT NOT NULL,               -- 聚合版本号(乐观锁)
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    UNIQUE (aggregate_type, aggregate_id, version)
);
注意:事件溯源不适用于所有场景。对于频繁更新且只关心最新状态的实体(如用户最后登录时间),传统 CRUD 更高效。事件溯源适合需要审计、复杂事件处理或跨服务状态同步的场景。

3.4 命令查询职责分离(CQRS)

CQRS 将系统的读写模型分离为独立的命令模型(写)与查询模型(读)。命令模型处理业务逻辑并产生事件,查询模型针对展示需求优化数据读取。

3.4.1 分离带来的好处

维度 命令模型(写) 查询模型(读)
数据形态 事件流 / 规范化表 物化视图 / 反规范化表
一致性 强一致性(聚合内) 最终一致性
扩展方式 按聚合类型分区 按查询维度独立扩展
缓存策略 不缓存(事件不可变) 可大量使用缓存
典型技术 Event Store、Kafka Elasticsearch、Redis、Read DB

3.4.2 与 Event Sourcing 的协同

Event Sourcing 与 CQRS 经常组合使用:命令模型将事件写入 Event Store,查询模型通过订阅事件流构建并更新自己的读视图。这种组合在微服务中被称为 ES/CQRS 模式。

Event Sourcing + CQRS 协同架构 命令处理器 验证 + 业务逻辑 Event Store 不可变事件日志 事件流 Kafka / Event Bus 事件投影器 订阅 + 转换 读模型 物化视图 / ES 查询 API

3.5 三者关系与适用场景

Event、Event Bus、Event Sourcing 与 CQRS 并非必须同时使用。下表总结了各组件在微服务熔断与隔离场景中的角色定位:

组件 熔断场景中的角色 隔离价值
Event 熔断状态变更通知(如 CircuitBreakerOpened) 事件不可变,下游可独立判断
Event Bus 熔断事件跨服务传播通道 解耦发布者与订阅者,避免级联故障
Event Sourcing 记录熔断状态变更历史 支持熔断恢复后的状态重建
CQRS 熔断规则配置(写)与状态查询(读)分离 读模型可独立缓存熔断状态,不阻塞写操作