进程间的通信本质是交换消息
第一个维度:一对一和一对多
一对一
:一个请求一个服务实例处理一对多
:一个请求多个服务实例处理第二个维度:同步和异步
同步模式
:客户端请求服务端实时响应,客户端等待响应过程中可能会阻塞线程异步模式
:客户端请求不会阻塞线程,服务端响应可以不是实时交互方式的两个维度具体类型
<font color="red">API 优先设计</font>:首先编写接口定义,然后与客户端开发人员一起查看这些接口定义。只有在反复迭代几轮 API 定义之后,才开始具体的服务实现编程。这种预先设计有助于你构建满足客户端需求的服务(即使在那些最简单的项目中,组件和 API 之间也经常发生冲突)。
API 随着需求变更会随之发生变化
它是一组规则,用于指定如何使用版本号,并且以正确的方式递增版本号
语义化版本控制规范由三部分组成:MAJOR.MINOR.PATCH
进行次要且向后兼容的改变
向后兼容的更改是对 API 的附加或增强
理想情况下应努力向后兼容
健壮性原则:服务因改为缺少的请求属性提供默认值,客户端应忽略额外的响应属性
进行主要且不向后兼容的改变
对 API 进行主要且不向后兼容的修改。无法要求客户端升级,新旧 API 在一段时间内需要同时支持
REST API :可以使用主要版本作为 URL 路径的第一个元素。比如 /v1/xxx
消息机制:可以在发布的消息中包含版本号
基于文本的格式:JSON 或 XML
好处:可读性高,同时也是自描述的。这样的格式允许消息的接收方只挑选他们感兴趣的值,而忽略掉其他。因此,对消息结构的修改可以做到很好的后向兼容性。
弊端:消息往往过度冗长,特别是 XML。消息较大时解析文本会引入额外开销。在对效率和性能敏感的场景下需要慎重。
二进制消息格式:Protocol Buffers 或 Avro
好处:传递二进制数据,性能好/效率高。
弊端:开发稍嫌复杂,可读性不高
模式:远程过程调用
客户端使用同步的远程过程调用协议(如 REST)来调用服务
好处
弊端
分布式系统中,当服务向另一个服务发送同步请求,永远存在局部故障的可能。如:服务端过载过高响应缓慢、服务端打包维护等导致无法正常提供服务。 这种局部故障如何解决?
模式:断路器模式(如:netflix hystrix 组件)
这事一个远程过程调用代理(如:hystrix 远程调用使用 HystrixCommon 模式),在连续失败次数超过指定阀值后的一段时间内,这个代理会立即拒绝其他调用(即:超过阀值后在指定时间内的调用请求会被直接拒绝)
如上图:API Gateway 必须保护自己免受无响应服务的影响。如:途中 Order Service
雪崩/故障传播:某个服务因无法提供正常响应,不断导致客户端越来越多调用被阻塞进而客户端也无法响应它的调用者,使故障不断扩展和传播,最后导致整个系统瘫痪。
要通过合理地设计来防止在整个应用程序中故障的传导和扩散,这是至关重要的。解决这个问题可分为两部分:
远程调用代理需要有一种自我保护机制,来保证调用在失败情况下能正确被处理
Netflix 保护机制组合:
远程调用失败后,这个调用的结果如何处理?
如上图:API Gateway 调用多个服务并聚合结果返回(适合选择返回备用值)
考虑局部故障至关重要:每个服务的数据对于客户端的重要性不一样,甚至可有可无,不重要数据服务调用失败依然可以正常响应客户端,该部分数据可省略或给个默认值,若重要数据如订单查询失败,则可返回客户端失败。
为什么需要服务发现?
什么是服务发现
包含服务实例网络位置信息的一个数据库,其关键组件是服务注册表
云服务时代,无法使用静态 IP 配置客户端,应用程序网络地址必须能够动态被其他服务所发现。服务启动或停止,服务发现机制会更新服务注册表,当客户端调用时,服务发现机制查询服务注册表以获取可用的服务实例列表,并将请求路由到其中一个服务
实现服务发现有以下两种主要方式:
服务端和客户端向服务注册表进行交互。服务端向注册表注册其网络位置,客户端查询服务注册表实例列表,并向其中一个实例发送请求。
这种服务发现模式是两种模式的组合:
好处:可以处理多平台部署问题(如:分别在 kubernetes 平台及 serverless 平台部署了,它们可以只同一个 eureka 注册中心交互)
弊端:
现代部署平台(如 Docker 和 Kubernetes)都具有内置的服务注册表和服务发现机制。部署平台为每个服务提供 DNS 名称、虚拟 IP(VIP)地址和解析为 VIP 地址的 DNS 名称。客户端向 DNS 名称和 VIP 发出请求,部署平台自动将请求路由到其中一个可用实例。服务注册、服务发现和请求路由完全由部署平台处理。
如上图:该平台负责服务注册表、用于跟踪已部署服务的 IP 地址。客户端使用 DNS 名称 order-service 访问 order-service,该服务解析为虚拟 IP 地址 10.1.3.4,该平台会自动在三个实例之间进行负载均衡。
平台层服务发现模式由两种模式组合:
好处:服务发现、服务注册等所有方面完全由部署平台处理,服务和客户端都不需要包含任何服务发现代码。不论何种框架和开发语言,服务发现机制可供所有服务和客户使用。
弊端:它仅限于支持使用该平台部署的服务,如部署在 kubernetes 和 docker 上的服务是不能互通的。
服务发现机制建议:尽可能使用平台提供的服务发现。
Gregor Hohpe 和 Bobby Woolf 在 《Enterprise Integration Patterns》一书中定义了一种有用的消息传递模型。在此模型中,消息
通过消息通道
进行交换。发送方(应用程序或服务)将消息写入通道,接收方(应用程序或服务)从通道读取消息。
模式:消息
。客户端使用异步消息调用服务。
消息由消息头和消息主题组成,消息头应包含发送者提供的名称与值、
唯一消息ID
以及可选的返回地址
消息类型
事件:表示发送方这一端发生了重要的事件
命令:一条等同于 RPC 请求的消息,它指定要调用的操作及其参数
文档:只包含数据,接收方决定如何解释它,一般是对命令的回复
两种类型的消息通道
点对点通道:向正从通道读取消息的某个消费者传递消息。服务使用点对对通道实现一对一交互
例:命令式消息通常通过点对点消息通道发送
发布订阅通道:通道将一条消息发送给所有的订阅方。服务使用发布订阅通道实现一对多交互
例:事件式消息通过发布订阅通道发送
无代理架构中,服务可以直接交换消息。如:ZERO、EMQ(待定)
好处
弊端
无消息代理和同步请求响应交互方式的弊端相同
消息代理是所有消息的中介节点,发送方将消息写入消息代理,消息代理将消息发送给接收方
好处
弊端
选择合适的消息代理需要考虑的因素
消息代理按需求选择最合适的。一个延迟非常低的打击可能不会保证消息顺序,不保证消息投递成功,只在内存保存消息。保证投递成功并在次盘持久化存储消息可能具有更高的延迟。不同的需求可采用不同的消息传递方式
开源消息代理:Kafka、Pulsar、RocketMQ、RabbitMQ、ActiveMQ
基于云的消息服务:AWS Kinesis、AWS SQS、阿里云 RocketMQ
<center>每个消息代理都用自己与众不同的 概念来实现消息通道</center>
并发指的是单个消息通道多个接收方
保证消息顺序的同时,横向扩展多个接收方实例。同一个消息通道,有多个接收方(如:kafka 一个主题有多个消费实例)
现代消息代理解决并发和消息顺序方案为分片(分区)通道
,具体步骤:
分片通道
由两个或多个分片组成,每个分片的功能类似一个通道(如:kafka每个分区就是一个通道
)例:kafka 的 topic 为一个消息通道,分区为分片通道,每个分片通道分配给 kafka 的消费组某一个消费者处理,生产者可以指定分区的 key,kafka同一个分区的消息有序总结处理并发和消息顺序
:同一个消息通道(topic)多个消费实例,消息通道(topic)拆分成分片通道(分区,多个分区),每个分片通道分配给多个实例中的某一个,同一个分片通道内消息是有序的。
重复消息处理办法
2. 跟踪消息并丢弃重复项
如图:消息 ID 被单独存在一张表,业务表的更新和消息 ID 的插入在同一个事务中,若消息重复,在整个事务失败。NoSQL 没有多表同时更新的事务,可将消息 ID 放在应用程序的数据表中
如何保证程序在更新数据库和发送消息是一个原子操作
,如果不是原子操作,则结果会产生不一致或系统故障
。
使用数据库作为消息队列事务性发件箱模式
:利用数据库作为临时消息队列,将业务创建、更新、删除等操作和消息写入数据库放在同一个事务中,利用本地事务
,保证消息一致。
如图:outbox 充当临时队列,使用一个 MessageReplay 读取 outbox 表数据并发送给消息代理。
使用轮询模式发布事件
MessageReplay 相当于轮询器,不断查询 outbox 表数据并发送给消息代理
模式:轮询发布数据
通过轮询数据库中的发件箱来发布消息
弊端:不断轮询数据库会导致服务和数据库开销变大
使用事务日志拖尾模式发布事件
MessageReplay 监听数据库 outbox 表事务提交日志,然后将对应数据发送到消息代理
模式:事务日志拖尾
通过拖尾事务日志发布对数据库所做的更改
开源事务日志拖尾工具
同步调用会降低应用程序的可用性,CAP 理论中可用性一般必须保证,异步可提升可用性,使服务之间松耦合。
减少同步通信方法:1. 使用异步交互模式
2. 数据复制
3.先返回响应,再完成处理
使用异步交互模式
使用请求/异步响应方式交互,如:请求后接收方发送一个消息给请求方
复制数据(数据分发)
数据复制指的是服务维护一个数据的副本,从而减少对其他服务的同步调用。
KT 通过数据分发,使得各个服务可自定义接收分发的数据
弊端
先返回响应,再完成处理
具体步骤如下:
领取专属 10元无门槛券
私享最新 技术干货