微服务架构的进程间通信(RPC)
1. 进程间通信(RPC)
在单体式应⽤中,各个模块之间的调⽤是通过编程语⾔级别的⽅法或者函数来实现的。但是⼀个基于微服务的分布式应⽤是运⾏在多台机器上的。
⼀般来说,每个服务实例都是⼀个进程。因此,如下图所⽰,服务之间的交互必须通过进程间通信(RPC)来实现。
2. 客户端与微服务的交互模式
交互模式可以从两个维度进⾏归类。(1)第⼀个维度是⼀对⼀还是⼀对多:
⼀对⼀:每个客户端请求有⼀个服务实例来响应。
⼀对多:每个客户端请求有多个服务实例来响应。
(2)第⼆个维度是这些交互式同步还是异步:
分布式和微服务的关系同步模式:客户端请求需要服务端即时响应,甚⾄可能由于等待⽽阻塞。
异步模式:客户端请求不会阻塞进程,服务端的响应可以是⾮即时的。
(3)⼀对⼀的交互模式有以下⼏种⽅式:
请求/响应:⼀个客户端向服务器端发起请求,等待响应。客户端期望此响应即时到达。在⼀个基于线程的应⽤中,等待过程可能造成线程阻塞。
通知(也就是常说的单向请求):⼀个客户端请求发送到服务端,但是并不期望服务端响应。
请求/异步响应:客户端发送请求到服务端,服务端异步响应请求。客户端不会阻塞,⽽且被设计成默认响应不会⽴刻到达。
(4)⼀对多的交互模式有以下⼏种⽅式:
发布/订阅模式:客户端发布通知消息,被零个或者多个感兴趣的服务消费。
发布/异步响应模式:客户端发布请求消息,然后等待从感兴趣服务发回的响应。
下表显⽰了不同交互模式:
每个服务都是以上这些模式的组合,对某些服务,⼀个RPC机制就⾜够了;⽽对另外⼀些服务则需要多种RPC机制组合。下图展⽰了在⼀个打车服务请求中服务之间是如何通信的。
上图中的服务通信使⽤了通知、请求/响应、发布/订阅等⽅式。例如,乘客通过移动端给『⾏程管理服务』发送通知,希望申请⼀次出租服务。『⾏程管理服务』发送请求/响应消息给『乘客服务』以确认乘客账号是有效的。紧接着创建此次⾏程,并⽤发布/订阅交互模式通知其他服务,包括定位可⽤司机的调度服务。
3.客户端与服务端接⼝API
不管选择了什么样的RPC机制,重要的是使⽤某种交互式定义语⾔(IDL)来精确定义⼀个服务的接⼝API。接⼝API的定义实质上依赖于选择哪种RPC。如果使⽤消息机制,API则由消息频道(channel)
和消息类型构成;如果选择使⽤HTTP机制,API则由URL和请求、响应格式构成。API的变化是不可避免的,微⼩的改变可以和之前版本兼容。⽐如,你可能只是为某个请求和响应添加了⼀个属性。这时,客户端使⽤旧版API应该也能和新版本⼀起⼯作。但是有时候,API需要进⾏⼤规模的改动,并且可能与之前版本不兼容。因为你不可能强制让所有的客户端⽴即升级,所以⽀持⽼版本客户端的服务还需要再运⾏⼀段时间。如果你正在使⽤基于基于HTTP机制的RPC,例如REST,⼀种解决⽅案是把版本号嵌⼊到URL中。每个服务都可能同时处理多个版本的API。或者,你可以部署多个实例,每个实例负责处理⼀个版本的请求。
4.容错处理
分布式系统中部分失败是普遍存在的问题。因为客户端和服务端是都是独⽴的进程,⼀个服务端有可能因为故障或者维护⽽停⽌服务,或者此服务因为过载⽽停⽌或者反应很慢。假设推荐服务⽆法响应请求,那客户端就会由于等待响应⽽阻塞,这不仅会给客户带来很差的体验,⽽且在很多应⽤中还会占⽤很多资源,⽐如线程,以⾄于到最后由于等待响应被阻塞的客户端越来越多,线程资源被耗费完了。如下图所⽰:
Netfilix Hystrix提供了⼀个⽐较好的解决⽅案,具体的应对措施包括:
⽹络超时:当等待响应时,不要⽆限期的阻塞,⽽是采⽤超时策略。使⽤超时策略可以确保资源不会⽆限期的占⽤。
限制请求的次数:可以为客户端对某特定服务的请求设置⼀个访问上限。如果请求已达上限,就要⽴刻终⽌请求服务。
断路器模式(Circuit Breaker Pattern):记录成功和失败请求的数量。如果失效率超过⼀个阈值,触发断路器使得后续的请求⽴刻失败。如果⼤量的请求失败,就可能是这个服务不可⽤,再发请求也⽆意义。在⼀个失效期后,客户端可以再试,如果成功,关闭此断路器。
提供回滚:当⼀个请求失败后可以进⾏回滚逻辑。例如,返回缓存数据或者⼀个系统默认值。
5.RPC实现技术
服务之间的通信采⽤同步的请求/响应模式,可以选择基于HTTP的REST或者Thrift。服务之间的通信采⽤异步的、基于消息的通信模式,可以选择AMQP或者STOMP。⼤量开源消息中间件可供选择,⽐如RabbitMQ、Apache Kafka、Apache ActiveMQ和NSQ。消息格式可以选择基于⽂本的,⽐如 JSON和XML;⼆进制格式(效率更⾼)的,⽐如Avro和Protocol Buffer。
5.1 采⽤异步的,基于消息的通信模式
下图展⽰了打车软件如何使⽤消息发布/订阅:
⾏程管理服务在发布-订阅channel内创建⼀个⾏程消息,并通知调度服务有⼀个新的⾏程请求,调度服务发现⼀个可⽤的司机然后向发布-订阅channel写⼊司机建议消息(Driver Proposed message)来通知其他服务。
5.2 采⽤同步的,基于请求/响应的通信模式
下图展⽰了打车软件如何使⽤REST:
乘客通过移动端向⾏程管理服务的/trips资源提交了⼀个POST请求。⾏程管理服务收到请求之后,会发送⼀个GET请求到乘客管理服务以获取乘客信息。当确认乘客信息之后,紧接着会创建⼀个⾏程,并向移动端返回201状态码响应。
使⽤基于HTTP的协议的好处:
HTTP⾮常简单并且⼤家都很熟悉。
可以使⽤浏览器扩展(⽐如Postman)或者curl之类的命令⾏来测试API。
内置⽀持请求/响应模式的通信。
HTTP对防⽕墙友好。
不需要中间代理,简化了系统架构。
使⽤基于HTTP的协议的不⾜之处:
只⽀持请求/响应模式交互。可以使⽤HTTP通知,但是服务端必须⼀直发送HTTP响应才⾏。
因为客户端和服务端直接通信(没有代理或者buffer机制),在交互期间必须都在线。
客户端必须知道每个服务实例的URL。客户端必须使⽤服务实例发现机制。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。