什么是 gRPC?
**gRPC(Google Remote Procedure Call)**是 Google 开源的一个高性能、通用的远程过程调用框架。
通俗来说,它让不同机器、不同语言写的程序之间可以“像调用本地函数一样”,快速、安全地相互调用代码。
为什么需要 gRPC?
在现代分布式系统中,不同服务往往部署在不同的服务器上,服务之间需要互相交流。传统的通信方式有:
HTTP REST API(基于文本的 JSON)
自定义的 TCP 协议、消息队列等
但是它们要么效率不高,要么实现复杂,特别是在服务规模变大时,维护和性能可能成为问题。
gRPC 诞生用于解决这些问题:
高性能:采用二进制传输协议(Protocol Buffers),比文本协议更省带宽、解析更快。
简单接口定义:用 *.proto
文件定义接口和消息,自动生成代码,减少手写重复工作。
多语言支持:支持 C++、Java、Python、Go、Node.js 等多达十几种语言。
多种通信模式:支持单向、请求响应、流式传输(单向或双向流)。
内置安全机制:支持 TLS 加密和认证。
核心组成
Protocol Buffers(Protobuf)
一种高效的序列化机制,把结构化数据快速编码成紧凑的二进制格式。
gRPC 使用 Protobuf 来描述请求和响应的数据结构和接口。
你首先写 .proto
文件定义消息格式和服务接口,然后通过工具自动生成对应语言的客户端和服务端代码。
服务端(Server)
运行在服务器上,真正实现接口逻辑(例如用户登录、数据查询)。
监听指定端口,接受客户端调用请求,返回结果。
客户端(Client)
客户端代码调用远程服务就像调用本地函数一样,隐藏底层网络细节。
负责和服务器建立连接,发送请求,获取返回。
一个简单的流程举例
你用 .proto
文件定义接口和消息:
//Protocol Buffers(简称 Protobuf)定义的 gRPC 接口和消息格式
//1. 这段代码的作用是什么?
//它是 gRPC 服务的接口定义和数据结构描述。简单来说:
//定义了一个叫 Greeter 的服务。(我们可以把服务理解为一组远程调用的接口)
//这个服务有一个方法(RPC)叫 SayHello。
//SayHello 接口接收一个 HelloRequest 消息作为输入,并返回一个 HelloReply 消息作为输出。
//这个 .proto 文件就是告诉 gRPC 框架:
//我们提供一个叫 Greeter 的远程服务,它有一个“说你好”的方法,你给我一个名字,我给你一个问候语。
//proto3 是当前推荐和主流版本,拥有更简洁、易用的语法,同时支持更多功能。
syntax = "proto3";
具体来说:
rpc 是 remote procedure call(远程过程调用)的关键字,声明一个远程方法。
SayHello 是方法名,决定客户端调用的接口名字。
(HelloRequest) 是输入参数类型,意思是客户端调用这个接口时,必须发送一个 HelloRequest 类型的消息。
returns (HelloReply) 是输出参数类型,表示服务端调用这个方法后,返回给客户端一个 HelloReply 类型的消息。
{} 当前没有额外的配置信息,只是空着。
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
这里定义了一个数据消息(Message)类型叫 HelloRequest。
message 就像是你在程序里定义的一个类或者结构体,表示一类数据。
string name = 1; 表示这个消息里有一条数据,叫 name,类型是字符串(string)。
= 1 是一个字段编号,用于二进制压缩编码,不用管它具体数字,但编号唯一且不可随意改变(影响版本兼容)。
message HelloRequest {
string name = 1;
}
这是另一个消息类型,名字叫 HelloReply。
代表服务端对客户端的回复内容。
里面只有一个 string 类型字段,名字是 message,用来放问候语。
换句话说,HelloReply 就是服务端返回给你的“你好,张三!”这类文本。
message HelloReply {
string message = 1;
}
简单描述一次调用过程:
客户端构造一个 HelloRequest,把 name 字段填成“张三”。
调用 Greeter 服务的 SayHello RPC 接口,发送请求。
服务器收到请求,获取 HelloRequest 里的名字“张三”,生成对应问候,比如“Hello, 张三!”。
服务器把这个文本放入 HelloReply 的 message 字段,返回给客户端。
客户端接收响应,得到问候语。
这样,客户端和服务端就通过定义好的接口和消息完成了一次远程调用。
4. 为什么要用这种方式?
规范明确:所有请求和响应的数据结构都写在 .proto 文件里,统一标准,方便多人开发。
自动生成代码:你只写一次 .proto,gRPC 提供工具可以自动帮你生成各种语言(Python、Java、Go…)的数据结构和接口调用代码,省力省时。
高效传输:数据用二进制格式编码,比普通的 JSON 文本更紧凑传输快。
跨语言无障碍通信:不管客户写的是 Java,服务端是 Go,接口格式都是一样的,互相调用没障碍。
5. 总结
syntax = "proto3"; 告诉用 proto3 语法定义。
service Greeter { ... } 申明一个叫 Greeter 的远程服务。
rpc SayHello (HelloRequest) returns (HelloReply) {} 表示服务有一个名叫 SayHello 的方法,接收一个 HelloRequest,返回一个 HelloReply。
message HelloRequest { string name = 1; } 定义了请求数据结构,只有一个字段 name。
message HelloReply { string message = 1; } 定义了响应数据结构,只有一个字段 message。
这就是一个最简单的 gRPC 接口例子,实现了“客户端传名字,服务端回应问候”的功能。
通过 gRPC 工具生成服务端和客户端代码。
服务端实现 SayHello
方法,接收请求以字符串 name
,返回问候消息。
客户端调用 SayHello
,传入名字,获得返回问候。
gRPC 的通信模式
gRPC 支持多种调用方式:
简单 RPC(Unary RPC):客户端发送一次请求,服务端返回一次响应。类似普通函数调用。
服务器流式 RPC(Server streaming):客户端发送一次请求,服务端返回持续的一系列响应。比如视频分段。
客户端流式 RPC(Client streaming):客户端发送多个请求,服务端返回一个响应。比如上传大文件。
双向流式 RPC(Bidirectional streaming):客户端和服务端各自发送多个消息,彼此独立,不必同步。类似实时聊天。
gRPC 的优势和特点
高性能:Protobuf 的二进制格式比 JSON 更加紧凑且解析快,网络带宽和CPU消耗更低。
接口明确:所有接口及数据格式定义清晰写在 .proto
文件里,便于文档和自动生成代码。
多语言支持:使用同一份 .proto
文件,可以生成不同语言客户端和服务器。
内建支持 HTTP/2:带来多路复用、头压缩、双向流、服务端推送等现代网络特性,效率高。
方便扩展:支持插件机制,也有丰富的生态系统,比如支持服务发现、负载均衡等。
内置安全:支持 TLS 加密,和基于认证的访问控制。
适用场景举例
大型微服务架构,服务间通信
跨语言 RPC 调用,比如C++后端和Python前端通信
需要高性能、低延迟的场景(游戏服务器、金融系统)
流媒体传输、实时数据处理
移动端和服务器端效率传输
总结一下
优缺点 | 描述 |
---|---|
优点 | 高性能、强类型接口定义、多语言支持、支持多种通信模式、安全 |
缺点 | 学习曲线比 REST 略陡,需要 protobuf 编译工具,调试相对复杂一些 |
暂无评论内容