相比于高性能、高可用架构模式在最近几十年的迅猛发展,可扩展架构模式的发展可以说是步履蹒跚。最近几年火热的微服务模式算是可扩展模式发展历史中为数不多的亮点,但这也导致了现在谈可扩展的时候必谈微服务,甚至微服务架构都成了架构设计的银弹——高性能也用微服务、高可用也用微服务,很多时候这样的架构设计看起来高大上,实际上是大炮打蚊子,违背了架构设计的"合适原则"和"简单原则"。
为了帮助你在实践中更好地进行可扩展架构设计,我将分别介绍几种可扩展架构模式。今天我先介绍传统的可扩展模式:分层架构和SOA。
分层架构是很常见的架构模式,它也叫 N 层架构,通常情况下 N 至少是 2 层。例如 C/S 架构、B/S 架构,常见的是 3 层架构(如 MVC、MVP 架构)、4 层架构,5 层架构的比较少见,一般是比较复杂的系统才会达到或者超过 5 层,比如操作系统内核架构。
按照分层架构进行设计时,根据不同的划分维度和对象,可以得到多种不同的分层架构。
划分的对象是整个业务系统,划分的维度是用户交互,即将和用户交互的部分独立为一层,支撑用户交互的后台作为另外一层。
划分的对象是单个业务子系统,划分的维度是职责,将不同的职责分离到不同的层。例如经典的三层架构:
这种架构的好处在于:
分层架构需要遵循禁止跨层访问的原则。展示层只能访问业务层,业务层只能访问数据层,数据层只能访问存储层。如果允许跨层访问,例如展示层直接访问存储层,那么存储层变更时会导致展示层也要跟着变动,失去了分层的意义。
分层架构的核心问题是不同层之间的边界比较模糊,边界一旦模糊,职责就难以明确区分。很多时候分层架构会演变为两层架构——业务和数据混杂在一起,失去了分层的意义。
SOA(Service-Oriented Architecture,面向服务架构)是一个古老的服务编排概念,早在 1996 年就被提出了,比微服务早了整整 20 年。然而 SOA 虽然发展了这么多年,却并没有取得特别广泛的应用,这其中有多方面原因。
2000 年左右,Web Service 概念被提出并开始蓬勃发展,SOA 也跟随 Web Service 的发展进入了第二个高潮期。当时 IBM、Oracle 等大厂都主推 Web Service,各种大会都在讲 Web Service,SOA 看起来前途无量。
然而,Web Service 最终并没有成为 SOA 的拯救者,原因在于:
ESB企业服务总线:ESB 是 SOA 实现的核心基础设施,但 ESB 本身成为了性能瓶颈。一个简单功能经过 ESB 转发后,性能可能降低 10 倍还多。更糟糕的是,ESB 本身成为了一个"中心",既没有实现真正的解耦,反而增加了系统的耦合度。
服务粒度问题:SOA 尝试将所有东西都定义为服务粒度,但有些业务功能其实不需要独立成服务,过度拆分反而导致系统复杂度急剧上升。
技术标准复杂:WS-*标准堆砌太多,学起来复杂,用起来更复杂。
SOA 的核心概念包括:
服务:具有清晰定义边界的业务功能单元
服务注册与发现:通过注册中心管理服务位置和元数据
企业服务总线(ESB):负责服务路由、协议转换、消息传递
服务契约:预先定义的服务接口规范
SOA 的设计理念是"化繁为简",试图通过标准化的服务定义和编排来解决企业级系统的集成问题。但由于过度设计和复杂性,SOA 最终未能达到预期效果。
| 维度 | 分层架构 | SOA |
|---|---|---|
| 划分维度 | 职责 | 服务 |
| 耦合度 | 层间解耦,层内耦合 | 服务间解耦 |
| 扩展方式 | 横向扩展整层 | 纵向扩展单个服务 |
| 适用场景 | 简单业务系统 | 复杂企业系统 |
| 实现复杂度 | 较低 | 较高 |
架构设计没有银弹,分层架构和 SOA 各有适用场景:
以下示例演示分层架构的基本结构,展示各层职责分离的效果。
python"""
分层架构示例:MVC 模式实现的学生信息管理
核心思想:各层职责分离,存储层变更不影响业务层
"""
from abc import ABC, abstractmethod
# ========== 存储层 ==========
class StorageLayer:
"""存储层:负责数据的持久化"""
def save(self, key, value):
print(f"[存储层] 保存数据: {key} = {value}")
def load(self, key):
print(f"[存储层] 加载数据: {key}")
return f"{key}_value"
# 如果需要更换存储实现,只需替换这个类
class MongoStorage:
"""MongoDB 存储实现"""
def save(self, key, value):
print(f"[MongoDB] 存储文档: {key} = {value}")
def load(self, key):
print(f"[MongoDB] 查询文档: {key}")
return f"mongo_{key}"
# ========== 数据层 ==========
class DataLayer:
"""数据层:负责数据访问逻辑"""
def __init__(self, storage):
self.storage = storage
def create_user(self, username, info):
print(f"[数据层] 创建用户记录")
self.storage.save(f"user:{username}", info)
def get_user(self, username):
print(f"[数据层] 获取用户记录")
return self.storage.load(f"user:{username}")
# ========== 业务层 ==========
class BusinessLayer:
"""业务层:负责业务逻辑处理"""
def __init__(self, data_layer):
self.data_layer = data_layer
def register(self, username, password, email):
# 业务逻辑验证
if len(password) < 6:
print("[业务层] 密码长度不足")
return False
user_info = {
"username": username,
"email": email,
"status": "active"
}
self.data_layer.create_user(username, user_info)
print(f"[业务层] 用户 {username} 注册成功")
return True
# ========== 展示层 ==========
class PresentationLayer:
"""展示层:负责用户界面交互"""
def __init__(self, business_layer):
self.business_layer = business_layer
def show_register_page(self):
print("[展示层] 显示注册页面")
def handle_register_submit(self, username, password, email):
print("[展示层] 提交注册请求")
return self.business_layer.register(username, password, email)
# 测试分层架构
if __name__ == "__main__":
print("=== 使用 MySQL 存储 ===")
mysql_storage = StorageLayer()
data_layer = DataLayer(mysql_storage)
business_layer = BusinessLayer(data_layer)
presentation = PresentationLayer(business_layer)
presentation.show_register_page()
presentation.handle_register_submit("zhangsan", "password123", "zhangsan@example.com")
print("\n=== 切换到 MongoDB 存储 ===")
# 只需替换存储层,其他层无需修改
mongo_storage = MongoStorage()
data_layer_mongo = DataLayer(mongo_storage)
business_layer_mongo = BusinessLayer(data_layer_mongo)
presentation_mongo = PresentationLayer(business_layer_mongo)
presentation_mongo.handle_register_submit("lisi", "pass456", "lisi@example.com")
输出示例:
=== 使用 MySQL 存储 === [展示层] 显示注册页面 [展示层] 提交注册请求 [业务层] 用户 zhangsan 注册成功 [数据层] 创建用户记录 [存储层] 保存数据: user:zhangsan = {'username': 'zhangsan', 'email': 'zhangsan@example.com', 'status': 'active'} === 切换到 MongoDB 存储 === [展示层] 提交注册请求 [业务层] 用户 lisi 注册成功 [数据层] 创建用户记录 [MongoDB] 存储文档: user:lisi = {'username': 'lisi', 'email': 'lisi@example.com', 'status': 'active'}
这个示例展示了分层架构的核心优势:当需要更换存储层实现(如从 MySQL 切换到 MongoDB)时,只需替换最底层的存储类,上层的业务逻辑和展示层完全无需改动。