Skip to content

11. 过滤与业务路由:别让每个服务都收到所有消息

产品把通知做细了

通知服务说:

我只关心订单创建和订单关闭。支付、发货、退款这些消息我不想处理。

仓库服务说:

我只关心支付成功和取消订单。

这时就要做好过滤和业务路由。

基础路由策略

订单域可以先设计一个 topic:

text
Topic: order-event-topic

Tags:
  order-created
  order-paid
  order-closed
  order-cancelled
  order-shipped

不同服务订阅不同 tag:

服务订阅
通知服务order-createdorder-closed
仓储服务order-paidorder-cancelled
积分服务order-paid
风控服务*

教学示例中先使用单 tag 或 *。复杂表达式要根据当前 RocketMQ 服务端和客户端能力验证后再用。

发送时带 Tag 和 Key

java
Message<OrderPaidEvent> message = MessageBuilder
        .withPayload(event)
        .setHeader(RocketMQHeaders.TAGS, "order-paid")
        .setHeader(RocketMQHeaders.KEYS, event.orderId())
        .build();

rocketMQClientTemplate.syncSendNormalMessage("order-event-topic", message);

业务路由不要只靠消费者 if

差写法:

java
if (!"order-paid".equals(event.type())) {
    return;
}

这会让消费者收到大量无关消息。应该优先用 topic/tag 做粗过滤,业务代码里再做二次校验。

小技巧

Topic 和 Tag 命名要稳定。建议用业务事实,不用页面名称:

不推荐推荐
order-page-clickorder-created
send-smsorder-paid
warehouse-apifulfillment-requested

消息是系统之间的契约,不是某个页面或接口的影子。

常见坑

  1. 所有服务订阅 *
    前期省事,后期消费压力和误处理风险都会上来。

  2. Tag 设计成状态机全部细节。
    Tag 是粗过滤。复杂条件可以放 payload 或业务查询。

  3. Key 不统一。
    有的用 orderId,有的用 paymentNo,排查时会混乱。

练习题

  1. 仓储服务应该订阅哪些订单事件?
  2. 为什么 send-sms 不适合作为订单事件 tag?
  3. 如果一个服务需要所有订单事件,应该怎么订阅?

参考答案

  1. 通常订阅 order-paidorder-cancelled,具体看库存和履约模型。
  2. 因为它描述的是消费动作,不是业务事实。
  3. 可以订阅 *,但要确认它确实承担全量事件处理职责,例如风控或审计。

来源

Built with VitePress. Deployed on Cloudflare Pages.