微服务及服务网格
微服务
是什么
单体应用的缺点:不同业务的代码在同一个项目内,合作上——代码改动和提交互相影响、依赖的版本冲突,程序效率上——程序包大、启动慢,部署运维上——某个业务的代码变更导致的部署更新会影响其他业务,等。鉴于这些缺点,如今微服务越来越流行。
微服务是一种开发软件的架构和组织方法,其中软件由通过明确定义的API 进行通信的小型独立服务组成。 这些服务由各个小型独立团队负责。它从业务领域的边界上对业务进行拆分,以方便以业务特性为导向进行独立的概念建模和开发。微服务架构,可以认为是面向服务的架构(Service-Oriented Architecture,SOA)的一种特定方法。
优点:单一职责、高内聚低耦合,支持技术异构,水平扩展方便,服务构建、测试、部署、更新、扩展等效率更高,其他;
缺点:单体变为微服务好像使得要做的事更多了,但随着业务发展长远来看是值得的。
单服务管理方便但大量服务使得服务整体运维管理负担变大;
单体应用拆分成微服务,需要额外做的主要有:
监控:分布式链路追踪(Sleuth/Zipkin)、日志(ELK,es、filebeat+logstash、kibana)、度量(SpringActuator)、监控(SpringBootAdmin、Zabbix等)
微服务技术架构示例:
详情可参阅《微服务设计》一书(这篇文章 是要点总结,强烈推荐阅读),包括微服务的如下多方面的指导:
介绍
建模设计
分解
集成
部署
测试(单元测试、接口或服务测试、UI测试等功能测试、响应、扩展、性能、安全等非功能测试、功能正确性的验收测试、破坏系统的探索性测试)
监控(链路追踪、日志、指标)
安全(认证与授权)
康威定律(Conway's Law):系统架构的设计受制于产生这些设计的组织的沟通结构,即任何组织在设计一套系统(广义)时,所交付的设计方案在结构上都与该组织的沟通结构保持一致。为啥会这样?组织结构间跨部门沟通比较麻烦,故倾向于通过接口调用不同结构的实现模块,从而系统设计本质上反映出了企业的组织机构,系统各模块间的接口也反映了企业各个部门之间的信息流动和合作方式。
什么是微服务
-
很小,专注好做一件事
- 构建服务时,内聚性很重要
- 单一职责原则:把因相同原因而变化的东西聚合到一起,把因不同原因而变化的东西分离开来
- 服务越小,独立性的好处越多,但管理大量服务也会越复杂
-
自治性
- 能独立部署
- 通过网络通信
- 能独立修改(不对调用方产生影响)
主要好处
-
技术异构性
-
弹性
- 舱壁,一个组件失效不会影响其它部分
-
扩展
- 粒度更细
-
简化部署
- 局部更新(C端常用)
- 快速迭代,容易回滚
-
与组织结构相匹配
-
可组合性
- 利于重用已有功能
-
对可替代性的优化
- (可以重写小服务)
服务分解
- 分析找到业务务的边界,按业务的边界拆分
- 拆到后面很可能数据库的耦合最大,存在各服务对数据库的交叉使用。推荐在分离服务前先分离数据库表结构。
微服务的设计(DDD)
一个系统的设计通常包括 【业务架构设计、系统架构设计、技术架构设计】 三个层面的设计。
业务架构——根据业务需求设计多个业务系统及其关系
系统架构——设计系统和子系统的模块。如MVC模式
技术架构——决定各模块采用的技术及框架
单体应用:侧重 系统架构和技术架构 设计
通常只是系统架构和技术架构的设计,缺乏业务架构设计(所有的业务都聚合在一个项目内)。
微服务:侧重业务架构设计,更多的是实践经验而非理论总结或指导。
在设计一个微服务系统或将单体应用改造为微服务系统时,通常重点进行的就是业务架构设计,即从服务的边界入手进行不同服务的界定以尽量达到功能的高内聚低耦合、然后针对各服务分别进行传统单体应用的系统架构和业务架构设计,这实际上与 DDD(Domain Driven Design,领域驱动设计)的某些思想不谋而合。DDD 给出了微服务在功能划分上没有给出很好指导的这个缺陷,它们在面对复杂问题和构建系统时是一种互补的关系。
DDD(Domain-Driven Design,领域驱动设计)
适用条件:适用领域驱动设计的系统须满足三个条件——1. 系统组件足够多。 2. 业务逻辑足够复杂。 3. 软件生命周期长。总之一句话,简单问题不要用领域驱动设计。金融软件恰好满足了上面三个要求,因此它也是一个领域驱动设计的标志性应用场景。
是什么:DDD 是一套应对复杂软件系统分析和设计的面向对象建模方法论。其概念太多内涵挺复杂,不同人有不同理解。其根本的思想,个人理解有两方面:
1、是在系统设计时充分考虑业务,将业务架构设计和系统架构设计进行一定程度的统一,这样设计出的系统能更长久地应对业务的后续持续迭代变化,减少以后返工(重构等)的可能性。
2、如名字所说,领域模型驱动。其所说的领域domain通常包含业务数据及行为,内聚自洽。而不是传统MVC中的静态对象Entity。
只是一种指导方针或建议,基于该指导进行系统设计时也是根据业务场景和个人不同的理解有不同的设计结果,没有标准答案没有对错。
主要概念:下面括号外为概念,括号里为为便于理解而举的微服务里的例子。
领域/子域(服务、子服务)
核心域/通用域/支撑域(核心服务、中间件服务或第三方服务、公共服务比如邮件发送)
统一语言(概念含义统一)
限界上下文(服务边界),上下文是跟业务范围有关的,比如电商场景中的订单上下文、支付上下文、物流上下文
聚合/聚合根(包、公共父包)
实体(domain 或 entity)、值对象(domain 或 entity),关于两者的区别见下文
内涵:DDD 侧重 业务架构和系统架构 设计。核心是领域对象概念的提出和应用指导。
1 业务架构设计:DDD在业务架构设计思想上与微服务设计思想契合即也是基于业务界限的模块划分,但为如何合理拆分服务提供了有效的指导(拆分过细导致服务爆炸、拆分不合理导致频繁重构等)。
领域驱动设计建议软件的所有参与方之间能以小组的形式进行直接沟通。开发要懂业务,业务方和产品也要懂技术。沟通的结果是形成一个大家都能认同和理解的领域语言。
2 系统架构设计:也提出了一些思想,主要有:
a 提出领域对象的概念:实体对象和值对象,前者是用唯一标识来标识的那些对象;作为区分,后者是用属性来描述的那些对象。可类比为 Entity 和 DTO、VO 的区别。
b 领域对象中绑定了行为,这样职责更明确内聚性更强。这是与传统系统架构设计思想很大的一个区别(感觉这种思想是分层思想逆反者,在走回头路???):
传统系统架构设计(特别是Spring中)中,实体等领域对象只是【表示对象的静态数据而没有业务行为】,具体的业务行为是在Service层写的,因此常常会感觉到很多实体有些冗余甚至多余。这种开发模式以数据为中心、以数据库ER设计作驱动。分层架构在这种开发模式下,可以理解为是对数据移动、处理和实现的过程。
这种对象称为 数据模型 或 贫血领域对象。对应地,DDD中解决这一问题,其对象称为 领域模型 或 充血领域对象。
贫血领域对象(Anemic Domain Object)是指仅用作数据载体,而没有行为和动作的领域对象。在 Spring 框架中被用得淋漓尽致。
而DDD中的领域(实体或值对象)不再只是表示数据的静态对象,而是将业务行为(不是指对该对象简单的get、set行为)也放在领域对象中。领域内的行为包括:与其他领域间的转换、领域自身的参数校验(而不是像传统MVC那样在接入层单独写独立于领域之外的校验逻辑)等
依据行为与领域对象的耦合程度,领域可分为失血模型、贫血模型、充血模型、胀血模型,实际上怎么耦合耦合到什么程度没有定论都是实践者自己发挥把握的。。。(OS:提出的思想发论文了,名利都有了,实际好不好用不关我事??)
例子1:一个用左上角坐标及长宽表示的 Rectangle 对象,要求设计一个计算其上下左右反转后的对象的方案?SpringMVC中通常是创建一个 Service 类并在其中写若干个方法,每个方法根据接收的 Rectangle 对象a计算反转后的对象b;而按 DDD 的思想则在该领域对象 Rectangle 内写方法,这样在使用时非常符合直觉: b=a.turnUp() 即可。
例子2:领域的构造方法中包含入参校验逻辑,这样应用层创建一个领域时即可执行参数校验,而不用调用单独的工具类校验;且若校验规则有变这种模式下不容易漏改。
例子3:把 SpringMVC 中 DAO 层的活也集成到 Entity 对象里,比如Ruby On Rails(OS:这也不是啥新鲜事,古早前不就这么干的么)。实际中不这样,因为耦合非常严重。
其他的就跟传统的架构设计大差不差了,MVC 的 DAO/Mapper/Repository 层、Service 层、Controller 层等。
虽然这个思路会导致代码耦合,但只要适当把握,还是可以带来收益的,因为一定程度的耦合还是可以减轻 Service 层的工作的。
、
实践:对笔者个人而言,对于 DDD,取其业务架构设计指导、弃其系统架构设计指导:DDD 的领域划分指导很有借鉴意义,但不太喜欢把行为集成在领域对象里的这种做法,因为会使得 MVC 三层划分不明确、代码的逻辑耦合变重了。当然如果能适当把握还是可以带来收益的,因为一定程度的耦合还是可以减轻 Service 层的工作。
与 Spring 的结合,涉及到的概念有 模块(就是一个服务)、领域对象(就是Entity层只不过对象集成了行为)、领域资源库(就是DAO层)、领域服务(就是Service层)、领域防腐层(就是Controller层)。一个参考例子(从包组织上大概可看出内涵):
import com.company.team.bussiness.cms.domain.valobj.*;//领域对象-值对象 import com.company.team.bussiness.cms.domain.entity.*;//领域对象-实体 import com.company.team.bussiness.cms.domain.aggregate.*;//领域对象-聚合根 import com.company.team.bussiness.cms.service.*;//领域服务 import com.company.team.bussiness.cms.repo.*;//领域资源库 import com.company.team.bussiness.cms.facade.*;//领域防腐层
关于 DDD 的参考资料:https://zhuanlan.zhihu.com/p/91525839
服务网格
(可参阅这篇文章)
服务网格是一个基础设施层,用于处理服务间通信。云原生应用有着复杂的服务拓扑,服务网格保证请求在这些拓扑中可靠地穿梭。在实际应用当中,服务网格通常是由一系列轻量级的网络代理组成的,它们与应用程序部署在一起,但对应用程序透明。
历史总是惊人的相似。为了解决端到端的字节码通信问题,TCP协议诞生,让多机通信变得简单可靠;微服务时代,Service Mesh应运而生,屏蔽了分布式系统的诸多复杂性,让开发者可以回归业务,聚焦真正的价值。
微服务间通信模式演变:
服务负责业务逻辑和服务间通信逻辑,后者比如服务的注册、发现、服务调用、调用的熔断降级限流等容错处理。缺点是耦合太严重,编码要处理的事太多太复杂。
通信逻辑剥离开,通过引用第三方库完成,例如hystrix、feign等。缺点是 需要学习库、依赖库版本升级容易有兼容问题、库所用语言绑定。目前这种方式是主流。
进一步抽象,第三方库的功能实现为一个与业务服务对等的服务,与业务服务部署在一个节点上,称为代理服务,业务服务于代理服务间通过API通信,这就是服务网格的主要内涵。其最重要的优点是像TCP一样,对应用程序透明、语言无关,故应用服务只需要关心自己的业务逻辑即可;缺点是增加了一层使得通信开销增大,另外代理服务群的运维管理也是个挑战。目前这种方式是新趋势。
可见,服务网格是一系列的用于处理服务间通信的代理服务组成的系统。用于提高微服务架构下服务间通信管理效率,即把服务间通信所涉及到的服务注册和发现、负载均衡、流量控制、熔断限流、认证与授权等基础的功能抽离出来,用专门的一个服务实现(称为代理服务),该代理服务与业务服务部署在一起。