gRPC

目录

[TOC]

前言

gRPC是由Google主导开发的RPC框架, 使用HTTP/2协议并用ProtoBuf作为序列化工具.
gRPC里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得用户能够更容易地创建分布式应用和服务. grpc官网

RPC

什么是RPC?

RPC: Remote Procedure Call远程过程调用.它是一种通过网络从远程计算机程序上请求服务, 而不需要了解底层网络技术的协议.简单的理解就是:从一台机器(客户端)上通过参数传递的方式调用另一台机器(服务器)上的一个函数或方法(可以统称为服务)并得到返回的结果
有如下特点:

1
2
3
1. RPC 会隐藏底层的通讯细节(不需要直接处理Socket通讯或Http通讯)
2. RPC 是一个请求响应模型。客户端发起请求,服务器返回响应(类似于Http的工作方式)
3. RPC 在使用形式上像调用本地函数(或方法)一样去调用远程的函数(或方法)。

下面这张图展示了RPC的原理:

RPC的发展路程

1
2
3
4
5
6
7
8
9
10
1. ONC RPC (开放网络计算的远程过程调用),OSF RPC(开放软件基金会的远程过程调用)
2. CORBA(Common Object Request Broker Architecture公共对象请求代理体系结构)
3. DCOM(分布式组件对象模型),COM+
4. Java RMI (remote method invocation远程方法调用)
5. .NET Remoting
6. XML-RPC,SOAP,Web Service
7. PHPRPC,Hessian,JSON-RPC
8. Microsoft WCF,WebAPI
9. ZeroC Ice,Thrift,GRPC
10. Hprose

我们现在用的非常广泛的restful web service也可以理解为RPC的实现

thrift

thrift是一个RPC的实现, thrift最初由facebook研发, 现已成为apache下面的开源项目.

IDL

thrift有自己的一套接口定义语言: IDL(Thrift interface description language), 这里就忽略IDL的语法

helloword

我们拿javapython进行测试, 现在有两个程序分别由javapython编写, 现模拟它们之间的通信

1
2
3
4
5
namespace java com.test

service HelloWorldService {
string sayHello(1:string username)
}

请观看详细演示

thrift的优点

1
2
3
4
1. 支持的语言广泛
2. 支持协议更多
3. 特性丰富, 支持的类型更多
4. 很多开源项目都支持thrift

thrift的缺点

1
2
3
4
1. 基本没有官方文档
2. bug fix 不积极
3. 现在最新的thrift版本还停留在v0.9.3,
4. 数据结构不能必须事先定义,中途不能改变,若数据结构发生变化,必须重新定义,编译

gRPC

gRPC客户端和服务端可以在多种环境中运行和交互 - 从google内部的服务器到你自己的笔记本,并且可以用任何 RPC持的语言来编写。所以,你可以很容易地用Java创建一个gRPC 服务端,用Go、Python、Ruby来创建客户端. 可以在github上找到各种语言的实现grpc

protocal buffers

gRPC默认使用protocal buffers, 这是google开源的一套成熟的结构数据序列化机制.

1
2
3
4
1. 定义一种message的格式(.proto文件)
2. 使用编译器对message进行编译, 转化为对应语言的代码(转化为一个类)
3. 提供对应语言的API来操作这些message
4. 对旧的数据格式进行兼容

Powerful IDL

Define your service using Protocol Buffers, a powerful binary serialization toolset and language.
示例: PersonMsg.proto文件

1
2
3
4
5
6
7
8
9
10
11
12
13
message Person {
// ID(必需)
required int32 id = 1;

// 姓名(必需)
required string name = 2;

// email(可选)
optional string email = 3;

// 朋友(集合)
repeated string friends = 4;
}

上面的1、2、3、4是unique numbered tag,是一个唯一标识

编译成java文件

有了.proto文件, 接下来生成类(java代码)

1
c:\protoc.exe --java_out=E:\god\ProtocTest PersonMsg.proto

生成了一个PersonMsg.java

使用API

编写代码对message进行序列化和反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;

public class Test {
public static void main(String[] args) throws IOException {

// 按照定义的数据结构,创建一个Person
PersonMsg.Person.Builder personBuilder = PersonMsg.Person.newBuilder();
personBuilder.setId(1);
personBuilder.setName("马强");
personBuilder.setEmail("xxg@wahley.com");
personBuilder.addFriends("Friend A");
personBuilder.addFriends("Friend B");
PersonMsg.Person xxg = personBuilder.build();

// 将数据写到输出流,如网络输出流,这里就用ByteArrayOutputStream来代替
ByteArrayOutputStream output = new ByteArrayOutputStream();
xxg.writeTo(output);

// -------------- 分割线:上面是发送方,将数据序列化后发送 ---------------

byte[] byteArray = output.toByteArray();

// -------------- 分割线:下面是接收方,将数据接收后反序列化 ---------------

// 接收到流并读取,如网络输入流,这里用ByteArrayInputStream来代替
ByteArrayInputStream input = new ByteArrayInputStream(byteArray);

// 反序列化
PersonMsg.Person xxg2 = PersonMsg.Person.parseFrom(input);
System.out.println("ID:" + xxg2.getId());
System.out.println("name:" + xxg2.getName());
System.out.println("email:" + xxg2.getEmail());
System.out.println("friend:");
List<String> friends = xxg2.getFriendsList();
for (String friend : friends) {
System.out.println(friend);
}
}

}

HTTP/2

Building on the HTTP/2 standard brings many capabilities such as bidirectional streaming, flow control, header compression, multiplexing requests over a single TCP connection and more.
These features save battery life and data usage on mobile devices while speeding up services and web applications running in the cloud.

gRPC是基于HTTP/2标准设计, 带来了诸如双向流,流控,头部压缩, 单TCP连接上的多路复用等等, 这些特性使得它在移动设备上表现更好, 更省电和节省空间占用(节省带宽、降低TCP链接次数、节省CPU使用和延长电池寿命)

使用gRPC

想使用gRPC, 可以在github上搜索grpc, 比如java版本的grpc-java

gRPC和thrift比较


该选择gRPC还是thrift?

什么时候选择gRPC?

1
2
3
1. 需要良好的文档、示例
2. 喜欢、习惯HTTP/2、ProtoBuf
3. 对网络传输带宽敏感

什么时候选择thrift?

1
2
3
4
1. 需要在非常多的语言间进行数据交换 (支持语言更多)
2. 协议层、传输层有多种控制要求 (支持的协议更多)
3. 需要稳定的版本
4. 不需要良好的文档和示例

etcd3中的gRPC

最新发布的etcd3中使用了的gRPC

Native etcd3 clients communicate over a gRPC protocol. The protocol messages are defined using protobuf, which simplifies the generation of efficient RPC stub code and makes protocol extensions easier to manage. For comparison, even after optimizing etcd2’s client-side JSON parsing, etcd3 gRPC still holds a 2x message processing performance edge over etcd2. Likewise, gRPC is better at handling connections. Where gRPC uses HTTP2 to multiplex multiple streams of RPCs over a single TCP connection, a JSON client must establish a new connection for every request.

下面是centos中官网的对使用gRPC的介绍
grpc中关于使用rest的介绍
CoreOS中关于grpc的介绍

参考

Take a REST with HTTP/2, Protobufs, and Swagger
gRPC with REST and Open APIs
etcd3: A new etcd
谁能用通俗的语言解释一下什么是RPC框架?
什么是 RESTful ?到底 REST 和 SOAP、RPC 有何区别?
thrift入门教程
Protocol Buffer 基础教程: Java
gRPC vs Thrift
Java使用Protocol Buffers入门四步骤
gRPC 官方文档中文版