SOA 面向服务架构:参考架构、核心机制与工程实践
SOA(Service-Oriented Architecture,面向服务的体系架构)并不只是 SOAP、WSDL 或 ESB 的组合,而是一套围绕“服务”组织企业 IT 能力的方法。本文从业务驱动、松耦合和服务复用出发,系统梳理 SOA 的参考架构、适配器、服务总线、流程服务、信息服务、服务治理、安全、可靠消息与分布式事务等核心机制,并结合现代微服务、API Gateway、消息系统和可观测性重新理解 SOA 中仍然具有工程价值的架构思想。
为什么会出现 SOA
企业信息系统发展到一定规模后,真正难解决的问题往往不再是“怎样写一个功能”,而是怎样让大量已经存在的系统继续发挥价值,并且能够随着业务变化重新组合。
典型企业可能同时存在 ERP、CRM、财务系统、供应链系统、数据库、文件系统以及各种历史应用。这些系统可能使用完全不同的语言、操作系统、中间件和数据模型。如果每两个系统之间都建立一套专用集成接口,最终很容易形成复杂的点对点网络:
flowchart LR
A[系统 A] <--> B[系统 B]
A <--> C[系统 C]
A <--> D[系统 D]
B <--> C
B <--> D
C <--> D
系统数量增加后,接口数量和依赖关系快速膨胀。一个业务流程发生变化,可能意味着修改多个系统;替换其中一个系统,也可能牵动大量上下游接口。
SOA 希望改变这种模式。
它不再首先问:
系统 A 怎么调用系统 B?
而是先问:
企业到底有哪些可以被独立使用、组合和管理的业务能力?
然后将这些能力定义成服务(Service),再通过统一的服务契约、通信机制和治理体系完成系统之间的协作。
因此,SOA 的目标并不是发明一种新的 RPC 技术,而是重新组织企业 IT。
它试图解决几个长期存在的问题:
- 业务能力与具体技术实现绑定过深;
- 相同业务能力在不同系统中重复建设;
- 遗留系统难以继续利用;
- 系统之间耦合严重;
- 业务流程变化会引起大量代码修改;
- 跨部门、跨组织系统难以互操作;
- IT 架构无法快速响应业务变化。
SOA 的核心思路可以概括为:
把业务能力封装成具有明确契约的服务,使服务可以独立实现、统一访问、重复使用,并通过组合形成更高层业务流程。
SOA 到底是什么
SOA 的全称是 Service-Oriented Architecture(面向服务的体系架构)。
从体系结构角度看,它是一种组织和使用分布式业务能力的软件架构范型。
一个服务通常具有几个基本特征:
- 对应明确的业务能力;
- 对外提供清晰的服务接口;
- 服务消费者不需要了解内部实现;
- 服务实现可以独立演进;
- 服务能够被多个业务流程重复使用;
- 服务可以和其他服务组合形成新的业务能力。
可以将服务理解成:
1 | |
外部依赖的是契约,而不是实现。
例如,一个“客户信用检查服务”的消费者需要知道:
1 | |
至于内部究竟:
- 查询 Oracle;
- 调用旧 COBOL 系统;
- 请求第三方 API;
- 使用 Java;
- 使用 C++;
- 部署在 Windows;
- 部署在 Unix;
理论上都不应该成为服务消费者必须了解的信息。
这正是 SOA 松耦合的基础。
SOA 不等于 Web Services
这是理解 SOA 时非常容易出现的误区。
SOAP、WSDL、UDDI、BPEL 和大量 WS-* 标准曾经是 SOA 最典型的一套技术实现,但 SOA 是架构思想,而 Web Services 是实现 SOA 的一组技术手段。
SOA 本身并不限定服务必须使用 SOAP。
服务之间完全可能通过:
- HTTP;
- HTTPS;
- 消息中间件;
- MOM(Message-Oriented Middleware);
- RMI;
- IIOP;
- JMS;
- Web Services;
等不同技术通信。
因此更准确的关系是:
1 | |
不要把一个架构范型缩小成某一种协议。
服务为什么通常是粗粒度的
SOA 中的服务与传统对象方法中的方法调用存在明显区别。
一个对象方法可能非常细:
1 | |
而 SOA 更倾向于表达完整业务操作:
1 | |
也就是:
1 | |
服务粒度较大的原因很直接:服务通常跨越网络甚至组织边界。
每次调用都可能带来:
- 网络通信;
- 序列化和反序列化;
- 安全校验;
- 服务发现;
- 消息转换;
- 事务协调;
- 日志审计;
等成本。
如果把本地对象调用式的细粒度接口直接暴露为远程服务,很容易造成大量网络往返和严重性能问题。
因此 SOA 的服务设计重点不是“暴露更多方法”,而是寻找合适的业务能力边界。
SOA 最重要的特征:松耦合
松耦合并不是简单地“通过网络调用”。
SOA 中至少包含三个维度的耦合。
接口松耦合
服务消费者依赖服务契约,而不依赖服务内部实现。
flowchart LR
Consumer[服务消费者]
Contract[服务契约]
Provider[服务提供者]
Impl[内部实现]
Consumer --> Contract
Contract --> Provider
Provider --> Impl
只要契约保持兼容,服务提供者就能够修改内部实现,而不要求消费者同步修改。
技术松耦合
服务消费者和服务提供者不要求采用相同技术栈。
例如:
1 | |
或者:
1 | |
SOA 强调尽可能减少:
- 编程语言绑定;
- 操作系统绑定;
- 中间件绑定;
- 厂商产品绑定。
这也是开放标准在 SOA 中如此重要的原因。
流程松耦合
服务最好不要只为某一个固定业务流程而设计。
假设存在:
1 | |
如果它只能够在“贷款审批流程”中使用,那么它的复用价值非常有限。
更合理的服务应当可以被:
1 | |
等多个流程使用。
也就是说:
服务表达稳定的业务能力,业务流程负责组织这些能力。
当业务流程发生变化时,优先重新编排服务,而不是修改每个服务本身。
SOA 为什么能提升业务灵活性
传统应用通常同时包含:
1 | |
它们紧密结合在一起。
SOA 则试图拆成:
1 | |
假设原业务流程为:
flowchart LR
A[创建订单] --> B[检查库存]
B --> C[信用检查]
C --> D[支付]
D --> E[发货]
业务发生变化后,可能需要增加风控:
flowchart LR
A[创建订单] --> B[检查库存]
B --> C[信用检查]
C --> R[风险检查]
R --> D[支付]
D --> E[发货]
只要原有服务仍然满足契约,大部分服务不需要修改。
改变的是:
服务的组合关系。
这就是 SOA 所强调的业务流程重构能力。
SOA 技术参考架构
一个完整的 SOA 系统不仅仅包含服务。
它通常涉及:
- 已有资源;
- 新开发服务;
- SOA 基础技术平台;
- 开发和管理工具;
- 系统使用人员;
- 其他 SOA 平台。
参考架构可以重新整理为下面的结构:
flowchart TB
subgraph USERS[人员]
Designer[设计人员]
Developer[开发人员]
Operator[操作人员]
Admin[管理员]
end
subgraph TOOLS[辅助工具]
Model[分析建模工具]
IDE[集成开发工具]
Ops[运行管理工具]
end
subgraph PLATFORM[SOA 基础技术平台]
Security[安全服务]
Interaction[交互服务]
Business[业务服务]
Information[信息服务]
Process[流程服务]
Collaboration[协作服务]
Runtime[运行管理服务]
ResourceMgr[资源管理服务]
Bus[连通服务 / ESB]
Adapter[适配器]
end
subgraph RESOURCE[已有资源]
App[应用系统]
DB[(数据库)]
File[文件]
end
Other[其他 SOA 平台]
Application[应用服务]
Designer --> Model
Developer --> IDE
Admin --> Ops
Operator --> Interaction
Model --> ResourceMgr
IDE --> ResourceMgr
Ops --> Runtime
Interaction --> Bus
Business --> Bus
Information --> Bus
Process --> Bus
Collaboration --> Bus
ResourceMgr --> Bus
Runtime --> Bus
Adapter --> Bus
App --> Adapter
DB --> Adapter
File --> Adapter
Collaboration <--> Other
Application --> PLATFORM
Security --- Interaction
Security --- Business
Security --- Information
Security --- Process
Security --- Collaboration
Security --- Bus
这个架构有一个非常重要的特点:
架构中的功能模块本身也是松耦合的,可以针对不同应用场景进行拆分和组合。
它不是要求所有 SOA 系统必须一次性部署完整平台,而是提供一个能力模型。
SOA 中的几类核心对象
整个架构可以先从几个外围对象理解。
资源
资源是企业已经拥有的 IT 资产,例如:
1 | |
这些资源很多甚至早于 SOA 平台存在。
SOA 的目标不是简单推倒重建,而是:
把已有资产重新包装为可以被服务化使用的资源。
新开发服务
新开发服务通常可以分成两类。
基本服务
由程序代码实现的较原子的业务服务。
流程化服务
通过流程工具组织多个基本服务形成的服务。
一个流程本身也可以再次暴露成服务:
1 | |
这使服务体系可以逐层构建。
人员
SOA 系统并不是只有机器之间调用。
典型角色包括:
| 角色 | 主要职责 |
|---|---|
| 设计人员 | 业务分析、服务建模、流程设计 |
| 开发人员 | 服务开发、流程实现、资源集成 |
| 管理人员 | 监控、管理 SOA 平台 |
| 操作人员 | 使用服务、处理人工任务 |
设计、开发、运行和业务操作构成完整的服务生命周期。
其他平台
SOA 特别强调跨系统甚至跨组织互操作。
一个组织内部可能统一使用一套基础技术平台,但不同组织之间很可能使用完全不同的产品。
因此需要:
1 | |
这也是协作服务存在的重要原因。
适配器:保护遗留系统投资
SOA 很现实的一点是:
企业不可能为了建设 SOA,把已经运行多年的系统全部重写。
因此参考架构专门设计了适配器(Adapter)。
基本关系为:
flowchart TB
subgraph Legacy[已有资源]
App[应用系统]
DB[(数据库)]
File[文件]
end
subgraph AdapterLayer[适配器]
AppAdapter[应用适配器]
DBAdapter[数据库适配器]
FileAdapter[文件适配器]
end
Bus[连通服务 / ESB]
App --> AppAdapter
DB --> DBAdapter
File --> FileAdapter
AppAdapter --> Bus
DBAdapter --> Bus
FileAdapter --> Bus
适配器负责把已有资源的原始接口转换成服务接口。
例如:
1 | |
或者:
1 | |
适配器不仅负责协议转换,还可能需要处理:
- 连接管理;
- 事务管理;
- 安全管理。
因此它实际上承担的是:
传统资源与服务世界之间的桥梁。
这和今天常见的 Anti-Corruption Layer、Legacy Adapter 等思想有明显共通之处。
连通服务:SOA 的通信骨干
SOA 参考架构中最核心的基础设施之一是连通服务。
其典型实现就是:
ESB(Enterprise Service Bus,企业服务总线)
连通服务主要解决:
1 | |
服务并不需要分别连接所有其他服务。
而是通过通信代理连接总线:
flowchart LR
ServiceA[服务 A] --> ProxyA[通信代理]
ServiceB[服务 B] --> ProxyB[通信代理]
ServiceC[服务 C] --> ProxyC[通信代理]
ProxyA <--> Bus[连通服务 / ESB]
ProxyB <--> Bus
ProxyC <--> Bus
这样原本的:
1 | |
被转换成:
1 | |
通信关系因此得到集中管理。
连通服务到底负责什么
连通服务主要承担以下能力。
通信代理
服务并不直接处理所有通信细节,而由通信代理负责:
1 | |
代理之间可以采用不同通信机制,例如:
1 | |
服务路由
服务消费者只表达:
1 | |
连通服务可以查询资源管理服务:
1 | |
然后完成服务请求转发。
从架构思想上看,这已经包含了后来大量服务发现和动态路由系统关注的问题。
通信质量
总线不仅仅负责“把数据发过去”。
还要考虑:
- 可靠性;
- 安全性;
- 事务;
- 性能;
- 服务调度;
- 运行管理。
因此 ESB 本质上是一个企业级通信中间层。
协作服务:跨平台、跨组织通信
如果两个服务属于同一技术平台,可以直接通过连通服务通信。
但现实世界中可能是:
1 | |
两个组织使用不同 SOA 平台。
此时由协作服务承担跨平台交互。
经典架构中:
flowchart LR
Bus[内部连通服务]
Comm[通信代理]
WS[Web Services 代理]
Registry[(公共注册中心)]
Tx[事务协调器]
External[其他 SOA 平台]
Bus <--> Comm
Comm <--> WS
WS <--> Registry
WS <--> Tx
WS <-- SOAP / HTTP --> External
协作服务在当时主要围绕 Web Services 技术构建,包括:
- Web 服务注册;
- Web 服务发现;
- SOAP 消息通信;
- 跨平台事务协调。
这里体现了 SOA 一个很重要的思想:
企业内部通信机制可以自主选择,但跨所有者控制域时应建立标准化互操作边界。
业务服务与流程服务不是一回事
参考架构中特别区分了:
- 业务服务;
- 流程服务。
业务服务
业务服务是新建业务服务的运行环境。
它主要承载:
1 | |
例如:
1 | |
这些服务可以调用其他服务。
流程服务
流程服务负责:
按照业务流程组织多个服务执行。
例如:
flowchart LR
Start([开始])
A[创建订单]
B[检查库存]
C[信用检查]
D[支付]
E[发货]
End([结束])
Start --> A
A --> B
B --> C
C --> D
D --> E
E --> End
流程服务通常需要提供:
- 流程驱动;
- 服务调用;
- 流程状态管理;
- 事务管理;
- 错误处理;
- 人工任务;
- 流程监控。
流程本身最终还可以被发布为更粗粒度服务。
于是形成:
1 | |
流程服务怎样调用其他服务
流程引擎一般不会直接绑定具体服务实例。
抽象调用关系为:
sequenceDiagram
participant P as 流程服务
participant B as 连通服务
participant R as 资源管理服务
participant S as 业务服务
P->>B: 请求执行某个服务
B->>R: 查找服务描述/服务位置
R-->>B: 返回服务信息
B->>S: 转发服务请求
S-->>B: 返回执行结果
B-->>P: 返回结果
这样流程关注的是:
1 | |
而不是:
1 | |
这正是服务动态绑定思想的价值。
人工任务如何进入业务流程
业务流程并不都是自动完成的。
例如:
1 | |
都可能需要人参与。
SOA 为此引入了交互服务。
流程可以变成:
flowchart LR
A[自动任务] --> B[流程服务]
B --> C[交互服务]
C --> D[人工处理]
D --> C
C --> B
B --> E[后续自动任务]
人在 SOA 中既可能是:
- 服务消费者;
- 服务提供者。
例如填写申请表:
1 | |
而人工审批则可以看成:
1 | |
这是一个相当重要的抽象:
人工行为同样可以作为业务流程中的服务节点。
信息服务:统一访问异构数据
企业中的数据通常散布在:
1 | |
如果每个应用都直接了解所有数据存储的位置和格式,会产生大量重复的数据集成代码。
因此 SOA 引入信息服务。
它试图向上层提供:
统一、透明的数据访问服务。
架构关系可以整理为:
flowchart TB
Client[应用 / 服务]
Info[信息服务]
View[虚拟数据视图]
Transform[数据加工]
Bus[连通服务]
App[应用系统]
DB[(数据库)]
File[文件]
Client --> Info
Info --> View
View --> Transform
Transform --> Bus
Bus --> App
Bus --> DB
Bus --> File
用户访问的是统一的数据视图,而不需要知道数据真正存储在哪里。
信息服务还可以完成:
- 数据过滤;
- 数据合并;
- 数据转换。
从今天的视角看,这与数据虚拟化、数据服务化以及部分 Data API 思想存在明显相似之处。
资源管理和运行管理必须分开理解
SOA 参考架构中存在两套非常重要但经常容易混淆的管理能力:
1 | |
它们关注的对象不同。
资源管理服务
资源管理服务解决的是:
系统里有什么?
例如:
1 | |
它维护的是资源描述信息。
可以把它理解为 SOA 的“元数据中心”。
分析建模工具、开发工具和其他服务都可以读取或修改这些资源信息。
典型操作包括:
1 | |
运行管理服务
运行管理服务解决的是:
系统现在运行得怎么样?
例如:
1 | |
管理能力主要分成两类。
运行信息收集
用于:
- 监控;
- 统计;
- 性能分析;
- 故障诊断。
管理命令执行
例如:
1 | |
因此:
1 | |
把两者分开,是理解 SOA 治理体系的关键。
安全服务为什么是横切能力
SOA 是典型的分布式系统。
大量服务跨:
1 | |
进行调用,因此安全不能只由单个业务服务自己处理。
参考架构把安全服务看作一种:
跨越整个体系结构的横切能力。
主要提供:
- 身份验证;
- 访问控制;
- 数据加密;
- 数据完整性;
- 抗抵赖。
它作用于多个层面:
flowchart TB
Security[安全服务]
Interaction[交互服务]
Bus[连通服务]
Collaboration[协作服务]
Process[流程服务]
Info[信息服务]
Security --- Interaction
Security --- Bus
Security --- Collaboration
Security --- Process
Security --- Info
例如:
1 | |
这种横切安全思想今天依然非常重要。
服务契约是整个 SOA 的基础
SOA 如果没有契约,就很难真正实现松耦合。
服务描述至少需要回答几个问题:
1 | |
经典服务契约通常包含:
| 内容 | 说明 |
|---|---|
| 输入输出 | 服务请求和响应的数据结构 |
| 服务接口 | 可调用的操作 |
| 消息格式 | 请求和响应如何编码 |
| 通信协议 | 怎样交换消息 |
| 服务地址 | 服务在哪里 |
| 安全策略 | 身份、权限、加密等要求 |
| 服务质量 | 可靠性、事务、优先级等 |
| SLA | 响应时间、可用率等 |
在 Web Services 体系中,典型描述语言就是:
WSDL(Web Services Description Language)
WSDL 主要用于描述:
1 | |
其根本意义并不是 XML 文件本身,而是:
把服务消费者与服务提供者之间的约定显式化、标准化。
Contract First:先定义契约,再实现服务
SOA 中一种非常典型的开发方式是:
1 | |
服务消费者可以根据契约生成代理:
1 | |
服务提供者则根据契约生成服务框架:
1 | |
因此双方只共享:
1 | |
而不共享内部代码。
这实际上就是后来 API First、Contract First 等思想的重要来源之一。
服务注册与服务发现
如果服务地址全部硬编码:
1 | |
服务提供者和消费者仍然存在非常强的位置依赖。
SOA 因此引入:
服务注册中心
服务提供者把服务描述发布到注册中心:
1 | |
消费者再查找:
1 | |
注册中心需要保存:
- 服务描述;
- 服务分类;
- 服务版本;
- 服务相关元数据。
在经典 SOA 体系中,注册中心可以通过:
1 | |
等方式实现。
重点不在具体产品,而在于:
服务描述应该可以被集中管理和查询。
静态查找与动态查找
服务发现存在两种基本模式。
静态查找
开发人员从注册中心查找服务,然后生成代理代码:
1 | |
之后运行时直接使用固定的绑定信息。
优点是简单。
缺点是运行时适应性较弱。
动态查找
运行中的服务消费者自动查询注册中心:
sequenceDiagram
participant C as 服务消费者
participant R as 服务注册中心
participant P as 服务提供者
C->>R: 查找某类服务
R-->>C: 返回服务描述与访问数据
C->>P: 动态调用
P-->>C: 返回结果
这样可以实现:
- 动态绑定;
- 服务实例切换;
- 智能路由。
不过真正做到完全依据业务语义自动选择服务,比简单的地址发现复杂得多。
这也是早期 SOA 研究中大量讨论“语义服务发现”的原因。
一个服务从发布到调用的完整路径
将服务契约、注册中心、连通服务和运行管理串起来,可以得到下面的抽象生命周期:
sequenceDiagram
participant Dev as 服务开发者
participant RM as 资源管理服务
participant Consumer as 服务消费者
participant Bus as 连通服务
participant Provider as 服务提供者
participant Monitor as 运行管理服务
Dev->>RM: 发布服务描述/契约
RM-->>Dev: 保存服务元数据
Consumer->>Bus: 请求某项业务服务
Bus->>RM: 查找服务
RM-->>Bus: 返回服务描述与定位信息
Bus->>Provider: 转发服务请求
Provider-->>Bus: 返回响应
Bus-->>Consumer: 返回结果
Provider->>Monitor: 上报运行信息
Bus->>Monitor: 上报通信运行信息
这条链路已经包含现代分布式服务治理中几个长期存在的基本问题:
1 | |
具体实现技术不断变化,但问题本身一直存在。
服务间通信需要考虑的不只是 HTTP
服务之间真正进行交互时,需要至少处理三层问题。
消息格式
双方首先必须理解:
1 | |
经典 Web Services 通常采用:
1 | |
服务通信协议
通信协议决定:
1 | |
底层传输协议
真正把数据从机器 A 传到机器 B,还需要底层传输机制。
经典 SOA 体系可能使用:
1 | |
因此要区分:
1 | |
两者并不是同一个层次。
SOA 的六种典型通信模式
服务通信并不只有同步请求/响应。
单向请求
1 | |
发送后不等待响应。
适用于:
1 | |
请求/响应
1 | |
最常见的同步调用模式。
请求/回调
1 | |
调用方不阻塞等待,服务完成后通过回调返回。
存储转发
消息先进入可靠队列:
flowchart LR
A[请求者] --> Q[(可靠消息队列)]
Q --> B[服务提供者]
这样双方不要求同时在线。
这是提高松耦合和可靠性的非常重要的方式。
发布/订阅
flowchart LR
Publisher[发布者] --> Topic[(Topic)]
Topic --> A[消费者 A]
Topic --> B[消费者 B]
Topic --> C[消费者 C]
一个消息可以被多个消费者接收。
适用于事件驱动场景。
会话模式
消费者和提供者建立一个持续会话:
1 | |
适用于需要多轮上下文交互的场景。
企业级服务通信必须考虑 QoS
只解决“消息能够传输”远远不够。
企业系统还要考虑:
可靠性
例如:
1 | |
性能
需要避免:
1 | |
必要时还需要:
1 | |
可扩展性
随着业务增长,需要能够增加节点,而不是重新设计整个体系。
运行审计
系统应该知道:
1 | |
否则一旦复杂服务链路出现问题,几乎无法定位。
服务有三种基本使用方式
SOA 中服务并不只是“直接调用”。
基本使用方式可以分为三种。
直接使用
1 | |
这是最简单的形式。
服务合成
一个服务内部调用其他服务:
flowchart LR
Client --> S[合成服务]
S --> A[服务 A]
S --> B[服务 B]
S --> C[服务 C]
合成服务本身仍然可以对外暴露服务接口。
服务编排
多个服务被业务流程统一组织:
flowchart TD
Start --> A[服务 A]
A --> B{业务条件}
B -->|条件 1| C[服务 B]
B -->|条件 2| D[服务 C]
C --> E[服务 D]
D --> E
E --> End
编排关注的是:
整个业务流程怎样执行。
Orchestration 与 Choreography
SOA 标准体系中曾经非常重视两个概念:
1 | |
虽然中文资料中常出现“编制”“编排”等不同翻译,但可以从控制方式理解。
Orchestration
存在一个中心流程控制者:
flowchart TB
O[流程编排器]
O --> A[服务 A]
O --> B[服务 B]
O --> C[服务 C]
谁先执行、谁后执行,由中心流程定义。
Choreography
没有一个参与方掌握全部流程。
各参与者依据公共交互协议协作:
flowchart LR
A[参与方 A] <--> B[参与方 B]
B <--> C[参与方 C]
C <--> A
它关注:
多个业务参与方之间应该怎样交互。
这种区别对于今天理解工作流编排与事件驱动协作仍然很有价值。
SOA 中流程需要支持哪些控制结构
一个真正的业务流程引擎至少需要支持几种基础流程。
顺序
1 | |
分支
flowchart TD
A --> B{条件}
B -->|true| C
B -->|false| D
并行
flowchart TD
A --> B
A --> C
A --> D
B --> E
C --> E
D --> E
汇聚条件还可能是:
1 | |
循环
flowchart TD
A --> B
B --> C{满足条件?}
C -->|否| A
C -->|是| D
这些看似简单的能力,实际上构成了大量业务工作流系统的基础。
长流程为什么需要补偿机制
分布式业务流程有一个非常棘手的问题。
假设执行:
1 | |
前三步已经执行成功,但发货失败。
数据库事务中的:
1 | |
通常无法跨越多个独立服务、多个数据库甚至多个组织直接完成。
因此 SOA 引入一种非常重要的思想:
补偿(Compensation)
例如:
1 | |
补偿不是把所有数据库状态机械恢复到过去,而是:
执行一个业务上语义相反的操作。
抽象流程为:
flowchart TD
A[执行服务 A] --> B[执行服务 B]
B --> C[执行服务 C]
C --> D{是否成功?}
D -->|成功| E[流程结束]
D -->|失败| CB[补偿 B]
CB --> CA[补偿 A]
这种思路后来也广泛出现在长事务和分布式事务设计中。
SOA 中的事务有三种典型模型
原子事务
要求:
1 | |
经典实现通常依赖:
Two-Phase Commit(2PC,两阶段提交)
适合相对短时间的、强一致性事务。
补偿事务
对于长时间业务流程,不要求所有系统始终持有数据库锁。
失败时执行相反业务操作:
1 | |
它更适合长时间业务活动。
基于流程的事务
现实业务流程中可能同时存在:
1 | |
因此流程层需要一个更高层事务框架:
1 | |
这种组合方式更符合真实企业流程。
可靠消息不是一句“至少一次”那么简单
企业级 SOA 要求消息系统解决几个问题:
- 消息必须能够被可靠传递;
- 可以获知消息状态;
- 能够识别重复消息;
- 必要时保证消息顺序。
最终形成几种常见语义:
At Most Once
最多一次:
1 | |
At Least Once
至少一次:
1 | |
这要求业务消费者通常具备幂等处理能力。
Exactly Once
从业务效果上只执行一次。
这是最理想但实现成本也最高的一类语义。
因此:
可靠消息设计永远不能只看 Broker,还必须看消费者的业务语义。
安全需要分层处理
SOA 中的安全不是一个登录页面能够解决的。
它通常可以分成几个层次。
传输级安全
关注网络链路:
1 | |
消息级安全
即使消息中间经过多个节点,也需要保护消息本身:
1 | |
经典 XML Web Services 因而出现:
1 | |
等标准。
服务级安全
服务本身需要判断:
1 | |
涉及:
1 | |
经典 Web Services 体系围绕这些需求发展出大量 WS-Security 相关标准。
用户与权限管理
还必须管理:
1 | |
因此安全不是一个独立模块,而是一整套身份和权限治理体系。
SOA 服务治理到底治理什么
“服务治理”经常被简单理解为注册中心。
实际上它远不止服务发现。
一个成熟 SOA 系统需要管理整个服务生命周期:
flowchart LR
Design[服务设计]
Develop[开发]
Register[注册]
Deploy[部署]
Run[运行]
Monitor[监控]
Change[变更]
Retire[下线]
Design --> Develop
Develop --> Register
Register --> Deploy
Deploy --> Run
Run --> Monitor
Monitor --> Change
Change --> Deploy
Change --> Retire
治理内容至少涉及:
- 服务描述;
- 服务版本;
- 服务分类;
- 服务发现;
- 服务部署;
- 服务运行状态;
- SLA;
- 安全策略;
- 日志审计;
- 性能监控;
- 生命周期。
这才是完整的服务治理。
为什么运行管理本身也应该服务化
SOA 有一个非常一致的思想:
对业务服务采用统一接口,对管理功能同样采用统一接口。
因此管理控制台并不需要直接了解每种服务内部结构。
可以抽象成:
flowchart TB
Console[运行管理工具]
Manager[运行管理服务]
A[连通服务]
B[流程服务]
C[业务服务]
D[协作服务]
Console --> Manager
Manager --> A
Manager --> B
Manager --> C
Manager --> D
运行管理服务统一处理:
1 | |
这样管理工具和具体平台之间也能保持松耦合。
SOA 中的统一操作界面
SOA 不仅处理后台服务。
对用户而言,不同服务最终还要通过界面进行使用。
交互服务因此需要解决:
- 内容统一管理;
- 服务消费代理;
- 服务提供代理;
- 多 Portal 集成;
- 多渠道访问。
经典多渠道包括:
1 | |
虽然其中部分设备名称带有明显时代特征,但背后的问题并没有消失:
同一个业务能力如何通过多个渠道提供服务?
今天仍然可能面对:
1 | |
变化的是终端,问题本身没有变化。
SOA 为什么特别强调开放标准
SOA 的目标之一是减少厂商绑定。
如果服务消费者必须使用:
1 | |
那么服务的互操作性就非常有限。
因此 SOA 极其强调标准化。
经典 SOA 标准主要由几个组织推动。
W3C
主要涉及 Web 基础和 Web Services 相关标准,例如:
1 | |
OASIS
大量企业 Web Services 标准来自 OASIS,例如:
1 | |
WS-I
WS-I 的重点并不是再创造一套协议,而是:
约束不同 Web Services 标准应该如何组合使用,从而提高不同厂商实现之间的互操作性。
经典 SOA 标准体系到底有多复杂
2000 年代的 SOAP/Web Services 生态形成了非常庞大的 WS-* 标准体系。
可以按问题重新分类,而不必逐个死记规范名称。
| 问题 | 经典技术或标准 |
|---|---|
| 数据模型 | XML Schema |
| 服务描述 | WSDL |
| 服务注册发现 | UDDI |
| 服务寻址 | WS-Addressing |
| 服务策略 | WS-Policy |
| 消息通信 | SOAP |
| 安全 | WS-Security、SAML、XACML、XML Signature |
| 可靠消息 | WS-ReliableMessaging |
| 事务 | WS-AtomicTransaction、WS-BusinessActivity |
| 流程 | WS-BPEL |
| 协作 | WS-Choreography |
| 运行管理 | Web Services Distributed Management |
| 互操作 | WS-I Profile |
理解这些标准时,最重要的并不是记版本号,而是理解它们为什么出现。
整个标准体系实际上是在不断回答:
1 | |
这些问题今天依旧存在,只是实现方式已经发生了很大变化。
SOA 适合解决什么问题
SOA 最有价值的场景通常不是一个全新的简单应用,而是复杂企业环境。
企业应用集成
例如:
1 | |
需要打通。
遗留系统复用
通过适配器将已有系统重新包装成服务,而不是完全重写。
跨部门业务协同
将不同部门能力服务化:
1 | |
再组织完整业务流程。
跨企业合作
例如供应链中的:
1 | |
通过标准接口交换服务。
业务流程频繁变化
如果业务流程变化频繁,而基础业务能力相对稳定,SOA 的服务组合方式就具有明显优势。
多渠道业务服务
同一业务能力可以通过不同渠道使用,而不要求每个渠道重新实现完整业务逻辑。
什么场景并不适合 SOA
SOA 不是所有程序都应该采用的架构。
如果只是一个:
1 | |
把每一个方法都改成远程服务往往只会增加复杂度。
远程服务通常还要承担:
1 | |
其成本远高于本地方法调用。
因此不要把:
1 | |
这样的内部函数机械改造成独立网络服务。
SOA 真正适合的是:
具有稳定业务语义、需要跨系统调用、值得被复用的业务能力。
SOA 实施最大的几个风险
SOA 理论非常漂亮,但工程实践并不简单。
XML 带来的性能成本
经典 SOA 广泛采用 XML。
XML 的优势是:
1 | |
但代价同样明显:
1 | |
在大规模、高吞吐系统中会明显增加资源消耗。
标准数量过多
WS-* 标准体系曾经复杂到令人望而生畏。
同一个问题甚至可能出现多个竞争规范。
于是企业需要面对:
1 | |
标准原本是为了降低厂商绑定,标准本身过度复杂之后,反而可能增加技术选型风险。
动态服务发现远比想象中复杂
“根据业务需求自动找到最佳服务”听起来非常理想。
但如果希望机器理解:
1 | |
就需要:
1 | |
单纯依靠接口名称远远不够。
这也是早期“语义 Web Services”长期研究却难以全面普及的原因之一。
服务粒度设计困难
服务太细:
1 | |
服务太粗:
1 | |
真正困难的是找到:
稳定且具有独立业务价值的服务边界。
这和今天划分微服务边界时面对的问题本质上非常相似。
SOA 不应该一次性“大爆炸式”建设
SOA 最危险的一种实施方式是:
1 | |
更合理的方法是增量演进:
flowchart LR
A[选择一个明确场景]
B[服务化少量核心能力]
C[建设必要基础设施]
D[验证业务价值]
E[积累服务治理经验]
F[逐步扩展]
A --> B --> C --> D --> E --> F
这与 SOA 强调保护已有资产的目标也是一致的。
企业架构不应该要求:
“旧系统全部重写以后,新架构才能开始工作。”
真正可持续的架构通常需要允许:
1 | |
长期共存和逐渐演进。
从今天重新理解 ESB
早期 SOA 中,ESB 往往承担非常多职责:
1 | |
结果很容易形成一个能力极其庞大的中心基础设施。
今天的工程体系更常把这些能力拆分到不同组件中。
可以进行一个概念上的映射:
| 经典 SOA 能力 | 现代工程中常见实现 |
|---|---|
| 服务入口 | API Gateway |
| 服务发现 | 注册中心、平台服务发现 |
| 服务间通信治理 | Service Mesh 或客户端治理 |
| 异步通信 | Message Broker / Event Streaming |
| 工作流 | Workflow / Orchestration Engine |
| 服务监控 | Metrics、Logs、Tracing |
| 安全身份 | TLS、Token、统一身份体系 |
| 策略治理 | Gateway、Mesh、Policy Engine |
| 遗留系统接入 | Adapter / Integration Layer |
需要特别强调:
这并不是说“API Gateway 就是 ESB”。
两者解决的问题范围和架构理念并不完全相同。
更准确的理解是:
早期 ESB 集中承载的许多基础能力,在现代云原生架构中经常被拆分到多个专门组件中。
SOA 与微服务是什么关系
微服务和 SOA 经常被描述成完全对立的两种架构,这其实过于简单。
SOA 很早就已经强调:
1 | |
这些思想与微服务有明显的连续性。
区别更多来自工程实现方式。
经典企业 SOA 往往偏向:
1 | |
而现代微服务架构更强调:
1 | |
可以把两者理解成:
微服务继承了大量 Service Orientation 的基本思想,但采用了更偏向独立部署、团队自治和轻量基础设施的工程实践。
因此学习 SOA 并不是为了重新建设一套 2006 年式 SOAP 平台。
真正有价值的是理解它早已提出的那些架构问题。
SOAP、REST、gRPC 和消息系统只是不同实现选择
如果抛开具体协议,SOA 真正关心的是:
1 | |
现代系统完全可能使用:
1 | |
实现服务通信。
因此:
1 | |
这些只是不同历史阶段常见的技术实现。
如果一个系统使用 REST API,却具有:
1 | |
它依然体现了大量 Service-Oriented 的设计思想。
经典服务注册中心与现代服务发现
UDDI 曾试图建立一个非常通用的 Web Services 服务目录。
经典模型更像:
1 | |
现代分布式平台里的服务发现通常更务实。
服务实例可能随着:
1 | |
不断变化。
因此服务发现更多聚焦于:
1 | |
而不是建立一个复杂的全球业务服务黄页。
但是它们背后的核心问题没有变化:
服务消费者不应该硬编码依赖具体服务位置。
经典 WS-Security 与现代安全体系
早期 Web Services 希望在 SOAP 消息级别实现:
1 | |
于是形成庞大的 WS-Security 标准体系。
现代系统实现这些能力时,常见方式已经发生变化,例如:
1 | |
但安全架构依然可以使用 SOA 的分层思想理解:
1 | |
如果只给服务加一个登录接口,却忽略整个调用链上的身份和授权传播,并不能解决分布式系统安全问题。
分布式事务的思路同样延续至今
经典 SOA 已经清楚地区分:
1 | |
这个区别今天依然极其重要。
在服务化系统中,如果试图把所有操作都纳入一个跨网络的全局数据库事务,很容易遇到:
1 | |
因此对于长业务流程,更常见的思路仍然是:
1 | |
名称和实现框架可能变化,但核心思想和早期 SOA 的补偿事务是一脉相承的。
SOA 中哪些思想今天最值得保留
如果把 SOAP、UDDI 和大量历史 WS-* 标准暂时放到一边,SOA 真正留下来的架构价值至少有以下几个方面。
按业务能力设计系统
不要从数据库表开始拆服务。
应该从:
1 | |
开始。
明确服务契约
调用双方依赖契约,而不是实现。
契约不仅是请求参数,还包括:
1 | |
服务边界必须稳定
好的服务应该围绕相对稳定的业务能力,而不是某一次具体业务流程。
优先降低耦合
需要同时检查:
1 | |
不能只因为改成 HTTP 调用就认为已经实现松耦合。
组合优于复制
当新的业务需求出现时,应优先尝试:
1 | |
而不是:
1 | |
治理与业务运行必须同步建设
服务数量增加以后:
1 | |
都必须成为架构的一部分。
不要因为新架构抛弃已有资产
适配器思想依然非常现实。
遗留系统未必漂亮,但只要仍然承载关键业务能力,就可以通过隔离和服务化方式继续利用。
业务流程和业务能力要分离
业务能力应该尽量稳定。
流程则允许:
1 | |
这才真正形成业务敏捷性。
一个现代化的 SOA 思维模型
如果把历史上具体产品和协议抽掉,可以把 SOA 简化成下面这个模型:
flowchart TB
Consumer[消费者 / 渠道]
Gateway[服务入口]
Discovery[服务发现与治理]
subgraph SERVICES[业务服务]
A[客户服务]
B[订单服务]
C[库存服务]
D[支付服务]
end
Workflow[流程 / 编排]
Messaging[消息与事件]
Adapter[遗留系统适配层]
Legacy[遗留系统]
Data[(数据资源)]
Security[身份与安全]
Observe[日志 / 指标 / Trace]
Consumer --> Gateway
Gateway --> A
Gateway --> B
Workflow --> A
Workflow --> B
Workflow --> C
Workflow --> D
A <--> Messaging
B <--> Messaging
C <--> Messaging
D <--> Messaging
SERVICES --- Discovery
SERVICES --- Security
SERVICES --- Observe
C --> Adapter
Adapter --> Legacy
Adapter --> Data
如果只看技术名称,它和 2006 年的 SOA 架构已经很不一样。
但如果看架构职责:
1 | |
很多问题其实并没有变化。
设计一个服务时应该问什么
SOA 最终不是一套中间件产品,而是一套架构思维。
在设计一个服务时,可以检查以下问题。
它是否对应明确业务能力
不要把:
1 | |
这类纯技术模块轻易定义成企业级业务服务。
更值得服务化的是:
1 | |
契约是否独立于实现
服务调用方是否必须知道:
1 | |
如果必须知道,说明服务封装仍然不足。
服务能否在多个流程中复用
如果一个服务只能属于一个具体流程,需要重新考虑其职责边界。
接口是否过细
如果一次完整业务操作需要:
1 | |
往往说明服务粒度存在问题。
失败语义是否清晰
必须定义:
1 | |
是否具备可观测性
一个服务如果无法回答:
1 | |
那么规模一旦增加,维护成本会迅速失控。
是否设计了生命周期
服务不是发布之后永远不变。
还要考虑:
1 | |
这也是服务治理不可缺少的一部分。
SOA 真正改变的不是通信协议,而是系统边界
回过头看,SOA 最重要的创新并不是:
1 | |
这些技术都会随着时间变化。
真正重要的是它重新提出了一个企业软件架构问题:
一个复杂组织中的 IT 能力,究竟应该如何定义、暴露、组合、管理和演进?
SOA 给出的答案是:
1 | |
这也是为什么即使经典 SOAP SOA 已经不再是新系统唯一甚至主要的技术路线,SOA 仍然值得学习。
总结
SOA 是一套围绕服务化业务能力构建企业系统的架构思想。
它通过服务契约将业务能力与技术实现分离,通过接口松耦合、技术松耦合和流程松耦合降低系统依赖,通过适配器保护遗留系统投资,通过连通服务解决服务通信,通过流程服务实现业务组合,再借助资源管理、运行管理、安全、可靠消息和事务机制形成完整的企业级服务体系。
经典 SOA 最具时代特征的部分,是 SOAP、WSDL、UDDI、ESB 和庞大的 WS-* 标准栈;最值得保留的部分,则是业务能力建模、Contract First、粗粒度服务、服务复用、流程组合、治理、补偿事务和增量演进等设计思想。
因此学习 SOA 时,不应该停留在“SOAP 怎么写”或者“ESB 是什么”这一层。
真正需要理解的是:
服务为什么要这样划分,服务之间为什么需要契约,系统为什么要松耦合,业务流程为什么应该与业务能力分离,以及当成百上千个服务开始协作以后,怎样解决发现、通信、安全、可靠性、事务和治理问题。
技术产品会换代,但这些问题并不会消失。