gRPC实战指南:高性能微服务通信框架
📌 简介
gRPC是RPC框架的一种,由Google开发。gRPC是一个高性能、开源和通用的RPC框架,基于Protobuf序列化协议开发,基于HTTP/2设计,带来诸如双向流、流控、头部压缩、单TCP连接上的多复用请求等特性。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。
RPC是什么
RPC(Remote Procedure Call)框架说白了就是让你可以像调用本地方法一样调用远程服务提供的方法,而不需要关心底层的通信细节。简单地说就是让远程服务调用更加简单、透明。RPC包含了客户端(Client)和服务端(Server)。
业界主流的RPC框架整体上分为三类:
| 类型 | 代表框架 | 特点 |
|---|---|---|
| 支持多语言的RPC框架 | Google的gRPC、Apache的Thrift | 跨语言,成熟稳定 |
| 只支持特定语言的RPC框架 | 新浪微博的Motan | 针对性强,性能优化 |
| 支持服务治理的分布式服务框架 | 阿里的Dubbo | 底层仍是RPC框架 |
🔧 原理
在gRPC里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得您能够更容易地创建分布式应用和服务。与许多RPC系统类似,gRPC也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个gRPC服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。
大致请求流程
1. 客户端(gRPC Stub)调用 A 方法,发起 RPC 调用
2. 对请求信息使用 Protobuf 进行对象序列化压缩(IDL)
3. 服务端(gRPC Server)接收到请求后,解码请求体,进行业务逻辑处理并返回
4. 对响应结果使用 Protobuf 进行对象序列化压缩(IDL)
5. 客户端接受到服务端响应,解码请求体。回调被调用的 A 方法,唤醒正在等待响应(阻塞)的客户端调用并返回响应结果
⚡ gRPC的特性
跨语言支持
gRPC可以跨语言使用,支持多种编程语言:
- C++、Java、Go、Python、Ruby
- C#、Node.js、Android Java
- Objective-C、PHP等
基于IDL定义服务
基于IDL(接口定义语言,Interface Define Language)文件定义服务,通过proto3工具生成指定语言的数据结构、服务端接口以及客户端Stub。
HTTP/2特性
通信协议基于标准的HTTP/2设计,支持:
- 双向流
- 消息头压缩
- 单TCP的多路复用
- 服务端推送
这些特性使得gRPC在移动端设备上更加省电和节省网络流量。
高性能序列化
序列化支持PB(Protocol Buffer)和JSON,PB是一种语言无关的高性能序列化框架,基于HTTP/2 + PB,保障了RPC调用的高性能。
易于扩展
安装简单,扩展方便,用该框架每秒可达到百万个RPC。
🚀 gRPC使用流程
- 定义标准的proto文件(后面部分会详细讲解protobuf的使用)
- 生成标准代码
- 服务端使用生成的代码提供服务
- 客户端使用生成的代码调用服务
💪 优势
性能优势
gRPC消息使用Protobuf进行序列化,序列化速度快、消息体积小。
代码生成
所有gRPC框架都为代码生成提供了一流的支持。gRPC开发的核心文件是*.proto文件,它定义了gRPC服务和消息的约定。根据这个文件,gRPC框架将生成服务基类、消息和完整的客户端代码。
通过在服务器和客户端之间共享*.proto文件,可以从端到端生成消息和客户端代码。客户端的代码生成消除了客户端和服务器上的重复消息,并为您创建了一个强类型的客户端。无需编写客户端代码,可在具有许多服务的应用程序中节省大量开发时间。
严格的规范
不存在具有JSON的HTTP API的正式规范。开发人员不需要讨论URL、HTTP动词和响应代码的最佳格式。(想想,是用Post还是Get好?使用Get还是用Put好?一想到有选择恐惧症的你是不是又开了纠结,然后浪费了大量的时间)
该gRPC规范是规定有关gRPC服务必须遵循的格式。gRPC消除了争论并节省了开发人员的时间,因为gRPC在各个平台和实现之间是一致的。
流式传输
HTTP/2为长期的实时通信流提供了基础。gRPC通过HTTP/2为流媒体提供一流的支持。
gRPC服务支持所有流组合:
| 模式 | 说明 | 应用场景 |
|---|---|---|
| 一元(简单RPC) | 一个请求对象对应一个返回对象,客户端发起一次请求,服务端响应一个数据 | 标准RPC通信 |
| 客户端流式RPC | 客户端传入多个请求对象,服务端返回一个响应结果 | 物联网终端向服务器报送数据 |
| 服务端流式RPC | 一个请求对象,服务端可以传回多个结果对象 | 股票实时数据推送 |
| 双向流式RPC | 结合客户端流式RPC和服务端流式RPC,可以传入多个对象,返回多个响应对象 | 聊天应用 |
截止时间/超时和取消
gRPC允许客户端指定他们愿意等待RPC完成的时间。该期限被发送到服务端,服务端可以决定在超出了限期时采取什么行动。例如,服务器可能会在超时时取消正在进行的gRPC / HTTP /数据库请求。
通过子gRPC调用截止时间和取消操作有助于实施资源使用限制。
⚠️ 劣势
- 浏览器支持有限 - 浏览器不完全支持gRPC
- 不是人类可读的 - Protobuf是二进制格式,不像JSON那样可读
🎯 使用场景
适合场景
gRPC非常适合以下场景:
| 场景 | 说明 |
|---|---|
| 微服务 | gRPC设计为低延迟和高吞吐量通信。gRPC非常适用于效率至关重要的轻型微服务 |
| 点对点实时通信 | gRPC对双向流媒体提供出色的支持。gRPC服务可以实时推送消息而无需轮询 |
| 多语言混合开发环境 | gRPC工具支持所有流行的开发语言,使gRPC成为多语言开发环境的理想选择 |
| 网络受限环境 | 使用Protobuf(一种轻量级消息格式)序列化gRPC消息。gRPC消息始终小于等效的JSON消息 |
不建议使用场景
在以下场景中,建议使用其他框架而不是gRPC:
| 场景 | 替代方案 |
|---|---|
| 浏览器可访问的API | gRPC-Web可以提供浏览器支持,但它有局限性并引入了服务器代理 |
| 广播实时通信 | SignalR具有持久连接的概念和对广播消息的内置支持 |
| 进程间通信 | 对于Windows,进程间通信管道是一种快速,轻量级的通信方法 |
📦 Protobuf
对于每个message,都会生成一个对应的消息类。在消息类中,编译器为每个字段提供了获取和设置方法,以及一些其他能够操作字段的方法。编辑器会针对于每个.proto文件生成.h和.cc文件,分别用来存放类的声明与类的实现。
📚 参考资料
- 示例代码 :zhangjixiang2018/grpc_test - 码云
- 官网 :C++ | gRPC
- 基础知识 :gRPC详解
- C++示例 :gRPC C++示例
- Protobuf用法 :protobuf用法(C++)
- Protobuf官网 :Protocol Buffers Documentation
💡 总结
gRPC是一个高性能的RPC框架,适合微服务、实时通信和多语言混合开发场景。其基于HTTP/2和Protobuf的设计使其具有低延迟、高吞吐量的特点。在选择是否使用gRPC时,需要考虑浏览器支持、广播通信等场景的限制。