SOA 架构详解:从模块化到服务化,以及什么时候应该使用 SOA
一、什么是 SOA?
SOA 的全称是:
Service-Oriented Architecture
中文叫:
面向服务架构。
很多刚接触 SOA 的开发者,会下意识把它理解成:
SOA 不就是把一个 Java 项目拆成多个 Maven Module 吗?
这种理解有一点接近,但并不准确。
因为:
Java 多模块解决的是代码组织问题,而 SOA 解决的是系统架构和业务能力复用问题。
SOA 的核心思想可以用一句非常简单的话概括:
将一个大型系统中的业务能力拆分成多个独立的“服务”,不同系统通过标准化接口调用这些服务,从而降低系统之间的耦合,提高业务能力的复用性。
例如,一个电商平台可能包含:
- 用户管理
- 商品管理
- 订单管理
- 库存管理
- 支付管理
- 物流管理
- 营销管理
传统系统可能把这些功能全部写在一个应用中:
MallApplication
├── User
├── Product
├── Order
├── Inventory
├── Payment
└── Logistics
随着系统越来越大,这种设计会逐渐出现很多问题。
例如支付功能可能不仅商城需要,移动 APP、POS 系统、客服系统、合作伙伴系统也需要。
如果每个系统都自己实现一次支付逻辑:
商城系统
└── 支付逻辑
APP
└── 支付逻辑
POS
└── 支付逻辑
客服系统
└── 支付逻辑
就会产生大量重复代码。
而 SOA 的思路是:
把“支付”这种通用业务能力独立出来:
┌──────────────┐
商城 ────────────→│ │
APP ─────────────→│ Payment │
POS ─────────────→│ Service │
客服系统 ─────────→│ │
└──────────────┘
这样,“支付”就从某个系统内部的功能,变成了整个企业可以复用的业务服务。
这就是 SOA 的核心思想。
二、SOA 到底解决什么问题?
SOA 最主要解决的问题,可以概括成四个字:
系统解耦。
除此之外,还有:
- 业务能力复用
- 异构系统集成
- 系统之间统一通信
- 大型企业系统治理
- 避免重复建设
假设一家银行拥有:
网上银行
手机银行
ATM
柜台系统
信用卡系统
贷款系统
理财系统
客服系统
这些系统都需要查询客户信息。
如果没有服务化,每个系统可能都维护一套客户查询逻辑。
于是就会出现:
手机银行
└── CustomerQuery
网上银行
└── CustomerQuery
ATM
└── CustomerQuery
贷款系统
└── CustomerQuery
一旦客户规则发生变化,例如以前只需要:
身份证 + 姓名
现在增加:
身份证 + 姓名 + 实名认证状态
那么很多系统都需要修改。
SOA 的解决方案是建立一个统一的:
Customer Service
例如提供:
getCustomer()
createCustomer()
updateCustomer()
verifyCustomer()
其他系统统一调用:
手机银行 ──────┐
网上银行 ──────┤
ATM ──────────┼──→ Customer Service
贷款系统 ──────┤
信用卡系统 ────┘
以后客户业务发生变化,主要修改 Customer Service。
调用方不需要关心服务内部实现。
这就是所谓:
业务能力服务化。
三、SOA 和 Java 多模块有什么区别?
这是很多 Java 开发者最容易混淆的地方。
例如一个 Maven 项目:
mall-parent
├── mall-user
├── mall-product
├── mall-order
├── mall-payment
└── mall-common
这个只能说明:
你的代码被拆成了多个模块。
它不一定是 SOA。
这些模块完全可能最终:
一起编译
一起打包
一起启动
一起部署
那么本质上还是:
模块化单体系统。
例如:
一个 JVM
┌─────────────────────────────────┐
│ │
│ User Module │
│ │
│ Product Module │
│ │
│ Order Module │
│ │
│ Payment Module │
│ │
└─────────────────────────────────┘
而 SOA 更强调:
User Service
Order Service
Payment Service
Inventory Service
这些服务通过接口进行通信。
例如:
Order Service
|
| HTTP / RPC / SOAP / MQ
↓
Payment Service
所以两者最关键的区别是:
| 对比项 | Java 多模块 | SOA |
|---|---|---|
| 关注点 | 代码组织 | 系统架构 |
| 粒度 | 代码模块 | 业务服务 |
| 是否独立运行 | 不一定 | 通常是服务化运行 |
| 是否跨系统使用 | 一般不是重点 | 非常重要 |
| 通信方式 | Java 方法调用 | HTTP、RPC、SOAP、MQ 等 |
| 核心目标 | 代码解耦 | 业务能力解耦和复用 |
可以这样理解:
Java 多模块,是把一栋楼划分成不同房间。
而:
SOA,是把业务拆成不同的建筑,每栋建筑负责一种业务,通过道路互相通信。
四、什么叫“服务”?
理解 SOA 最关键的一步,就是理解:
Service 到底是什么?
服务不是简单的:
UserService.java
SOA 中所谓的 Service,更接近:
一个可以独立对外提供业务能力的功能单元。
例如:
Payment Service
可以提供:
createPayment()
queryPayment()
refund()
cancelPayment()
外部系统只需要知道:
支付服务提供哪些接口?
请求参数是什么?
返回结果是什么?
异常规则是什么?
调用方不需要知道:
支付服务内部使用 Java 还是 C#
使用 MySQL 还是 Oracle
内部有多少张表
内部有多少个类
这就是 SOA 中非常重要的:
服务封装。
五、SOA 的核心特征
1. 服务化
SOA 的第一个核心思想就是:
将业务能力封装成服务。
例如:
Customer Service
Order Service
Payment Service
Inventory Service
Logistics Service
这些服务通常对应的是:
真实业务能力。
而不是一些技术工具。
例如下面这些就不太属于 SOA 中典型的业务服务:
StringService
DateService
JsonService
DatabaseService
因为它们只是技术能力。
SOA 更关注:
客户
订单
账户
支付
贷款
库存
物流
这类业务领域。
六、SOA 的第二个核心思想:松耦合
假设订单系统需要修改支付状态。
一种非常糟糕的设计是:
Order System
|
↓
Payment Database
订单系统直接执行:
UPDATE payment
SET status = 'PAID'
WHERE order_id = 10001;
这种设计意味着订单系统知道:
支付数据库地址
支付表名称
字段名称
数据结构
于是支付系统一旦修改数据库结构:
status
改成:
payment_status
订单系统就可能直接报错。
这就是:
强耦合。
SOA 希望变成:
Order Service
|
↓
Payment Service
订单系统只需要调用:
pay(orderId, amount)
支付系统内部:
用什么数据库
怎么实现
有多少张表
数据怎么存
订单系统都不需要知道。
双方只需要遵守:
接口契约。
这就是:
松耦合。
七、什么是服务契约?
SOA 中有一个非常重要的概念:
Service Contract
中文叫:
服务契约。
服务契约可以理解成:
服务提供方和服务调用方提前约定好的规则。
例如支付服务提供:
POST /payment
请求:
{
"orderId": "10001",
"amount": 299.00
}
返回:
{
"paymentId": "P20260001",
"status": "SUCCESS"
}
调用方只关心:
接口地址
请求格式
返回格式
错误码
调用规则
至于支付服务内部怎么写,不需要知道。
所以 SOA 的一个非常重要的原则就是:
调用方依赖服务接口,而不是依赖服务内部实现。
八、SOA 中的服务复用
SOA 最重要的价值之一就是:
Service Reuse,服务复用。
假设一个企业存在:
Web 商城
移动 APP
微信小程序
POS
客服系统
合作伙伴平台
它们全部需要支付。
如果每个系统自己开发支付:
APP → 自己实现支付
Web → 自己实现支付
POS → 自己实现支付
客服系统 → 自己实现退款
大量逻辑会重复。
SOA 则建立统一的:
Payment Service
所有系统调用:
APP ──────────┐
Web ──────────┤
小程序 ────────┼──→ Payment Service
POS ──────────┤
客服系统 ──────┘
Payment Service 可以统一管理:
支付
退款
交易查询
支付状态
对账
这样,一个业务能力只需要维护一套。
九、SOA 中的服务组合
一个完整业务往往并不是一个服务就能完成。
例如用户下单可能涉及:
订单服务
库存服务
优惠服务
支付服务
物流服务
通知服务
于是一次下单可能变成:
创建订单
↓
检查库存
↓
锁定库存
↓
计算优惠
↓
创建支付
↓
支付成功
↓
扣减库存
↓
创建物流单
↓
发送通知
这个过程叫:
服务组合。
如果存在专门的流程控制组件统一控制服务执行过程,则经常会涉及:
Service Orchestration
也就是:
服务编排。
十、经典 SOA 中为什么经常出现 ESB?
SOA 时代经常会看到一个名词:
ESB
全称:
Enterprise Service Bus
中文:
企业服务总线。
它可以理解成:
企业内部系统通信的交通枢纽。
例如企业里存在:
CRM
ERP
支付系统
订单系统
库存系统
银行核心系统
合作伙伴系统
如果所有系统之间直接通信,很容易形成:
A ↔ B
A ↔ C
A ↔ D
B ↔ C
B ↔ D
C ↔ D
系统越来越多以后,调用关系会变成蜘蛛网。
于是可以加入一个 ESB:
系统 A ─────┐
系统 B ─────┤
系统 C ─────┼──→ ESB ───→ 各种服务
系统 D ─────┤
系统 E ─────┘
ESB 可以负责:
服务路由
协议转换
消息转换
数据格式转换
权限控制
日志记录
异常处理
服务编排
十一、ESB 为什么对传统大型企业特别有用?
因为大型企业经常存在:
异构系统。
例如一家银行内部可能同时存在:
Java
.NET
C++
COBOL
Mainframe
Oracle
DB2
老旧 TCP 系统
SOAP 系统
REST 系统
例如:
系统 A 使用:
SOAP + XML
系统 B 使用:
REST + JSON
系统 C 使用:
TCP + 自定义报文
这时候 ESB 可以充当翻译器:
SOAP/XML
↓
ESB
↓
标准协议
↓
业务服务
或者:
TCP 报文
↓
ESB
↓
JSON
↓
新业务系统
所以经典 SOA 特别适合:
大型企业遗留系统集成。
十二、SOA 的典型架构
一个比较典型的 SOA 架构可以表示为:
┌──────────────────────────────────────┐
│ Applications │
│ │
│ APP Web CRM ERP Partner │
└─────────────────┬────────────────────┘
│
↓
┌──────────────────────────────────────┐
│ ESB │
│ │
│ Routing │
│ Protocol Conversion │
│ Data Transformation │
│ Security │
│ Logging │
└─────────────────┬────────────────────┘
│
┌───────┼────────┐
↓ ↓ ↓
Customer Order Payment
Service Service Service
↓ ↓ ↓
Database Database Database
这里最重要的是:
应用
↓
服务调用
↓
业务服务
而不是:
应用
↓
直接操作其他应用数据库
十三、SOA 中经典的角色
经典 SOA 理论中通常有三个非常重要的角色。
1. Service Provider
服务提供者。
例如:
Payment Service
提供支付服务。
2. Service Consumer
服务消费者。
例如:
Order Service
调用支付服务。
3. Service Registry
服务注册中心或者服务目录。
服务提供者告诉注册中心:
我提供 Payment Service。
消费者查询:
Payment Service 在哪里?
然后调用。
于是形成经典流程:
Service Provider
|
Publish
↓
Service Registry
↑
Find
|
Service Consumer
|
Bind
↓
Service Provider
也就是经典的:
Publish → Find → Bind
十四、什么时候应该使用 SOA?
这是本文最重要的部分。
并不是所有系统都需要 SOA。
SOA 更适合以下场景。
场景一:企业内部存在大量系统,需要互相集成
这是 SOA 最经典的使用场景。
例如一个大型集团已经有:
ERP
CRM
OA
财务系统
供应链系统
订单系统
库存系统
会员系统
支付系统
这些系统可能来自不同厂商,技术栈也完全不同。
例如:
ERP → SAP
CRM → Java
财务系统 → .NET
老系统 → C++
核心系统 → Mainframe
但这些系统之间需要互相通信。
例如:
CRM
↓
查询订单
↓
Order Service
或者:
ERP
↓
查询库存
↓
Inventory Service
这个时候,SOA 非常适合。
因为 SOA 本身非常强调:
异构系统集成。
十五、场景二:多个系统需要共享同一种业务能力
例如企业中有:
APP
Web
微信小程序
客服后台
运营后台
POS
合作伙伴平台
这些系统都需要:
会员信息
支付
库存
订单查询
优惠券
物流
如果每个系统都自己写,会产生大量重复逻辑。
此时可以建设统一服务:
Customer Service
Payment Service
Inventory Service
Coupon Service
Logistics Service
于是:
多个系统
↓
统一业务服务
这种场景特别适合 SOA。
十六、场景三:系统历史悠久,无法全部推倒重写
大型银行、保险、电信、政府、航空、制造企业经常遇到这种问题。
可能存在一个已经运行十几年的核心系统:
Mainframe
COBOL
Oracle
C++
但公司又需要开发:
手机 APP
微信小程序
Web 平台
开放 API
你不可能告诉公司:
老系统全部删掉,我们重新写。
风险非常高。
SOA 提供了一种更现实的方案:
旧系统
↓
Adapter
↓
Service
↓
新系统
例如:
Old Core Banking System
↓
Account Service
↓
Mobile APP
这样可以:
保留旧系统,同时逐步将能力服务化。
十七、场景四:企业需要建立统一的业务能力中心
很多大型企业希望建设:
用户中心
订单中心
支付中心
库存中心
商品中心
会员中心
营销中心
这些本质上就是:
企业级共享业务能力。
例如:
电商平台
直播平台
线下门店
供应商平台
都调用:
统一用户中心
统一订单中心
统一支付中心
这种设计天然符合 SOA 的思想。
十八、场景五:业务流程需要组合多个系统能力
例如企业贷款流程:
客户信息系统
↓
征信系统
↓
风险评估系统
↓
审批系统
↓
贷款系统
↓
支付系统
整个流程横跨多个系统。
SOA 可以将这些能力全部服务化:
Customer Service
Credit Service
Risk Service
Approval Service
Loan Service
Payment Service
再通过流程编排组合起来。
这种:
跨系统复杂业务流程
也是 SOA 非常典型的应用场景。
十九、什么时候不适合使用 SOA?
SOA 并不是万能的。
对于很多小型项目,强行 SOA 反而会增加复杂度。
场景一:非常小的项目
例如:
个人博客
企业官网
简单后台
小型管理系统
Demo
毕业设计
整个项目只有:
5~10 个业务模块
2~5 个开发人员
这时候直接使用:
模块化单体架构
通常更合适。
例如:
mall
├── user
├── order
├── product
├── payment
└── common
这样开发、测试、部署都非常简单。
如果硬拆成:
User Service
Order Service
Product Service
Payment Service
就会额外产生:
服务通信
服务部署
服务发现
日志追踪
分布式事务
网络异常
服务监控
复杂度可能远远大于收益。
二十、场景二:业务还没有稳定
如果产品还处于:
创业初期
需求天天变
业务边界不清晰
那么过早做服务化容易出现:
今天拆 User Service
明天发现 User 和 Member 其实是一回事
后天又拆成 Customer Service
再过几天发现订单也拆错了
最终:
服务边界不断修改。
这时候通常更适合先使用:
模块化单体。
等业务稳定以后,再逐步服务化。
二十一、场景三:团队规模非常小
假设:
3 个开发人员
结果你设计:
20 个服务
团队每天可能不是在写业务,而是在处理:
服务部署
RPC 问题
网络问题
配置问题
日志问题
服务治理问题
这就属于:
为了架构而架构。
架构设计一定要考虑:
业务规模
系统规模
团队规模
运维能力
而不是:
技术越复杂越高级
二十二、SOA 和微服务是什么关系?
SOA 和微服务非常容易混淆。
两者都强调:
服务化
松耦合
业务能力拆分
接口通信
但是它们并不是完全相同的东西。
可以先简单理解:
SOA
↓
企业级服务化思想
↓
进一步演进
↓
Microservices
当然,真实的软件架构发展并不是简单的父子关系,但从学习角度这样理解非常容易建立认知。
二十三、SOA 和微服务的区别
可以通过下面这张表理解:
| 对比 | SOA | 微服务 |
|---|---|---|
| 服务粒度 | 通常较粗 | 通常更细 |
| 关注范围 | 企业级系统集成 | 单个大型应用拆分 |
| 通信方式 | SOAP、Web Service、消息等 | REST、RPC、gRPC、MQ |
| 中心化程度 | 较强 | 更强调去中心化 |
| ESB | 比较常见 | 通常避免重量级 ESB |
| 服务部署 | 不一定完全独立 | 强调独立部署 |
| 数据管理 | 可能共享数据 | 更倾向独立数据 |
| 治理方式 | 集中式治理较多 | 分布式治理较多 |
例如一个 SOA 系统可能拆成:
Customer Service
Order Service
Payment Service
Inventory Service
而微服务可能进一步拆:
Payment Service
Refund Service
Settlement Service
Reconciliation Service
Wallet Service
所以从粒度上看:
SOA 通常关注:
企业业务能力。
微服务往往关注:
更细粒度、可独立部署的业务服务。
二十四、为什么后来微服务比传统 SOA 更流行?
经典 SOA 中经常大量依赖 ESB。
最初 ESB 可能只是:
路由
协议转换
消息转换
后来很多企业不断往 ESB 中增加:
业务规则
流程逻辑
权限
数据转换
异常处理
服务编排
最后 ESB 逐渐成为:
企业系统核心
于是出现一个问题:
所有服务
↓
全部依赖 ESB
ESB 本身越来越复杂。
修改一个流程可能需要:
修改 ESB
↓
测试
↓
重新部署
↓
影响大量服务
因此微服务架构后来更加强调:
让服务本身负责业务逻辑,让通信基础设施尽量简单。
也就是著名的:
Smart Endpoints and Dumb Pipes
可以简单翻译成:
服务自己聪明,通信管道尽量简单。
二十五、从单体到 SOA 可以怎么理解?
我们可以通过系统的发展过程理解。
最开始:
单体系统
例如:
MallApplication
├── User
├── Product
├── Order
├── Payment
└── Inventory
随着代码越来越多,开始进行模块化:
mall-user
mall-product
mall-order
mall-payment
但是它们仍然可能运行在:
同一个 JVM
然后随着企业系统越来越多,开始把业务能力真正独立出来:
User Service
Order Service
Payment Service
Inventory Service
于是进入:
服务化架构。
这就是理解 SOA 最容易的一条路线:
单体
↓
模块化
↓
服务化
↓
SOA
如果进一步强调:
更小粒度
独立部署
独立数据库
自动化运维
容器化
服务治理
就越来越接近现代:
微服务架构。
二十六、一个实际电商 SOA 例子
假设公司存在三个应用:
Web 商城
手机 APP
客服系统
系统需要:
用户
商品
订单
支付
库存
物流
SOA 可以设计成:
┌───────────────────┐
Web ─────────────────→│ │
APP ─────────────────→│ ESB │
客服系统 ─────────────→│ │
└─────────┬─────────┘
│
┌──────────┬───────────┼───────────┐
↓ ↓ ↓ ↓
User Service Order Payment Inventory
Service Service Service
|
↓
Logistics Service
例如 APP 创建订单:
APP
↓
Order Service
↓
Inventory Service
↓
Payment Service
↓
Logistics Service
如果客服系统需要退款:
客服系统
↓
Payment Service
↓
refund()
这样,同一个 Payment Service 就可以被:
APP
Web
客服系统
共同复用。
这就是 SOA 非常典型的价值。
二十七、判断一个系统是不是 SOA,可以看什么?
可以问下面几个问题。
第一,系统是不是按照业务能力拆分?
例如:
订单服务
支付服务
库存服务
客户服务
而不是单纯:
util-module
dao-module
controller-module
第二,服务之间是不是通过明确接口通信?
例如:
HTTP
RPC
SOAP
消息队列
而不是直接修改对方数据库。
第三,一个业务服务是不是可以被多个应用复用?
例如:
APP
Web
POS
客服系统
都可以调用:
Payment Service
第四,服务内部实现是否对调用方隐藏?
订单系统只知道:
pay()
而不知道支付系统内部:
有多少张表
什么语言实现
数据库是什么
如果这些条件比较明显,就具有比较典型的:
SOA 特征。
二十八、SOA 最适合什么类型的公司?
SOA 特别适合:
第一类:银行
因为银行系统非常多:
核心系统
贷款
支付
信用卡
网银
手机银行
ATM
柜台
风控
而且历史系统非常多。
第二类:保险公司
存在:
客户
保单
理赔
核保
支付
代理人
财务
大量业务能力需要跨系统共享。
第三类:电信运营商
例如:
用户
套餐
计费
充值
账单
订单
客服
网络资源
也是非常典型的 SOA 场景。
第四类:大型制造企业
例如:
ERP
MES
WMS
CRM
SCM
财务
采购
供应商系统
存在大量异构系统集成需求。
第五类:大型互联网和集团企业
如果公司内部有:
多个产品
多个业务线
多个前端入口
多个内部系统
并且存在大量共享业务能力,也非常适合服务化思想。
二十九、SOA 的优点
SOA 最明显的优点包括:
1. 业务能力可以复用
一次开发:
Payment Service
多个系统使用。
2. 降低系统耦合
调用方依赖:
Service Interface
而不是依赖服务内部代码和数据库。
3. 方便异构系统集成
例如:
Java
C#
COBOL
C++
只要遵守统一接口,都可以互相通信。
4. 适合大型企业逐步改造
不需要把几十年的老系统全部重写。
可以:
老系统
↓
服务封装
↓
新应用使用
5. 业务能力更加标准化
例如整个公司只有一个:
Customer Service
而不是:
CRM 有一套客户逻辑
APP 有一套客户逻辑
Web 又有一套客户逻辑
三十、SOA 的缺点
SOA 同样会带来明显的复杂度。
1. 分布式系统复杂度上升
以前:
orderService.pay()
可能只是 Java 方法调用。
现在:
Order Service
↓
网络
↓
Payment Service
于是会产生:
网络超时
服务不可用
调用失败
重试
熔断
数据一致性
2. 服务治理困难
服务越来越多以后,需要解决:
服务注册
服务发现
版本管理
权限
监控
日志
链路追踪
3. 系统测试更加复杂
以前:
启动一个应用
就能测试。
服务化以后:
User Service
Order Service
Payment Service
Inventory Service
可能全部需要配合。
4. 运维成本提高
以前:
部署 1 个应用
现在可能是:
部署几十个服务
需要更成熟的:
CI/CD
监控
日志
容器
自动化部署
三十一、架构设计应该如何选择?
实际项目中,不要看到:
SOA
微服务
Spring Cloud
Dubbo
就觉得一定比单体高级。
架构没有绝对的高级和低级。
真正需要考虑的是:
业务复杂度
团队规模
公司规模
系统数量
历史系统情况
复用需求
运维能力
如果:
系统很小
团队很小
业务简单
使用:
模块化单体
往往最好。
如果:
企业系统非常多
大量异构系统
公共业务能力需要复用
历史系统无法全部重写
需要进行企业级系统集成
那么:
SOA 是非常合理的选择。
如果:
系统规模非常大
服务需要独立部署
团队组织已经按照业务域拆分
需要高频发布
云原生基础设施成熟
则可以考虑:
微服务架构。
三十二、总结
SOA 的全称是:
Service-Oriented Architecture,面向服务架构。
它最重要的思想不是 SOAP,也不是 ESB,更不是 Java 多模块。
它真正解决的问题是:
将企业中的业务能力封装成标准化、可复用的服务,让不同系统通过接口调用这些服务,从而实现松耦合、系统集成和业务能力复用。
可以用下面这条主线理解:
一个大型系统
↓
业务越来越复杂
↓
多个系统出现相同业务能力
↓
将公共业务能力抽离
↓
形成独立 Service
↓
通过统一接口提供能力
↓
多个系统共享
↓
SOA
SOA 特别适用于:
大型企业
多业务系统
异构系统
历史遗留系统
共享业务能力
跨系统业务流程
而对于:
小项目
小团队
简单后台
业务尚不稳定
通常没必要一开始就使用 SOA。
最后可以记住一句最简单的话:
Java 多模块,是把一个程序拆成多个代码模块;SOA,则是把整个企业的业务能力拆成一个个可以被不同系统调用的服务。
如果再进一步理解架构演化,可以粗略建立下面这条认知链:
单体架构
↓
模块化单体
↓
SOA
↓
微服务
↓
云原生服务架构
理解了这条线以后,再学习 Dubbo、Spring Cloud、Nacos、Gateway、RPC、MQ、服务注册发现、熔断、限流、链路追踪,就不会再感觉这些技术是零散的知识点。
因为它们本质上都在回答同一个问题:
当我们把一个大型系统拆成很多服务以后,这些服务应该怎样通信、发现、管理、监控和协作?