2.1 微服务架构到底是什么
2.1.1 软件架构是什么, 为什么它如此重要
软件架构的定义
该定义来自卡耐基梅隆大学软件工程研究所的 Len Bass 及其同事:
- 计算机系统的软件架构是构建这个系统所需要的一组结构, 包括软件元素, 它们之间的关系以及两者的属性
有点像 E-R 图.
软件架构的4+1视图模型
我玩过的游戏 <<缺氧>> 中也提供了不同视图:
- 电路
- 水管
- 气管
- 气体分布
- 温度
- …
以前我对架构抱有高大上的想法 (银弹), 但现实是复杂的.
每个视图的目的:
场景:
- 负责把视图串联在一起
为什么架构如此重要
架构是如何影响质量属性的?
2.1.2 什么是架构的风格
David Garlan 和 Mary Shaw 定义了如下架构风格:
- 有限的元素 (组件)
- 关系 (连接器)
- 组合它们的一组约束
4+1视图模型描述了软件架构不用方面, 而架构风格是视图模型的实例?
分层式架构风格
分层架构将软件元素按 “层” 的方式组织. 每个层都有明确定义的职责. 分层架构还限制了层之间的依赖关系. 每一层只能依赖于紧邻其下方的层 (如果严格分层) 或其下面的任何层.
三层架构是应用与逻辑视图的分层架构, 它将应用程序的类组织到以下层中:
分层架构风格的弊端:
关于架构风格的六边形
六边形架构风格选择以业务逻辑为中心的方式组织逻辑视图.
此架构的一个关键特性和优点是业务逻辑不依赖于适配器, 相反, 各种适配器都依赖业务逻辑.
业务逻辑具有一个或多个端口 (port). 端口定义了一组操作, 关于业务逻辑如何与外部交互:
- 入站端口是业务逻辑公开的 API, 它使外部应用程序可以调用它
- 一个实例是服务接口, 定义服务的公共方式
- 出站端口是业务逻辑调用外部系统的方式
- 一个实例是存储库接口, 定义数据访问操作的集合
业务逻辑的周围是适配器:
- 入站适配器: 通过调用入站端口来处理来自外部的请求
- Spring MVC Controller
- 订阅消息的消息代理客户端
- 出站适配器: 实现出站端口, 并通过调用外部应用程序或服务处理来自业务逻辑的请求
- 数据访问对象 (DAO)
- 代理类
2.1.3 微服务架构是一种架构风格
- 单体架构是一种架构风格, 它的实现视图是单个组件: 单个可执行文件或 WAR 文件
- 微服务架构也是一种架构风格. 它的实现视图由多个组件构成: 一组可执行文件或 WAR 文件
- 它的组件是服务
- 连接器是使这些服务能够协作的通信协议
- 每个服务都有自己的逻辑视图架构, 通常是六边形架构
微服务架构强加的一个关键约束是服务松耦合.
- 服务之间的协作方式存在一定限制
什么是服务
服务是一个单一的, 可独立部署的软件组件, 它实现了一些有用的功能.
- 典型的服务往往都具有六边形架构
什么是松耦合
服务之间的交互采用 API 完成, 这样做就封装了服务的实现细节.
- 数据库私有访问
- 数据共享困难
共享类库的角色
- 要注意避免引入耦合
可能的例子:
- 不太会变的功能应该打包成共享库, 以便各个服务来引用, 避免重复实现
- 经常变更的功能应以服务来实现
服务的大小并不重要
- 大小不是一个重要的考虑因素
- 由小团队开发的服务, 交付时间短, 与其他团队协作少
2.2 为应用程序定义微服务架构
定义架构的三步式流程 (大概的方法):
- 需要不断迭代, 创新
- 第一步: 将应用程序的需求提炼为各种关键请求
- 第二步: 确定如何分解服务, 两种策略 (都是非技术概念分解和设计)
- 定义与业务能力相对应的服务
- 围绕领域驱动设计的子域来分解和设计服务
- 第三步: 确定每个服务的 API, 还有
- 服务的写作方式
- 进程间通信机制
服务分解的障碍:
- 网络延迟
- 服务之间的同步通信降低了可用性
- 维护跨服务的数据一致性
- 上帝类
可以研究 go-micro 是如何解决的.
2.2.1 识别系统操作
起点是应用程序的需求, 包括用户故事及其相关的用户场景.
两步式流程:
- 抽象领域模型, 提供描述系统操作的词汇表
- 确定系统操作, 根据领域模型描述每个系统操作的行为
创建抽象领域模型
- 第一步: 为应用程序描绘一个抽象的领域模型, 能够为描述系统操作定义一些词语
- 通过用户故事, 提炼一些类
类的作用:
定义系统操作
两种类型的系统操作:
- 命令型: 创建, 更新, 删除数据
- 查询型: 查询, 读取数据
识别系统指令的切入点是分析用户故事和场景中的动词.
系统命令举例:
命令规范定义了命令对应的参数, 返回值和领域模型类的行为.
行为规范中包括前置条件, 后置条件.
createOrder() 系统操作规范:
acceptOrder() 系统操作规范:
2.2.2 根据业务能力进行服务拆分
创建微服务架构的策略之一: 采用业务能力进行服务拆分.
- 业务能力是指一些能够为公司 (或组织) 产生价值的商业活动
业务能力定义了一个组织的工作
组织的业务能力通常是指这个组织的业务是做什么, 它们通常都是稳定的. 组织采用何种方式来实现它的业务能力, 是随时间不断变化的.
- “兑现支票”: 支票 -> ATM -> 智能手机
识别业务能力
一个组织有哪些业务能力, 是通过对组织的目标, 结构和商业流程的分析得来的.
- 业务能力通常集中在特定的业务对象上
- 能力通常可以分解为子能力
业务能力规范包括:
- 输入
- 输出
- 服务等级协议 (SLA)
FTGO 的业务能力:
从业务能力到服务
决定将哪个级别的能力层次结构映射到服务是一个非常主观的判断.
2.2.3 根据子域进行服务拆分
领域驱动设计是构建复杂软件的方法论:
- 面向对象
- 领域模型. 领域词汇表, DDD 也称为通用语言 (Ubiquitous language)
DDD 的两个重要概念:
- 子域
- 限界上下文, 包括实现这个模型的代码集合
可以通过 DDD 的方式定义子域, 并把子域对应为每一个服务:
2.2.4 拆分的指导原则
面向对象设计的一些原则可以用于知道微服务架构的设计工作.
单一职责原则
Single Responsibility Principle, SRP
改变一个类应该只有一个理由.
闭包原则
Common Closure Principle, CCP
在包中包含的所有类应该是对同类的变化的一个集合, 也就是说, 如果对包做出修改, 需要调整的类应该都在这个包之内.
- <<面向对象设计的原则>> Bob Martin
2.2.5 拆分单体应用为服务的难点
网络延迟
解决方案:
- 在一次往返中获取多个对象
- 把多个相关的服务组合在一起
同步进程间通信导致可用性降低
服务之间的调用是个链条, 如果其中某个服务出现问题, 那么用户的某个操作就会失败.
- 使用异步解耦
在服务之间维持数据一致性
需要实现事务操作, 如果要更新两个或更多服务的数据, 要么都成功, 要么都失败.
- 两阶段提交 (two phase commit)
- Saga (最终一致)
获取一致的数据视图
也是类似事务, 但不会带来真正问题 (读操作).
上帝类阻碍了拆分
上帝类是在整个应用程序中使用的全局类.
传统建模技术创建的 Order 类结构:
解决方案是使用 DDD, 并将每个服务视为具有自己的领域模型的单独子域:
- 每个服务有自己领域模型及其对应的 Order 类
Order -> Delivery:
Order -> Ticket:
Order -> 新 Order:
- 用事件驱动机制 Saga 来维护服务之间的一致性
2.2.6 定义服务 API
存在服务 API 的两个原因:
- 某些操作对应系统操作
- 存在一些其他操作用以支持服务之间的写作
定义服务 API 的过程:
- 系统操作映射到服务
- 确定服务是否需要与其他服务写作以实现系统操作
把系统操作分配给服务
- 确定哪个服务是请求的初始入口点
确定支持服务协作所需要的 API
前置条件, 后置条件:
- REST 等同步通信机制
- 消息代理的异步消息
- 自包含服务
- CQRS 模式