4. 企业服务总线(ESB)模式:核心功能与落地实践

说到 ESB,很多刚接触 SOA 的同学第一反应就是「这不就是个消息中转站吗?」
嗯,这么说也不算错,但太简单了。
我在早期做项目时,也以为 ESB 就是个管道,把 A 的数据搬到 B 就行。
结果呢?系统上线后,路由规则乱成一团,数据格式天天打架,业务方天天找上门。
后来我才真正理解:ESB 的核心不是「搬数据」,而是「治理集成」。

4.1 ESB 的核心功能:路由、转换、编排

ESB 的三大核心能力,我习惯用一个比喻来记:路由是导航,转换是翻译,编排是导演。

4.1.1 路由(Routing)

路由解决的是「消息该去哪」的问题。
别小看这个功能,真实场景远比你想的复杂。

  • 基于内容的路由:根据消息体里的字段值,决定转发到哪个服务。比如订单金额大于 1 万走审批流程,小于 1 万直接发货。
  • 基于上下文的路由:根据调用方身份、来源系统、时间等上下文信息路由。比如内部系统调用走内网,外部合作伙伴走专线。
  • 动态路由:运行时根据注册中心的服务状态动态调整目标。服务挂了?自动切换到备用节点。
我的经验:路由规则一定要设计成可配置的,别硬编码在代码里。我曾经接手过一个项目,路由逻辑散落在十几个 XML 配置文件和 Java 类里,改一条规则要改四个地方,上线时提心吊胆。

4.1.2 转换(Transformation)

转换解决的是「消息长什么样」的问题。
你想想看,一个企业里可能有几十个系统,每个系统都有自己的数据格式。
CRM 用 XML,ERP 用 JSON,老系统用固定长度的文本文件。
没有 ESB 做转换,这些系统之间就得两两对接,N 个系统需要 N×(N-1)/2 个接口——这谁受得了?

常见的转换模式:

  • 格式转换:XML ↔ JSON ↔ CSV ↔ 二进制
  • 协议转换:HTTP ↔ JMS ↔ FTP ↔ Socket
  • 数据映射:字段名、数据类型、枚举值的映射。比如 A 系统的「性别:0/1」映射到 B 系统的「性别:M/F」
  • 数据增强:在消息流转过程中补充数据,比如根据用户 ID 查询姓名并追加到消息里
避坑指南:我曾经遇到过一个案例,转换规则里做了大量的数据清洗和业务校验,结果 ESB 变成了性能瓶颈。记住:ESB 只做格式和协议的转换,业务校验应该交给服务本身。

4.1.3 编排(Orchestration)

编排解决的是「多个服务怎么配合」的问题。
一个业务流程往往需要调用多个服务,而且有先后顺序、有分支、有异常处理。
ESB 的编排能力,就是把这些服务调用串成一个完整的业务流程。

举个例子,一个下单流程:

  1. 调用库存服务扣减库存
  2. 调用支付服务发起支付
  3. 调用物流服务创建配送单
  4. 如果支付失败,回滚库存

这些步骤如果用代码写在业务系统里,耦合度太高。用 ESB 编排,流程变更只需要改配置,不用改代码。

关键认知:编排和编排引擎(如 BPEL、BPMN)不是一回事。ESB 的编排通常指轻量级的服务调用序列控制,而 BPMN 更侧重人工任务和长周期流程。别混为一谈。

4.2 ESB 与 API 网关的对比

这个问题我经常被问到:「有了 API 网关,还要 ESB 干嘛?」
说实话,这两个东西确实有重叠,但定位完全不同。

对比维度 ESB API 网关
核心定位 企业集成总线,连接异构系统 API 统一入口,管理南北向流量
协议支持 多协议(JMS、FTP、SOAP、REST…) 以 HTTP/HTTPS 为主
消息转换 强,支持复杂数据映射和格式转换 弱,通常只做简单的请求/响应转换
服务编排 支持,可编排多个服务形成业务流程 不支持或很弱
路由能力 内容路由、上下文路由、动态路由 基于 URL 路径的静态路由为主
治理能力 服务注册、监控、SLA 管理 限流、熔断、鉴权、日志
典型场景 系统间集成、数据同步、业务流程自动化 微服务 API 暴露、移动端/前端接入

说白了,ESB 管的是东西向流量(系统与系统之间),API 网关管的是南北向流量(外部到内部)。
我见过不少团队把 API 网关当 ESB 用,结果路由规则写了几百行,性能一塌糊涂。也见过把 ESB 当网关用,结果暴露了太多内部服务细节,安全风险很大。

我的建议:如果你们是微服务架构,对外暴露 API 用网关,内部服务间集成用轻量级 ESB 或消息中间件。别试图用一个工具解决所有问题。

4.3 轻量级 ESB 实践

传统 ESB(比如 IBM WebSphere ESB、Oracle SOA Suite)太重了,部署复杂、学习成本高、运行起来吃资源。
现在大家更倾向于轻量级 ESB,说白了就是「只做 ESB 最核心的事,其他能省则省」。

4.3.1 轻量级 ESB 的选型原则

  • 基于消息中间件:用 RabbitMQ、Kafka、RocketMQ 作为传输层,ESB 只做路由和转换
  • 配置驱动:路由和转换规则用 DSL 或配置文件定义,不用写代码
  • 容器化部署:支持 Docker/K8s,可以快速扩缩容
  • 可观测性:集成 Prometheus、Grafana,能监控每条消息的流转情况

4.3.2 一个简单的轻量级 ESB 示例

我用 Camel + RabbitMQ 搭过一个轻量级 ESB,核心代码就几十行:

// 定义路由:从 RabbitMQ 接收订单消息
from("rabbitmq:exchange:order?routingKey=order.create")
  // 消息转换:XML 转 JSON
  .unmarshal().jacksonxml(Order.class)
  .marshal().json(JsonLibrary.Jackson)
  // 内容路由:根据金额分流
  .choice()
    .when(simple("${body.amount} > 10000"))
      .to("rabbitmq:exchange:order.approve?routingKey=approval")
    .otherwise()
      .to("rabbitmq:exchange:order.ship?routingKey=shipping")
  .end();

你看,路由、转换、编排都在一个 DSL 里完成了。部署的时候打个 jar 包,扔到 Docker 里就跑起来了。

关键点:轻量级 ESB 不是功能阉割,而是「按需集成」。不需要的协议就不支持,不需要的治理功能就不集成。保持核心能力,去掉冗余负担。

4.3.3 轻量级 ESB 的典型架构

下面这张图是我常用的轻量级 ESB 架构,你可以参考:

轻量级 ESB 架构示意图 CRM 系统 ERP 系统 WMS 系统 消息中间件 RabbitMQ / Kafka 主题:order.create 主题:order.approve 主题:order.ship 主题:inventory.update ESB 引擎 Camel / Spring Integration 路由(Routing) 转换(Transformation) 编排(Orchestration) 业务应用 / 外部系统 说明: 1. 服务提供者发送消息到中间件 2. ESB 引擎订阅消息,执行路由/转换/编排 3. 处理后的消息转发给消费者

4.3.4 落地时的几个坑

最后分享几个我踩过的坑:

  • 别在 ESB 里做事务:ESB 本质是异步消息系统,强事务会让性能急剧下降。用补偿机制代替分布式事务。
  • 注意消息幂等性:消息可能重复投递,消费端要做好幂等处理。我遇到过因为没做幂等,库存扣了两次的惨案。
  • 监控比功能更重要:ESB 是集成枢纽,一旦出问题影响面很大。一定要有消息轨迹追踪和告警机制。
  • 别过度编排:编排逻辑太复杂,ESB 会变成单点故障。复杂的业务流程建议用工作流引擎,ESB 只做服务调用。
最后的忠告:ESB 不是银弹。如果你的系统只有三五个服务,直接用 API 网关加消息队列就够了。ESB 的价值在「规模」和「异构」——系统多了、协议杂了、格式乱了,才是 ESB 真正发力的地方。