详解微服务技术中进程间通信( 二 )


 
有时候,你不得不对API做一些主要的、不兼容的改动 。既然不能强制客户端立刻升级,那这个服务必须能够支持旧版本的API一定时期 。如果你用的是基于HTTP的机制,如REST,一个好的办法是在API的URL中嵌入版本号 。每个服务实例应该可以同时处理不同版本的API请求,或者是部署不同的服务实例来处理不同的API版本 。
 
处理部分失败 
在之前关于API网关的文章中曾经提到,在分布式系统中,总会存在部分失败的风险,既然客户端和服务是分开的进程,一个服务可能不能对一个客户端请求及时的返回结果,服务也可能因为错误或者是维护停止了,亦或是因为过载而对请求响应缓慢 。
 
比如说,如上篇文章中提到的那个产品详页的场景,试想一下如果那个推荐服务失去响应了,客户端的一个本地实现就可能在无限的等待响应中被阻塞了,这不仅会带来劣质的用户体验,而且在很多应用中,这会消耗宝贵的资源,如一个线程,最终运行时环境会线程耗尽,变成无法响应,正如下图所示 。
 

详解微服务技术中进程间通信

文章插图
 
 
为了避免这种问题,把你的服务设计成能处理部分失败是很有必要的 。
 
Netfix给我们提出了一个可以遵循的好办法,其中处理部分失败的原则包括:
 
  • 网络超时:永远不要无限的阻塞,总是在等待响应中使用超时,使用超时来确保资源不会被无限绑定 。
  • 限制未解决的请求数量:对一个客户端持有的对一个服务没有完成的请求,应该设定上限值,这个上限一旦达到,发送更多的请求就会是无意义的,而且这些新的请求需要立刻返回为失败 。
  • 回路中断器模式:跟踪成功请求和失败请求的数量,如果错误率超过了一个事先配置的阈值就开启回路中断器,让进一步的尝试立刻失败 。如果大量的请求正处在失败中,那就预示服务不可用,而且发送请求也是无意义的 。经过超时周期之后,客户端应该再进行尝试发送请求,如果请求成功,就关闭回路中短器 。
  • 提供回滚机制:一个请求失败时,执行回滚逻辑,比如说返回缓存的数据或者是默认值,也或者诸如一个关于推荐商品的空集合 。
 
Netfix Hystrix是这些模式的一种开源实现,如果你正在使用JVM,你肯定会考虑使用Hystrix的,如果你运行的是一个非JVM的环境,同样需要考虑使用一个类似的库 。
 
IPC技术 
有许多IPC技术可供选择,如同步的请求/响应机制,这里面有基于HTTP方式的REST和Thrift,另外有基于消息的异步通信机制,如AMQP和STOMP 。其中消息的格式也是多种多样的,有一些是人可读的,比如JSON和XML,有些是二进制格式的(这种更高效),如Avro和缓存协议 。稍后我们介绍同步的IPC机制,但在这之前,先讨论异步的IPC机制 。
 
异步(基于消息的通信)
当使用消息时,进程间通过异步的交换消息来通信 。客户端通过向服务发送消息来发送请求,如果期望服务返回应答,那么它发送回一个独立的消息给客户端 。由于通信是异步的,客户端不会阻塞在等待返回结果上,客户端应该是基于不会立刻收到返回结果的假设来实现 。
 
消息包含消息头(如发送者这样的元数据)和消息体,各种消息在通道上交换,任意数量的生产者都能往通道上发送消息,同样,任意数量的消费者也能从这个通道接收消息 。有两种类型的通道:点对点通道和发布/订阅通道 。点对点的通道只给连接到这个通道上的众多消费者中的一个发送消息,服务使用这种通道往往是采用前面提到的一对一的交互风格 。发布/订阅这种通道,是给连接到它之上的所有消费者发送消息,这种通道往往被一对多风格的服务采用 。
 
下图描述的是,在打车应用中,发布/订阅的通道是如何使用的
详解微服务技术中进程间通信

文章插图
 
 
 
行程管理服务向发布/订阅通道发送一个行程创建的消息,以此告诉那些对此感兴趣的服务(比如说分发器服务),一个新行程创建了 。分发器服务找到一个可用的司机,将一个需要提名司机的消息写入发布/订阅通道,这样其它的服务就能得到这个通知 。
 
有许多消息系统可供选择,你应该选择那些能支持多种开发语言的 。一些消息系统支持AMQP和STOMP这些标准协议,其它的系统是一些专有而且文档化的协议 。现在有不少开源的消息系统,其中包括RabbitMQ,Apache Kafka,Apache ActiveMQ和NSQ 。总体上看,他们都支持消息格式和通道,都是可靠的、高性能的和可扩展的,但它们在消息模型细节方面有着巨大的差异 。


推荐阅读