RPC是RemoteProcedureCall(远程过程调用)的缩写,是运行在多任务操作系统或联网计算机之间的程序和进程使用的一种通信技术。开始编码的人都应该知道,现代编程中最常用的系统间通信方式是:http调用和rpc调用。对于同一个网络或互操作的网络环境,rpc调用方式是系统间通信交互最常用的方式,其性能比基于http的通信方式提高数倍甚至数个数量级协议。我们公司平台的rpc通信每秒几万甚至更高,每次调用的通信时间在一定程度上几乎可以忽略不计。另外,我们首席架构师深厚的系统设计功底,使用了进程内缓存等优化措施,整体rpc调用平均耗时也在1毫秒以下。这是http协议无法达到的速度。如果你在浏览器的F12窗口观察过,如果一次http协议调用的总耗时是5毫秒甚至10毫秒,那么你其实可以认为这个http请求的响应时间很短。就是这样。因此,大部分公司内部系统之间的通信,都会使用rpc调用的方式。不要在这里开玩笑。如果你公司的内部系统通信是基于http协议,那说明你的系统很可能没有性能需求。RPC调用虽然简化了编码的难度,但是实现一个rpc框架绝非易事,实现一个优秀的rpc框架更是难上加难。连接服务大多数rpc框架的服务器作为服务运行。为了避免在监听端口上与其他进程发生冲突,一般会随机选择一个端口进行监听。虽然这样看起来不错,但是给客户带来了麻烦。如果服务端监听固定端口,客户端连接服务端时,至少可以在代码中固定服务端的IP和端口。但是现在服务端监听的端口是随机的,更可怕的是服务端可能会改变或者切换IP,那么客户端如何才能正确的与服务端建立连接呢?服务器使用这种随机方式监听端口的原因之一是为了以后的扩展。客户端如何正确连接到服务器,采用了集中式的解决方案。服务器引入了服务注册表的概念。有些系统可能用其他名称来表示,但功能是相似的。这个注册中心存储了所有的服务器信息,包括每个服务器的IP和端口,有的甚至还有版本信息。每个服务器进程启动时,主动连接到注册中心,主动注册。.客户端在发起连接服务时,首先到注册中心查找注册的服务器信息,然后进行连接。这样,rpc调用在某种程度上是在连接步骤中“自动化”的。调用方法客户端和服务端建立tcp连接后(有些rpc框架会使用udp协议),接下来的问题就是客户端和服务端如何相互识别。举个栗子:客户端想实现一个获取用户名的方法,如何定义方法名让服务端正确识别呢?我应该传递一个字符串“GetName”还是传递一个整数1来表示它?服务器的返回结果,如果发生异常,如何返回?当我们在本地调用一个函数时,语法、语义、语法和语义的分析,编译器已经帮我们做好了,但是rpc是远程过程调用。虽然表面上和本地类似,但是已经出现了跨网络的情况,语法语义等,这些分析都需要客户端和服务端达成共识。事实上,现代几乎大多数rpc通信都遵循一个标准:当客户端发起远程调用时,首先会调用本地的Stub,Stub负责将被调用的接口、函数和参数按照约定的协议格式进行编码,以及然后通过本地Runtime进行传输,最后通过网卡将数据包发送到指定的服务器。serverRuntime收到请求后,会先调用本地的Stub按照约定的协议格式进行解码,最后调用server的具体函数。函数执行后,结果由本地存根编码,通过运行时发送给客户端。clientRuntime收到消息后,使用本地Stub进行解码,然后进行其他处理。可见,现代rpc框架实际上是将协议封装和数据传输抽象成不同的层次。Stub负责协议部分,Runtime处理数据传输和网络相关部分。网络数据传输数据通过网络传输时,如何识别每个数据包的完整性。如果是简单的int类型数据,很简单,但是如果是类或者数组,甚至是其他变长类型,rpc通信协议如何约束这些,如果能正确识别数据是最协议部分的困难部分。更何况还有大头小头编码的问题。任何形式的基于网络的传输都是不可靠的,网络的本质是不可靠的。包括网络抖动、错误等引起的丢包和粘包,如何正确处理也是rpc通信中很重要的一环。如果rpc请求失败,是丢弃还是直接重试,需要指定这些策略。性能如果rpc调用是同步的,性能会大大降低。如何实现rpc的异步调用,是rpc是否优秀的重要指标。rpc的网络传输再好,也会有性能损耗。是否可以缓存一些结果数据?不管是客户端还是服务端,处理请求的线程是否可以复用(线程池)?它可以支持多种语言吗?Socket简单,RPC难,更多精彩文章分布式大并发系列架构设计系列趣味算法与数据结构系列设计模式系列
