1. RPC

RPC (Remote Procedure Call)是一个计算机通信协议,该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。RPC是一个分布式计算的CS模式,总是由Client向Server发出一个执行若干过程请求,Server接受请求,使用客户端提供的参数,计算完成之后将结果返回给客户端。RPC的协议有很多,比如最早的CORBA,Java RMI,Web Service的RPC风格,Hessian,Thrift,甚至Rest API。

1.1 RPC的调用流程

图片来自你应该知道的RPC原理

  • 服务消费方(client)调用以本地调用方式调用服务;
  • client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
  • client stub找到服务地址,并将消息发送到服务端;
  • server stub收到消息后进行解码;
  • server stub根据解码结果调用本地的服务;
  • 本地服务执行并将结果返回给server stub;
  • server stub将返回结果打包成消息并发送至消费方;
  • client stub接收到消息,并进行解码;
  • 服务消费方得到最终结果。

RPC的目标就是要2~8这些步骤都封装起来,让用户对这些细节透明。

1.2 RPC需要解决的问题

  • 通讯的问题
  • 服务寻址的问题
  • 参数的序列化和反序列化
  • 负载均衡的问题

2. 服务通信协议

服务通信主要是Client和Server之间建立网络连接,所有交换的数据都在这个连接里传输,连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。不同的RPC框架可能使用不同的网络协议,常用的有直接使用TCP,基于HTTP/HTTP2.0 等,目前pigeon使用的有TCP和HTTP协议。在java领域一些工具和框架已经封装对底层协议的使用进行了封装例如比较著名的Netty(这也是pigeon在使用的通信框架),Apache MINA

3. 服务寻址

每次Client向Server端发起请求之前,需要知道该向哪个Server发请求,也就涉及到服务寻址的问题。最简单的方式是直接指定Server的ip,访问特定机器上的服务。

但是在分布式环境中,通过在代码中指定ip的方式是不合适的,所以现在的RPC框架基本都是使用配置的方式来实现服务的寻址。配置方式下涉及Server端服务的注册和Client端的服务寻址,这里就成为了Zookeeper应用的绝佳场景。

3.1 ZooKeeper 管理分布式服务配置

ZooKeeper 分布式服务框架是 Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。ZooKeeper的架构通过冗余服务实现高可用性。因此,如果第一次无应答,客户端就可以询问另一台ZooKeeper主机。ZooKeeper节点将它们的数据存储于一个分层的命名空间,非常类似于一个文件系统或一个前缀树结构。客户端可以在节点读写,从而以这种方式拥有一个共享的配置服务。

图片来自分布式服务框架 Zookeeper -- 管理分布式环境中的数据

3.1.1 服务注册
当每次Server启动时,想调用ZooKeeper的Client,将自身提供的服务注册到ZooKeeper中,形如:

    http://service.test.com/demoservice/demo_1.0.0:127.0.0.1

当Server Shut down 时也会将自身节点在ZooKeeper配置中进行摘除。

3.1.2 服务寻址

Client每次请求Server之前,需要向ZooKeeper中查询该服务对应的地址,例如需要使用demoservice,查询key为http://service.test.com/demoservice/demo_1.0.0的对应ip,即可访问对应服务。

3.1.3 服务修改广播

当一个服务发生修改时,如服务的启动与关闭,都会将消息发送到感兴趣的Client。

ZooKeeper的原理及使用参见 ZooKeeper项目

4. 序列化及反序列化

Client找到对应Server之后就需要传递参数到Server端,Server在处理完数据之后也需要将结果返回给Client。

每种序列化协议都有不同的优点和确定,一个成熟的序列化协议需要通盘考虑通用性,强健性,可调试性/可读性,性能,可扩展性以及安全性等方面。目前常见的序列化协议主要有hessian,XML、JSON、ProtobufThriftAvro

例如,pigeon支持多种序列化方式,序列化方式只需要在客户端调用时通过serialize属性指定,一般情况推荐兼容性最好的hessian。
如果需要自行设计序列化方式,可以继承com.dianping.pigeon.remoting.common.codec.DefaultAbstractSerializer类来定义自己的序列化类,并通过SerializerFactory.registerSerializer(byte serializerType, Serializer serializer)接口将自定义的序列化类注册进来。

5. 负载均衡

负载平衡(Load balancing)是一种计算机网络技术,用来在多个计算机(计算机集群)、网络连接、CPU、磁盘驱动器或其他资源中分配负载,以达到最佳化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的。负载均衡器有各种各样的工作排程算法(用于决定将前端用户请求发送到哪一个后台服务器),最简单的是随机选择和轮询。更为高级的负载均衡器会考虑其它更多的相关因素,如后台服务器的负载,响应时间,运行状态,活动连接数,地理位置,处理能力,或最近分配的流量。

例如,pigeon支持random、roundRobin、weightedAutoware这几种类型,默认weighted Autoware策略。在pigeon框架中在每一次发送请求时都会有在线程中计算请求的返回时间,weighted Autoware策略是根据各个线程统计的响应时间来判断该服务的负载情况,响应时间越长说明该机器的负载越重。

6. 容灾

这里我们主要以pigeon为例介绍其实现容灾的方式,以供参考。

6.1 健康检测

在pigeon中,当使用tcp协议连接是,Client会定期发送心跳消息和接收心跳消息,如果心跳未正常返回,则在Client端会摘除这个Server节点,在后续服务寻址时不再选择该Server节点。

6.2 超时及重试

Client端可以配置一个服务的超时时间,当发送请求是,pigeon线程会计算该请求所耗费的时间,如果超过限制时间尚未返回,则根据配置返回超时或者进行重试,避免客户端过长时间的等待。

6.3 客户端配置集群策略模式

pigeon 的客户端集群策略有failfast、failover、failsafe和forking 四种方式。

  • failfast-调用服务的一个节点失败后抛出异常返回
  • failover-调用服务的一个节点失败后会尝试调用另外的一个节点
  • failsafe-调用服务的一个节点失败后不会抛出异常,返回null,后续版本会考虑按配置默认值返回
  • forking-同时调用服务的所有可用节点,返回调用最快的节点结果数据

6.4 服务隔离与限流

  • 配置服务方法级别的最大并发数
  • 限制某个客户端应用的最大并发数

详情参见Pigeon开发指南

7. 目前常见的RPC框架

除了hessian协议之外,还提供了通过servlet方式实现的RPC框架

Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目。Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(目前支持C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),并由生成的代码负责RPC协议层和传输层的实现。

Finagle是Twitter基于Netty开发的支持容错的、协议无关的RPC框架,该框架支撑了Twitter的核心服务。

Dubbo 是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。

gRPC是一个高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言。gRPC提供了一种简单的方法来精确地定义服务和为iOS、Android和后台支持服务自动生成可靠性很强的客户端功能库。客户端充分利用高级流和链接功能,从而有助于节省带宽、降低的TCP链接次数、节省CPU使用、和电池寿命。

8. RPC 与 微服务(MicroService)

微服务是一种架构思想,一个微服务一般只完成某个特定的功能,比如下单服务,订单查询服务,是将应用分解为小的,相互连接的服务。

微服务在系统层面有多种多样的表现形式,例如暴露restful api,SOA服务或者http接口。RPC可以作为实现微服务系统的一种实现方式将各个应用都暴露出RPC的服务接口,从而实现微服务的架构。

References

pigeon框架
pigeon user guide
RPC调用框架比较分析
RPC框架实现 - 容灾篇 - bangerlee

RPC原理详解 - 永志
你应该知道的RPC原理

Twitter的RPC框架Finagle简介
gRPC:Google开源的基于HTTP/2和ProtoBuf的通用RPC框架

Apache ZooKeeper
Apache ZooKeeper doc

分布式服务框架 Zookeeper -- 管理分布式环境中的数据

Google Protocol Buffer 的使用和原理
Protocol Buffers
Netty at Twitter with Finagle
Twitter的RPC框架Finagle简介

Goodbye Microservices, Hello Right-sized Services
微服务架构解析
微服务架构的设计模式
解析微服务架构(二)微服务架构综述
解析微服务架构(一)单块架构系统以及其面临的挑战
微服务实战(一):微服务架构的优势与不足
单体应用与微服务优缺点辨析
[SOLID](https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)