GRPC - 介绍与安装

A high performance, open source, general RPC(Remote procedure call) framework that puts mobile and HTTP/2 first. – gRPC Website

概述

gRPC 是由 Google 与 2015 年开源的一套主要面向移动应用开发的 RPC 框架。 相对于其他 RPC 框架而言,它有两个显著的特点:

简单来讲,RPC指的就是一个进程(client)发起一个函数调用,但是实际用来执行这个函数调用是另一个进程(server)。这个函数调用会阻塞在那里,直到收到响应。Server进程可以与client进程可以位于同一台机器也可以是不同机器。Client和server都有一个stub模块,client的stub负责发送request,并处理server返回的response;而server的stub则负责处理client发送的request,并返回response。 通常,我们使用Interface Description Language来定义RPC的消息格式。

特性

基于 HTTP/2 协议标准设计

  • 移动网络高延迟,低带宽,高丢包率的状态,使得我们需要进行大量的网络调优。而 HTTP/1.1 的一些特性使得它并不能很好的适应移动网络,一方面使用文本协议和无法复用 HTTP 头使得 HTTP/1.1 的流量消耗较大,另一方面 HTTP/1.1 的请求是有序堵塞的,使得 head-of-line blocking 问题十分严重,即使采用多连接和 pipelining 效果仍有限。但 HTTP/2 则可以用比较有效解决这些问题:采用二进制协议,完全多路复用,报头压缩,更能主动推送消息到客户端。

强大的 IDL 特性

  • 默认情况下,gRPC 使用 protobuf 作为 IDL(Interface Definition Language) 来定义服务(当然也可以使用 json 等):给定相应服务的 .proto 文件,gRPC 可以通过插件生成相应的客户端和服务器调用过程代码,使得客户端和服务器不再需要关心具体的请求装配,收发,解析过程,而更专注于相应的业务逻辑。

使用 gRPC 作为 RPC 框架的典型开发流程如下

  1. 后端定义服务,生成 .proto 文件
  2. 后端通过插件生成服务器接口代码,填充实现
  3. 客户端通过插件生成对应客户端代码,并调用
  • 多语言支持

    gRPC支持多种语言,并能够基于语言自动生成客户端和服务端功能库。目前已提供了C版本grpc、Java版本grpc-java 和 Go版本grpc-go,其它语言的版本正在积极开发中,其中,grpc支持C、C++、Node.js、Python、Ruby、Objective-C、PHP和C#等语言,grpc-java已经支持Android开发。

在gRPC客户端可以直接调用不同服务器上的远程程序,使用姿势看起来就像调用本地程序一样,很容易去构建分布式应用和服务。和很多RPC系统一样,服务端负责实现定义好的接口并处理客户端的请求,客户端根据接口描述直接调用需要的服务。客户端和服务端可以分别使用gRPC支持的不同语言实现。

grpc_concept_diagram

GRPC(GO) 环境

安装 gRPC runtime

1
go get -u -v google.golang.org/grpc

安装 protocol buffers 支持(包含 compilerruntime):从 protocol buffers 下载对应的二进制:

1
2
3
4
5
6
7
8
unzip protoc-3.3.0-osx-x86_64.zip
mv protoc-3.3.0-osx-x86_64 /software/protoc

#: 选择性写入到profile
export PATH="/software/protoc/bin:$PATH"

protoc --version
libprotoc 3.3.0

安装 Go protoc plugin

1
go get -u -v -a github.com/golang/protobuf/protoc-gen-go

编译器使用

使用 protoc 命令编译 .proto 文件,不同语言支持需要指定输出参数,如:

1
2
3
4
5
6
7
8
9
10
11
protoc \
--proto_path=IMPORT_PATH \
--cpp_out=DST_DIR \
--java_out=DST_DIR \
--python_out=DST_DIR \
--go_out=DST_DIR \
--ruby_out=DST_DIR \
--javanano_out=DST_DIR \
--objc_out=DST_DIR \
--csharp_out=DST_DIR \
path/to/file.proto

这里详细介绍golang的编译姿势:

-I 参数:
指定import路径,可以指定多个-I参数,编译时按顺序查找,不指定时默认查找当前目录

--go_out golang编译支持,支持以下参数:

  • plugins=plugin1+plugin2 - 指定插件,目前只支持grpc,即:plugins=grpc
  • M 参数 - 指定导入的.proto文件路径编译后对应的golang包名(不指定本参数默认就是.proto文件中import语句的路径)
  • import_prefix=xxx - 为所有import路径添加前缀,主要用于编译子目录内的多个proto文件,这个参数按理说很有用,尤其适用替代一些情况时的M参数,但是实际使用时有个蛋疼的问题导致并不能达到我们预想的效果,自己尝试看看吧
  • import_path=foo/bar - 用于指定未声明package或go_package的文件的包名,最右面的斜线前的字符会被忽略
  • 末尾 :编译文件路径 .proto文件路径(支持通配符)

完整示例:

1
protoc -I . --go_out=plugins=grpc,Mfoo/bar.proto=bar,import_prefix=foo/,import_path=foo/bar:. ./*.proto