RPC是什么
RPC(Remote Procedure Call) 释义是远程过程调用,常存在于分布式系统中。
比如说现在有两台服务器A, B,一个在A服务器上的应用想要调用B服务器上的应用提供的某个,由于不在两个方法不在一个内存空间,不能直接调用,需要通过网络表达调用的语义和传达调用的数据。
RPC要解决的问题
- 建立通信:在客户端与服务端建立起数据传输通道。著名的 gRPC 使用的 http2 协议,也有如dubbo一类的自定义报文的tcp协议。
- 寻址:A服务器上的应用需要告诉RPC框架,B服务器地址、端口,调用函数名称。所以必须实现待调用方法到远端ID的映射。
- 序列化与反序列化:由于网络协议都是二进制的,所以调用方法的参数在进行传递时首先要序列化成二进制,B服务器收到请求后要再对参数进行反序列化。
恢复为内存中的表达方式,找到对应的方法进行本地调用,得到返回值。返回值从B到A的传输仍要经过序列化与反序列化的过程。序列化协议如基于文本编码的Xml、Json,也有二进制编码的Protobuf、 Hessian等。
仅仅了解了RPC的相关文字概念,远远是不能理解RPC所带来的优势,RPC在作比较的时候,大多也是以HTTP作比较。不如先来了解一下HTTP,通过比较,我们加深对RPC的特性。
- HTTP 是建立在 TCP 协议之上,所以 HTTP 协议的瓶颈及其优化技巧都是基于 TCP 协议本身的特性,例如 tcp 建立连接的 3 次握手和断开连接的 4 次挥手以及每次建立连接带来的 RTT 延迟时间。
- HTTP 的基本优化:影响一个 HTTP 网络请求的因素主要有两个:带宽和延迟。
一个POST协议的格式大致如下:
1 HTTP/1.0 200 OK 2 Content-Type: text/plain 3 Content-Length: 137582 4 Expires: Thu, 05 Dec 1997 16:00:00 GMT 5 Last-Modified: Wed, 5 August 1996 15:55:28 GMT 6 Server: Apache 0.84 7 8 <html> 9 <body>Hello World</body> 10 </html>
通过简单的了解到Http的一些特性外,我们能够看到http1.1协议的tcp报文包含太多废信息,简化协议内容,减少不必要的传输内容成为了关键。
gRPC
gRPC是谷歌开源的一个 RPC 框架,面向移动和 HTTP/2 设计。
内容交换格式采用ProtoBuf(Google Protocol Buffers),开源已久,提供了一种灵活、高效、自动序列化结构数据的机制,作用与XML,Json类似,但使用二进制,(反)序列化速度快,压缩效率高。
传输协议 采用http2,性能比http1.1好了很多。
和很多RPC系统一样,服务端负责实现定义好的接口并处理客户端的请求,客户端根据接口描述直接调用需要的服务。客户端和服务端可以分别使用gPRC支持的不同语言实现。
ProtoBuf 具有强大的IDL(interface description language,接口描述语言)和相关工具集(主要是protoc)。用户写好.proto描述文件后,protoc可以将其编译成众多语言的接口代码。
为什么要使用自定义 tcp 协议的 rpc 做后端进程通信?
即使编码协议也就是body是使用二进制编码协议,报文元数据也就是header头的键值对却用了文本编码,非常占字节数。如代码所使用的报文中有效字节数仅仅占约 30%,也就是70%的时间用于传输元数据废编码。当然实际情况下报文内容可能会比这个长,但是报头所占的比例也是非常可观的。
简单来说成熟的RPC库相对Http容器,更多的是封装了“服务发现”,"负载均衡",“熔断降级”一类面向服务的高级特性。可以这么理解,RPC框架是面向服务的更高级的封装。如果把一个Http Servlet容器上封装一层服务发现和函数代理调用,那它就已经可以做一个RPC框架了。
Dotnet gRPC Demo
创建gprc项目,并配置proto
1 dotnet new grpc -o GrpcGreeter 2 3 - greet.proto 4 5 syntax = "proto3"; 6 7 option csharp_namespace = "GrpcGreeter"; 8 9 package Greet; 10 11 // The greeting service definition. 12 service Greeter { 13 // Sends a greeting 14 rpc SayHello (HelloRequest) returns (HelloReply); 15 } 16 17 // The request message containing the user's name. 18 message HelloRequest { 19 string name = 1; 20 } 21 22 // The response message containing the greetings. 23 message HelloReply { 24 string message = 1; 25 } 26 27 - Start.cs 28 public void ConfigureServices(IServiceCollection services){ 29 services.AddGrpc(); 30 } 31 32 public void Configure(IApplicationBuilder app, IWebHostEnvironment env){ 33 app.UseEndpoints(endpoints =>{ 34 endpoints.MapGrpcService<GreeterService>(); 35 endpoints.MapGet("/", async context => { 36 await context.Response.WriteAsync("Communication with gRPC endpoints"); 37 }); 38 }); 39 }