本篇主要总结第二章:如何拆分服务。
什么是软件架构
拆分服务是一个软件架构问题。要讨论如何拆分,就要先弄明白什么是软件架构。作者引用卡耐基梅隆大学软件工程研究所对软件架构下的定义:
计算机系统的软件架构是构建这个系统所需要的一组结构,包括软件元素、它们之间的关系以及两者的属性。
关键就是软件元素(elements)和这些元素之间的关系(relation)。
紧接着,作者隆重推出软件架构的4+1视图模型。4个不同视图,每个视图都描述架构的一个特定方面,每个视图包括特定的软件元素和相互之间的关系。
- 逻辑视图:由开发人员根据功能性需求创建。类和包以及它们之间的关系。
- 实现视图:由构建编译系统创建(软件打包出来的样子)。打包出来的模块和组件以及它们之间的依赖关系。
- 进程视图:软件运行起来的样子。进程以及进程间的通信。哪些进程需要在z-轴(多实例)或z-轴(分片)扩展上;进程之间的通信方式等。
- 部署视图:进程和运行进程的机器(物理或虚拟)。软件怎么部署,哪些进程放在哪种机器上,比如需要内存大的进程放在内存大的机器上,需要CPU运算的进程放在多核CPU机器上,需要IO的进程放在高性能ssd的机器上。
- 场景:负责把视图串联起来,每个场景负责描述在一个视图中的多个架构元素如何协作,以完成一个请求。
六边形架构风格
有了这些软件架构的基础知道和方法论,再来讲如何拆分服务就具象化了。在介绍了分层架构风格后,作者重点推荐六边形架构风格,是描述微服务架构中每个服务的架构的好方法。六边形架构使业务逻辑不依赖于表示层逻辑或数据访问层逻辑,业务逻辑通过端口和适配器实现外部通信。在Java开发中,端口通常就是Java的接口;适配器,就是 SpringMVC中的controller或者访问数据库的DAO类。
微服务架构风格
将应用程序构建为松耦合、可独立部署的一组服务。参考软件架构定义提炼微服务架构的元素和关系:
- 元素:服务
- 每个服务都有自己的逻辑视图架构(通常为六边形架构)
- 单一的、可独立部署的软件组件,通过API提供功能的访问。
- 关系:服务间的通信协议
- 松耦合(约束):
- API提供交互
- 不能对服务的数据库直接访问和调用
- 松耦合(约束):
定义微服务的三步式流程
- 定义系统操作(需求user story)
- 创建抽象领域模型
- 定义系统操作:命令、参数、返回值、前置条件和后置条件
- 命令型:C-U-D增改删
- 查询型:Q-R查读
- 定义服务
- 根据业务能力进行拆分
- 根据子域DDD进行服务拆分
- 定义服务API和协作方式
- 把系统操作分配给服务
- 确定支持服务协作所需要的API
拆分服务的指导原则
- 单一职责原则 SRP
- 每个类承担一个职责,改变一个类应该有一个理由
- 闭包原则 CCP
- 在包中包含的所有类应该是对同类变化的一个集合
拆分的难点
将单体应用拆分为服务后,需要解决的几个难点:
- 网络延迟
- 服务之间大量往返调用
- 同步进程间通信导致可用性降低
- 如果有涉及多个进程间同步通信的可用性就是多个服务的可用性的乘积,服务多了系统的总体可用性就降低了
- 在服务之间维持数据一致性
- 某些操作需要更新多个服务中的数据时,需要保持各服务之间的数据一致性
- 获取一致的数据视图
- 跨多个服务(数据库)获得真正一致的数据视图。
- 上帝类阻碍了拆分
- 在整个单体应用程序中使用的全局类,采用DDD每个服务只关注自己领域的部分。
学习总结
服务拆分在实际项目中是一个反复迭代和更新过程。拆分后的服务之间一定要建立松耦合的关系,避免陷入分布式单体的陷阱。下一章主要介绍微服务架构中的通信。