微服务架构设计模式
2021-11-16 16:54:57 13 举报
AI智能生成
微服务架构设计模式
作者其他创作
大纲/内容
软件架构
定义: 计算机系统的软件架构是构建这个系统所需要的一组结构,包括软件元素, 他们之间的关系以及两者之间的属性
4+1 视图模型<br>
逻辑视图<br>
主要是整个系统的抽象结构表述,关注系统提供最终用户的功能,不涉及具体的编译即输出和部署,通常在UML中用类图,交互图,时序图来表述,类似与我们采用OOA的对象模型
物理视图
物理视图通常也叫做部署视图(deploymentview),是从系统工程师解读系统,关注软件的物流拓扑结,以及如何部署机器和网络来配合软件系统的可靠性、可伸缩性等要求。
进程视图
从过程角度,描述系统的并发和同步设计。旨在解决进程、线程、并发、同步、通信等方面的问题;
开发视图
描述软件在开发环境下的静态组织,从程序实现人员的角度透视系统,也叫做实现视图(implementation view)。开发视图关注程序包,不仅包括要编写的源程序,还包括可以直接使用的第三方SDK和现成框架、类库,以及开发的系统将运行于其上的系统软件或中间件, 在UML中用组件图,包图来表述。
用例场景+1
用例视图(Use Cases View),最初称为场景视图,关注最终用户需求,为整个技术架构的上线文环境.通常用UML用例图和活动图描述。
重要性
功能性需求
主要包括程序的意义, 用例或者用户故事等<br>
非功能性需求<br>
能力的需求, 包括不限于可维护性/可伸缩性/可测试性/可扩展性/可部署性<br>
风格表现方式<br>
分层式
将软件元素按照层次来进行划分, 例如表现层/业务层/持久层等<br>
<br>
六边形式
选择将业务逻辑作为核心层的一种逻辑视图, 六个边包括不局限于各种出入站的适配器等. 例如入站包括: RestFul/Soap 服务/Controller适配器/消息接收器等, 出站包括: 存储接口/其他服务调用器/消息发送器等等;<br>
<br>
实现风格
单体应用
定义: 将应用程序构建为单个可执行和可部署的组件<br>
微服务
定义<br>
微服务: 将应用程序构建为松耦合,可独立部署的一组服务
服务: 是一个单一的,可独立部署的软件组件, 实现了一些有用的功能.<br>
松耦合: 服务之间的交互采用API完成, 封装了服务内部的细节.<br>
<br>
备注<br>
如何区分共享库? <br>
如果是底层通用的不太可能变化的东西, 可以使用共享库功能. 例如一些公关的Util包, 或者一些第三方的框架, 甚至是业务上一些底层没有变更需求的公关组件.
服务的大小重要否?<br>
微服务这个术语可能让你错误的聚焦在微上, 它似乎暗示了服务应该很小. 事实上这并不是一个考虑的主要因素, 更多的要从团队开发角度上, 交付的时间上, 与其他团队协作最少工作上, 其他还包括测试上等. <br>
微服务架构的实现
定义
和所有软件开发一样, 第一架构也是一项艺术而非技术, 现实世界中这也是一个不断迭代和持续创新的过程.<br>
<br>
识别系统操作<br>
系统操作是应用程序必须处理的请求的一种抽象描述, 它既可以是更新数据的命令, 也可以是查询数据的操作. 具体就是描述服务之间协作方式的架构场景.<br>
拆分服务<br>
根据业务能力拆分
业务能力一般类似于角色-能力的角度, 例如外卖送餐服务的角色为送餐员, 其能力是取餐/送单/返回等.<br>
根据领域概念拆分
领域概念来自DDD的划分, 将领域切分为一个一个的子域. <br>
<br>
拆分原则
单一原则
小的/内聚的/仅仅含有单一职责的服务, 这样设计可以缩小服务的大小, 并提升其稳定性.<br>
闭包原则
相同功能的一组组件都应该在一个服务内, 这个可以控制服务的数量. 理想情况下, 一个变更只会影响一个团队和一个服务. 其是解决分布式单体这种可怕的反模式的法宝.<br>
拆分难点
网络延迟
同步进程间通信可能导致可用性降低
服务之前维持数据的一致性, 例如分布式事务<br>
获取一致的数据视图, 一致性差导致的数据瞬时差异<br>
公共类/上帝类, 造成了拆分困难.<br>
事件溯源
概念<br>
这个是一种以事件为中心的编写业务逻辑和持久化领域对象的方法, 通常情况下可以和领域事件协调一起<br>
好处
可靠地发布领域事件<br>
保留历史, 可以作为行为分析, 或者数据审计使用<br>
最大限度的可以减少对象与关系的阻抗失调问题
主要是说BO对象与关系表无法映射的时候的差异问题
缺点
学习曲线高
消息传递的问题, 造成复杂度高<br>
事件演化分析, 需要有一定的能力<br>
删除数据/ 查询历史的事件, 需要一定的技术基础<br>
发布事件方式
第三方程序轮询事件表/ 事件的集合<br>
通过数据库本身的事务日志拖尾机制, 或者类似mysql的bin log模式<br>
设计模式
聚合器微服务设计模式
聚合器调用多个服务实现应用程序所需的功能。它可以是一个简单的 WEB 页面,将检索到的数据进行处理展示。它也可以是一个更高层次的组合微服务,对检索到的数据增加业务逻辑后进一步发布成一个新的微服务,这符合 DRY 原则。另外,每个服务都有自己的缓存和数据库。如果聚合器是一个组合服务,那么它也有自己的缓存和数据库。聚合器可以沿 X轴 和 Z轴 独立扩展。
<br>
代理微服务设计模式
在这种情况下,客户端并不聚合数据,但会根据业务需求的差别调用不同的微服务。代理可以仅仅委派请求,也可以进行数据转换工作。
<br>
链式微服务设计模式
在这种情况下,服务A 接收到请求后会与 服务B 进行通信,类似地,服务B 会同 服务C 进行通信。所有服务都使用同步消息传递。在整个链式调用完成之前,客户端会一直阻塞。因此,服务调用链不宜过长,以免客户端长时间等待。
<br>
分支微服务设计模式
这种模式是聚合器模式的扩展,允许同时调用两个微服务链,如下图所示
<br>
数据共享微服务设计模式
自治是微服务的设计原则之一,就是说微服务是全栈式服务。但在重构现有的“单体应用(Monolithic Application)”时,SQL 数据库反规范化可能会导致数据重复和不一致。因此,在单体应用到微服务架构的过渡阶段,可以使用这种设计模式,如下图所示
<br>
异步消息传递微服务设计模式
虽然 REST 设计模式非常流行,但它是同步的,会造成阻塞。因此部分基于微服务的架构可能会选择使用消息队列代替 REST 请求/响应,如下图所示
<br>
查询模式
外部化配置模式
业务逻辑设计
组织模式<br>
事务脚本<br>
抛弃OO的思想, 直接面向过程的一种设计方式.Matrtin 曾经提到过这个, 类似使用存储过程代替服务来直接处理.<br>
领域模型
将业务逻辑组织为由具有状态和行为的类构成的对象模型.
领域驱动设计
基本元素<br>
实体(Entity)
具有持久化ID的对象
值对象
工厂
存储库(Repository)
服务
实现不属于实体或者值对象的业务逻辑对象
聚合设计模式
概念: 将领域模型组织为聚合的集合, 每个聚合都是可以作为一个单元进行处理的一组对象构成的图<br>
<br>
规则
只引用聚合的根<br>
说白了只能通过跟对象引用别的聚合的根, 或者被引用<br>
聚合间的引用必须使用主键
没有对象引用了, 但是我觉得可以使用类似ID/UUID/Code等婉转的方式<br>
一个事务中, 只能创建和更新一个聚合<br>
如果使用Saga, 那么每一个聚合都是一个参与者.<br>
<br>
颗粒度<br>
这个按照你的团队成熟度/业务成熟度/实际情况等考虑
领域事件<br>
概念: 领域事件是聚合发生变化的事情, 通常代表着状态的变化. <br>
识别方法
事件风暴模式, 包括头脑风暴/识别事件发生机制/识别聚合<br>
发布方式
通过聚合主动发送事件给订阅者, 类似Observer模式<br>
通过聚合根保存这些事件, 由外部或者其他机制来检索<br>
例子
<br>
观测性模式
开发安全相关
进程间通信<br>
概述
交互方式
<br>
一对一
请求/响应
单个客户端发起请求并等待返回, 可能导致线程堵塞.<br>
异步请求/响应
单个客户端发起异步请求, 服务器异步返回响应. <br>
单向通知<br>
单个客户端方发起请求, 不期望服务器端返回<br>
一对多<br>
发布/订阅
客户端发布消息, 被0-N个感兴趣的服务订阅<br>
发布/异步响应
客户端发布消息, 然后等待从特定的的服务发回的响应. 类似两个消息通道..<br>
API定义<br>
api优先原则, 例如使用RAML或者Swagger等提前定义好API的规范, 保证前后端的并行工作<br>
API的版本规范, 可以使用路径加上版本号, 或者HttpHeader中加入verison等机制<br>
向后兼容需要考虑健壮性原则, 避免产生升级壁垒<br>
消息格式<br>
文本
JSON/XML
二进制
Protocol Buffers/Avro/Thrift<br>
同步通信
RPI概念
RPI是远程过程调用模式<br>
REST
概念<br>
RESTful是这一种开发的风格, 最早来自Roy的论文<br>
另外一个关键性概念是 资源<br>
成熟度模型<br>
Level 0<br>
本层级的 Web 服务只是使用 HTTP 作为传输方式,实际上只是远程方法调用(RPC)的一种具体形式。SOAP 和 XML-RPC 都属于此类。<br>
Level 1<br>
Level 1 层级的 API 引入了资源的概念。要执行对资源的操作,客户端发出指定要执行的操作和任何参数的 POST 请求。<br>
Level 2<br>
Level 2 层级的 API 使用 HTTP 语法来执行操作,譬如 GET 表示获取、POST 表示创建、PUT 表示更新。如有必要,请求参数和主体指定操作的参数。这能够让服务影响 web 基础设施服务,如缓存 GET 请求。<br>
Level 3<br>
Level 3 层级的 API 基于 HATEOAS(Hypertext As The Engine Of Application State)原则设计,基本思想是在由 GET请求返回的资源信息中包含链接,这些链接能够执行该资源允许的操作。例如,客户端通过订单资源中包含的链接取消某一订单,GET 请求被发送去获取该订单。HATEOAS 的优点包括无需在客户端代码中写入硬链接的 URL。此外,由于资源信息中包含可允许操作的链接,客户端无需猜测在资源的当前状态下执行何种操作。(包括字描述和下次动作的概念)<br>
<br>
优缺点<br>
好处
简单好用上手快
工具和浏览器扩展支持方便测试<br>
使用http协议对于防火墙比较友好<br>
行为和资源分离,更容易理解。<br>
弊端<br>
直接的请求/响应模式, 可用性需要双方保持在线保证<br>
客户端必须要支持URL的位置概念, 否则而需要服务发现来定位<br>
多个请求中获取一个资源, 概念上有些不匹配<br>
映射到HTTP动词上很有挑战, 包括返回的HTTP状态码也是痛点<br>
gRPC<br>
概念
一种基于二进制消息的协议, 有一个或者多个服务的请求和响应定义组成, 类似java的接口. 除了支持简单的请求/响应, 还支持流式的RPC, 支持双向流入流出方式.<br>
优缺点
好处
设计复杂的操作的API比较方便
高效/紧凑的进程间通信, 大量通信的时候比较有优势
支持双向流的模式
支持各种异构语言的实现, 和相互调用<br>
弊端
学习成本, 且上手需要学习IDL规范<br>
防火墙可能不支持HTTP/2的协议
调试和跟踪二进制没有文本方便<br>
断路器模式
概念
一个远程过程调用的代理, 再连续失败次数超过一定阈值后, 这个代理会拒绝掉其他访问该服务的调用. 例如Hystrix<br>
处理方式<br>
网络超时, 避免无限的堵塞<br>
限制请求的数量, 使用流量桶/令牌桶模式<br>
断路器模式, 根据成功失败的数量, 来进行限制<br>
服务发现
概念
其关键性组件是服务注册表, 包含服务实例的网络位置信息额一个数据库<br>
主要方式
应用层服务发现模式
自注册和客户端发现
<br>
平台层服务发现模式
Docker和Kubernetes 有内置的服务注册表和服务发现能力, 可以使用DNS和虚拟IP进行路由.<br>
第三方注册/服务端发现
<br>
异步通信
消息类型
文档<br>
仅仅包含数据的通用消息, 接受者知道如何解析它<br>
命令
等同于使用RPC做调用, 包含具体的操作和参数<br>
事件<br>
表示发送方发生了具体的时间, 通常情况下是领域事件, 例如说Order的状态变更<br>
例子
<br>
通道类型
点对点通道
一方传给另一方, 一对一的通讯<br>
发布订阅通道
一对多的交互模式<br>
消息代理
无代理架构
服务可以直接交换消息, 例如ZeroMQ就是一种技术, 也是规范. 可以实现Tcp, Unix风格的Socket和多播等<br>
有代理架构
消息代理是中介节点, 好处是发送方不需要直接接受方的位置, 同时有缓冲的和持久化的功能.包括ActiveMQ/RabbitMQ/Kafka等<br>
<br>
<br>
消息顺序<br>
现在消息代理Kafka和Aws Kinesis使用的是分片/分区通道 发送消息头部制定分区键, 这样可以通过hash来计算进行选择. SQS使用的也是分组的概念, 使用消息分组ID来进行分区.<br>
<br>
重复消息
幂等消息处理<br>
程序本身进行处理, 根据业务的要求进行代码的编写<br>
重复消息丢弃
例如: 使用数据库的唯一约束进行丢弃, 每次接受一条消息插入到数据库, 插入失败的则丢弃<br>
事务性消息<br>
使用数据库表作为消息队列<br>
首先插入消息到数据库表, 然后利用其它的消息中继程序读取消息再发送.<br>
<br>
两种方式
1. 使用消息中继轮询消息表, 进行数据的发送<br>
2. 使用事务日志拖尾机制, 例如每次事务提交都在拖尾的事务日志中添加一个条目, 事务日志挖掘其可以读取, 再转换为消息发送. 例如: Debezium和LinkedIn Databus等<br>
异步交互
<br>
0 条评论
下一页
为你推荐
查看更多