4. EventBridge高级路由
当事件总线接入的事件源越来越多,一个常见问题会迅速暴露:所有消费者都收到所有事件。订单服务被无关的日志事件唤醒,风控函数被测试环境的心跳事件触发,成本随调用量线性上升。EventBridge 的高级路由能力正是为解决这类问题而设计的——它让规则在事件到达目标之前完成筛选、裁剪与重塑,并在需要时把历史事件保存下来以便重放。
内容过滤:让规则只匹配真正关心的事件
EventBridge 规则由 eventPattern 决定是否触发。它采用 JSON 匹配语义,而不是正则表达式:键必须存在且值相等,数组表示“任一匹配”,嵌套对象表示逐层匹配。一个只关心生产环境、金额超过 500 的订单创建事件,可以写成:
{
"source": ["app.orders"],
"detail-type": ["OrderCreated"],
"detail": {
"env": ["prod"],
"amount": [{ "numeric": [">", 500] }]
}
}
这里有几个容易踩坑的细节。第一,source、detail-type 是顶层字段,而业务属性必须放在 detail 下,写错层级会导致规则永不匹配。第二,数值比较必须使用 numeric 操作符,直接写 "amount": [500] 是字符串相等匹配,不会命中 500.0。第三,anything-but、prefix、exists、equals-ignore-case 等操作符可以组合出更精细的条件,例如排除测试租户:
"detail": {
"tenantId": [{ "anything-but": ["sandbox", "demo"] }]
}
过滤发生在规则评估阶段,未匹配的事件不会产生目标调用,因此它既是逻辑隔离手段,也是成本控制手段。设计时应遵循“先窄后宽”的原则:先用 source 和 detail-type 把范围压到最小,再用 detail 做业务条件判断。
输入转换:把事件重塑成目标需要的形状
过滤解决“要不要发”,输入转换解决“发什么”。默认情况下,EventBridge 把完整事件信封(含 id、time、source 等元数据)原样投递给目标。但下游往往只想要业务字段,或者需要固定格式。此时使用 InputTransformer,它由 InputPathsMap 和 InputTemplate 两部分组成:前者用 JSONPath 从事件中抽取变量,后者用 <变量名> 占位符拼装新载荷。
{
"InputPathsMap": {
"orderId": "$.detail.orderId",
"amount": "$.detail.amount",
"region": "$.region"
},
"InputTemplate": "{\"order\": <orderId>, \"total\": <amount>, \"src\": \"<region>\"}"
}
需要注意:InputTemplate 必须是一段合法 JSON 字符串,字符串型变量要自己加引号,数值型则不加。如果某个路径在事件中不存在,转换会失败,规则不会投递——这既是保护也是风险,建议对可选字段使用 InputPath 的默认值能力或在模板中做兜底。除了转换器,还可以使用 Input 直接投递固定常量,或用 InputPath 只取事件的一个子对象,三者按需选择。
归档:把事件流变成可回溯的历史
归档(Archive)是重放的前提。创建归档时需要指定一个 eventPattern,只有匹配的事件才会被写入归档;同时设置 retentionDays,0 表示永久保留。归档本身不产生目标调用,因此成本远低于把事件转发到存储服务。一个实用的做法是:为每条关键业务规则建立对应归档,模式与规则保持一致,这样“被处理过的事件”和“被保存的事件”天然对齐。
归档的典型用途有三类:故障后补发丢失事件、新消费者上线时回灌历史数据、以及审计与对账。需要注意的是,归档保存的是事件原始形态,重放时不会经过输入转换,而是重新走一遍规则匹配与转换流程——这意味着如果规则后来被修改,重放结果可能与当初不同。
重放实战:从归档到目标的一次完整回灌
假设订单服务在 14:00 到 14:20 之间因下游故障丢失了一批事件,现在需要补发。操作路径是:在 EventBridge 控制台选择对应归档,点击“开始重放”,指定 StartTime 和 EndTime(例如 2024-06-01T14:00:00Z 至 2024-06-01T14:20:00Z),选择目标事件总线(通常就是原总线),然后启动。重放任务会异步执行,可以在详情页看到 ReplayState 从 RUNNING 变为 COMPLETED,以及 EventLastReplayedTime 用于确认进度。
重放过程中有几个关键判断点。第一,重放事件会带上 replay-name 字段,消费者可以据此识别“这是补发而非实时事件”,从而决定是否跳过重复处理。第二,如果目标本身不具备幂等性,重放可能造成重复下单或重复扣款,因此消费者必须基于业务主键做去重。第三,重放不会自动限速,若目标承载能力有限,应先用较小时间窗试跑,观察目标错误率后再扩大范围。
把过滤、转换、归档、重放串成一条工程链路
这四项能力不是孤立功能,而是一条完整的事件治理链路。过滤决定哪些事件进入处理路径,转换决定进入路径后以什么形态呈现,归档决定历史是否可回溯,重放决定历史能否被重新利用。一个成熟的事件驱动系统通常按如下方式组织:每条业务规则配置精确的 eventPattern,用 InputTransformer 把事件裁剪为目标所需的最小载荷,同时为该规则建立同模式的归档,并在消费者侧实现基于业务主键的幂等。这样,当故障发生时,运维人员可以按时间窗重放归档事件,消费者依靠幂等逻辑安全地完成补处理,而无需人工逐条修复数据。
最后提醒一个常见误区:不要把归档当成“全量事件日志”使用。归档只保存匹配其 eventPattern 的事件,如果模式写得过窄,故障时可能发现关键事件根本没被保存。因此归档模式应略宽于业务规则,或在总线级别为所有事件建立兜底归档,再按需重放。