分布式计算场景下,在一台计算机上运行的程序,需要跟另一台计算机上的程序进行交互。从开发角度而言,如果这种交互看起来跟本地函数调用是一模一样的,成本是最低。
因此,RPC设计需要考虑以下三个因素:
1.在本地和远程计算机之间,传递对象。
对象的角色是入参和返回值。这种传递对方的方式叫序列化和反序列化。对象是类的实例化,对象内部有函数和变量。一个对象在生命周期内可以经历多种计算,形成特定的状态,序列化就是把对象转化成一组二进制字节码。把这组字节码发送到远程计算机后,可以直接在远程计算机复制出这个对象。就像《黑客帝国》的密探史密斯先生,伸手到穿越到另一个世界,复制出另一个完全一样的史密斯。
2.远程调用的类定义。
如果把一组二进制码,传递到远程计算机反序列化,远程计算机需要知道这组二进制码的含义。进一步地,对象的作用是传递参数的话,因此不需要有函数,更进一步地,成员变量一律是public ,protected和private是没有意义。这块有两种现实方式:第一种,本地计算机和远程计算机都有被传递的对象的类定义源码; 第二种,非源码方式的定义。
3.远程调用的代理类。
远程调用的形式跟本地调用是一样的,实际上背后的过程不一样,因此需要给远程调用做一次封装,解决背后的不一样的问题,这层封装叫代理,由RPC框架解决。
在这三个因素之外,还有一些次级的问题:服务端和客户端的关系问题,单向还是双向; 服务端的服务注册; 使用哪种传输协议,TCP/UDP,HTTP,HTTP2; 使用哪种序列化方式,xml,json,protobuf, avri, thrift; 是否支持多种语言。
开源RPC框架非常多,从业务角度而言,选择开源框架有几个原则:
1.用的人多。这意味着潜在的坑少,没有大坑,糟糕的坑大概率被填完了。好招人,懂的人比较多。普适多种业务,在不同场景下都经历了考验。
2.社区稳定强大。框架可以持续活下去,你的技术投入不会打水漂。框架可以持续进化下去,应对新业务新趋势。
3.支持多种语言。公司内部不同业务使用不同语言,可以在RPC上交互。
4.性能。足够高。足够用。
5.足够简洁。
影响比较大的RPC框架:
gRPC:google开源,protocal buffer(以下简称pb)序列化,需要通信协议,支持多种语言,不能更换序列化库,入参必须有Context,出参必须是Status。
sofa-pbrpc:百度开源,pb序列化,需要通信协议,只支持c++,不能更换序列化库,入参出参复杂。
pebble:腾讯开源,pb序列化,需要通信协议,只支持c++,不能更换序列化库,入参出参跟本地调用完全一致。缺点:服务注册只能使用对象指针,不能是lambda,也不能是function。
mesagepak-rpc: apache项目,mesagepak序列化,不需要通信协议,只支持c++,不能更换序列化库,客户端入参出参跟本地调用完全一致,服务端实现略搓略原始。
thrift: facebook开源给apache,thift是rpc框架,提供序列化功能,不需要通信协议,支持多种语言,入参出参跟本地调用完全一致。缺点,官方文档少,bug修复,rpc不是线程安全的,另外facebook又开源了一个 fbthrift。美团、小米、喜马拉雅、evernote在用。
avro rpc:apache项目,avro是序列化库,提供rpc功能,不需要通信协议(自带schema),支持多种语言,入参出参跟本地调用完全一致。客户端和服务端需要维护一份共同的schema文件,也就是avpr文件。Hadoop体系大量使用avro。avro性能类似thrift,也有测评指出性能只有thrift一半。
Hessian:自有二进制序列化,支持多种语言,不需要通信协议,不支持更换序列库。它的RPC是基于HTTP协议的。是一种轻量级的RPC框架,适应于对性能要求不高的场景。
RMI:jdk的rpc。目前使用较少。在dubbo的rpc支持列表里。
早年还有一些xmlrpc,基本上不被技术选型考虑。