03.微服务治理

RPC

远程过程调用(RPC)是一种设计范例,它允许两个实体以通用的请求-响应机制通过通信通道进行通信。在过去的三十年中,RPC的定义发生了巨大的变化和发展,因此RPC范式是一个广泛的分类术语,它指的是过去四十年中出现的所有RPC式系统。RPC的定义已经发展了数十年。它已从简单的客户端-服务器设计过渡到一组互连的服务。尽管最初的RPC实现被设计为用于将计算外包给分布式系统中的服务器的工具,但RPC多年来已经发展为构建与语言无关的应用程序生态系统。RPC范例已成为创建真正革命性的分布式系统的驱动力的一部分,并已引起了不同系统之间的各种通信方案和协议。

RPC范例已用于实现我们的日常系统。从较低级别的应用程序,例如Network File SystemsRemote Direct Memory Access访问协议到开发微服务生态系统,RPC已经成为现实。到处使用。RPC具有多种应用程序-SunNFSTwitterFinagle,Apache Thrift,Java RMI,SOAP,CORBAGooglegRPC等。

RPC多年来发展了。RPC最初是作为一个同步,不安全的请求响应系统,后来演变成一个安全,异步,可恢复的范例,它已经影响了协议和编程设计,例如HTTP,REST,以及几乎所有带有请求响应系统的程序。它已过渡到异步,双向通信机制,用于通过Internet连接服务和设备。最初的RPC实现主要集中在本地专用网络上,其中多个客户端与服务器通信,并同步等待服务器的响应。现代的RPC系统具有端点彼此通信,异步传递参数和处理响应以及具有双向请求响应流(从客户端到服务器以及从服务器到客户端)的端点。RPC影响了各种设计范例和通信协议。

rpc是远端过程调用,其调用协议通常包含传输协议和序列化协议。

传输协议包含:如著名的[gRPC](grpc / grpc.io)使用的http2协议,也有如dubbo一类的自定义报文的tcp协议。

序列化协议包含:如基于文本编码的xml json,也有二进制编码的protobuf hessian等。

一般来说,RPC主要是解决两方面问题:

(1)分布式服务治理

(2)跨语言调用

总结上面几个模型,可以得出如下结论: (1)多处理机系统结构所需的额外开销,包括调度,对 共享资源的竞争、同步、处理机之间通信等。(2)当处理机台数增加时,额外开销时间也增加。有 时,额外开销的增加可能比处理机数目的线性增加更 快。(3)R/C比值越大,越有利于计算过程。如果采用粗粒 度,能够获得较大的R/C比值;但是并行程度将大为降 低。(4)为了使价格和性能都比较合理,处理机数目存在一 个极大值,这个值主要依赖于机器的系统结构、基本 技术(尤其是通信技术)和具体的应用问题。粒度与并行的关系并行性在很大程度上依赖于R/C比值,R/C是衡量任务粒度(Granularity)的尺度,其中:R:程序执行时间,C:通信开销细粒度并行:R/C小,通信开销大,并行度低。粗粒度并行:R/C大,通信开销小,并行性高。

传统上,多处理机专为 “ 并行计算机 ” 所设计,沿着这样的思路,当前Linux支持SMP奔腾系统,在该系统中多处理机共享单个计算机中的单个存储器和总线接口。每个运行Linux的机器组都有可能通过网络互相连接形成并行处理群。第三种选择是使用Linux系统作为 “ 主机 ”,提供专门的相关并行处理机(attached parallel processor )。第四种新选择是寄存器内SIMD并行,应用于多媒体扩展(MMX )。并 行处理(Parallel Processing )是计算机系统中能同时执行两个或更多个处理的一种计算方法。并行处理可同时工作于同一程序的不同方面。并行处理的主要目的是节省大 型和复杂问题的解决时间。为使用并行处理,首先需要对程序进行并行化处理,也就是说将工作各部分分配到不同处理进程(线程)中。并行处理由于存在相互关联 的问题,因此不能自动实现。另外,并行也不能保证加速。从理论上讲,在n个并行处理的执行速度可能会是在单一处理机上执行的速度的n倍。

API是应用程序编程接口(Application Programming Interface)的缩写。维基百科指出“总的来说,它是各种组件之间的一组明确定义的通信方法”。它可以是软件框架或库的接口,也可以是操作系统为原生系统软件(如POSIX)开发人员公开的底层接口。现如今,当人们谈论API时,他们通常指的是通过HTTP端点公开的远程接口。为了区分这些远程API和上面提到的本地系统API,我将用术语“Web API”指代远程API

严格来说,API仅用来描述接口,也就是客户端和服务器、API消费者和API提供者之间用于交换信息的语言。对于API消费者来说,API只不过是对接口和端点URLURL集的描述。URLWeb的基本构建块之一,客户端可以在不知道服务器性质或位置的情况下访问信息或服务。

我们通过底层设计范式(如查询、RPCRESTful)或协议(如SOAPgRPCGraphQL)进一步对远程API(或Web API)进行分类。除此之外,我们还通过目标受众来区分API,将它们分为公共、合作伙伴或私有/内部API;延伸阅读 Architecture Style CheatSheet

互联网上的机器大都通过TCP/IP协议相互访问,但TCP/IP只是往远端发送了一段二进制数据,为了建立服务还有很多问题需要抽象:

数据以什么格式传输?不同机器间,网络间可能是不同的字节序,直接传输内存数据显然是不合适的;随着业务变化,数据字段往往要增加或删减,怎么兼容前后不同版本的格式? 一个TCP连接可以被多个请求复用以减少开销么?多个请求可以同时发往一个TCP连接么? 如何管理和访问很多机器? 连接断开时应该干什么? 万一server不发送回复怎么办?

RPC可以解决这些问题,它把网络交互类比为“client访问server上的函数”:clientserver发送request后开始等待,直到server收到、处理、回复client后,client又再度恢复并根据response做出反应

我们来看看上面的一些问题是如何解决的:

数据需要序列化,protobuf在这方面做的不错。用户填写protobuf::Message类型的requestRPC结束后,从同为protobuf::Message类型的response中取出结果。protobuf有较好的前后兼容性,方便业务调整字段。http广泛使用json作为序列化方法。 用户无需关心连接如何建立,但可以选择不同的连接方式:短连接,连接池,单连接。 大量机器一般通过命名服务被发现,可基于DNS, ZooKeeper, etcd等实现。在百度内,我们使用BNS (Baidu Naming Service)brpc也提供"list://“和"file://"。用户可以指定负载均衡算法,让RPC每次选出一台机器发送请求,包括: round-robin, randomized, consistent-hashing(murmurhash3 or md5)locality-aware. 连接断开时可以重试。 如果server没有在给定时间内回复,client会返回超时错误。

既然是基于消息,那么跑不掉两种模式:Point-to-Point,Message Broker。P2P的模式大家都了解的,就是启动箭头端口,然后等其他应用连接上来,load balance等都是由SDK或者sidecar来搞定。Message Broker就不一样啦,你只需要将消息发送到broker,然后就不用管啦,这些路由等,都是由message broker搞定,完全透明。这篇文章我们主要讲基于Message Broker来做RPC通讯,也就是RSocket Broker负责完成所有的路由等功能。

基于消息的RPC通讯,这个消息的格式还有一点点不同,之前文章介绍过,我们这里再细化一下。RPC Message主要有三个部分:

消息元信息(message metadata):元信息主要提供一些基础信息,对于RPC消息来说,最主要的就是路由元信息(Routing metadata)和消息数据的格式(data encoding metadata)。路由是标明你要调用哪个服务,broker来帮你发送到指定的服务提供方。消息数据的格式,主要就是对象的序列化和反序列化,服务方可以获得真实的对象。 消息数据:要发送的数据,对于RPC来说,就是参数和返回结果。你调用一个服务时,需要提供调用的参数,服务逻辑执行完毕后,将结果再返回回来。数据通常有一定的编码格式,这个由data encoding metadata来控制,RSocket Broker目前主要支持三种: json, hessianprotobuf。 消息ID:消息是异步发送出去的,服务方逻辑执行完毕后,也是消息发送回来。RPC是要求知道结果的,所以返回的消息和发出去的消息是要匹配的,这样才能知道调用的结果。在RSocket中,这个ID你不需要自己设置,这个是SDK自动帮你匹配的,完全透明,我们只需要设置元信息和数据就可以。

RPC(Remote Procedure Call),远程过程调用,从最简单最抽象的模式来看,就是下面这个图这样。客户端调用某个方法,然后中间经过一系列的过程,调用到服务端的某个方法。服务端进行处理之后,做出相应,然后逐层原路返回到客户端。

640

一般来说,开发者只需要关注蓝色( functions )部分,而至于红色部分( stub句柄)和黄色部分(socket网络)部分呢,框架层面会把它解决掉。蓝色部分,服务端开发者要做的事情就是定义某个接口,客户端开发者要做的事情就是调用某个接口,一切开发模式都跟本地调用无差别。

Links