gRPC(一)
创始人
2025-06-01 12:58:03
0

一、RPC基本概念

RPC:远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的思想。

常见 RPC 技术和框架有:应用级的服务框架:阿里的 Dubbo/Dubbox、Google gRPC、Spring Boot/Spring Cloud、Facebook 的 Thrift、Twitter 的 Finagle 等。

  • 远程通信协议:RMI、Socket、SOAP(HTTP XML)、REST(HTTP JSON)。
  • 通信框架:MINA 和 Netty。

Google gRPC 框架是基于 HTTP2 协议实现的,底层使用到了 Netty 框架的支持。

1.RPC 框架

一个典型 RPC 的使用场景中,包含了服务发现、负载、容错、网络传输、序列化等组件,其中“RPC 协议”就指明了程序如何进行网络传输和序列化
在这里插入图片描述

2. RPC 核心功能

RPC 的核心功能是指实现一个 RPC 最重要的功能模块,就是上图中的”RPC 协议”部分:
在这里插入图片描述
一个 RPC 的核心功能主要有 5 个部分组成,分别是:客户端、客户端 Stub、网络传输模块、服务端 Stub、服务端等。
在这里插入图片描述
重要组成:

  1. 客户端:服务调用方。
  2. 客户端存根:存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端。
  3. 服务端存根:接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理。
  4. 服务端:服务的真正提供者。
  5. Network Service:底层传输,可以是 TCP 或 HTTP。

一次 RPC 调用流程如下:

  1. 服务消费者通过本地调用的方式调用服务。
  2. 客户端存根接收到调用请求后负责将方法、入参等信息序列化成能够进行网络传输的消息体,找到远程的服务地址,并且将消息通过网络发送给服务端
  3. 服务端存根收到消息后进行解码(反序列化操作)。
  4. 服务端存根根据解码结果调用本地的服务进行相关处理
  5. 服务端本地服务业务处理,处理结果返回。
  6. 服务端存根序列化结果,将结果通过网络发送至消费方。
  7. 客户端存根接收到消息,并进行解码(反序列化)。
  8. 服务消费者得到最终结果。

RPC的目标就是要2~7这些步骤都封装起来,让用户对这些细节透明。

二 .gRPC简介

官网:https://www.grpc.io/
gRPC 官方文档中文版:http://doc.oschina.net/grpc

RPC目标:让远程服务调用更加简单、透明,其负责屏蔽底层的传输方式(TCP/UDP)、序列化方式(XML/Json)和通信细节。服务调用者可以像调用本地接口一样调用远程的服务提供者,而不需要关心底层通信细节和调用过程。

gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHPC# 支持.

gRPC 也是基于以下理念:

  1. 定义一个服务,指定其能够被远程调用的方法。
  2. 在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。
  3. 在客户端拥有一个存根能够像服务端一样的方法。
    在这里插入图片描述

gRPC 的功能优点:

  • 高兼容性、高性能、使用简单。

gRPC 的组成部分:

  • 使用 http2 作为网络传输层
  • 使用 protobuf 这个高性能的数据包序列化协议
  • 通过 protoc gprc插件生成易用的 SDK

三、使用 protobuf序列化协议

1.什么是ProtoBuf

ProtoBuf是一种跨平台、语言无关、可扩展的序列化结构数据的方法,可用于网络数据交换及存储。
在序列化结构化数据的机制中,ProtoBuf是灵活、高效、自动化的,相对常见的XML、JSON,描述同样的信息,ProtoBuf序列化后数据量更小(在网络中传输消耗的网络流量更少)、序列化/反序列化速度更快、更简单。
一旦定义了要处理的数据的数据结构之后,就可以利用ProtoBuf的代码生成工具生成相关的代码。只需使用 Protobuf 对数据结构进行一次描述,即可利用各种不同语言对你的结构化数据轻松读写。

2.如何使用 ProtoBuf

2.1 ProtoBuf 协议的工作流程

  1. 先要定义服务接口,其中应包含如下信息:消费者消费服务的方式、消费者能够远程调用的方法以及调用这些方法所使用的参数和消息格式等。在服务定义中所使用的语言叫作接口定义语言(IDL)。
  2. 借助服务定义,可以生成服务器端代码,同时,还可以生成客户端代码,也就是客户端存根。就像调用本地函数那样,客户端能够远程调用我们在服务接口定义中所指定的方法。底层的 gRPC 框架处理所有的复杂工作,通常包括确保严格的服务契约、数据序列化、网络通信、认证、访问控制等。
    在这里插入图片描述
    服务定义是在 ProductInfo.proto 文件中声明的,服务器端和客户端都会使用该文件来生成代码。这里假设 ProductInfo 服务使用 Go 语言来实现,消费者使用 Java 语言来实现,两者之间的通信则通过 HTTP/2 来进行。
  • IDL文件:相当于约定。这个约定需要采用与具体开发语言、平台无关的语言来进行描述。这种语言被称为接口描述语言;
  • IDL Compiler:IDL文件中约定的内容为了在各语言和平台可见,需要有一个编译器,将IDL文件转换成各语言对应的动态库。
  • Stub/Skeleton Lib:负责序列化和反序列化的工作代码。(客户端端存根)Stub,一方面接收应用层的参数,并对其序列化后通过底层协议栈发送到服务端,另一方面接收服务端序列化后的结果数据,反序列化后交给客户端应用层;(服务端存根)Skeleton,其功能与Stub相反,从传输层接收序列化参数,反序列化后交给服务端应用层,并将应用层的执行结果序列化后最终传送给客户端Stub;
  • Client/Server:指的是应用层程序代码,他们面对的是IDL所生存的特定语言的class或struct;
  • 底层协议栈和互联网:序列化之后的数据通过底层的传输层、网络层、链路层以及物理层协议转换成数字信号在互联网中传递。

2.2. ProtoBuf 消息定义

// Java类
public class Person
{private String name;private Int id;private String email;
...
}

proto3协议

syntax = "proto3"; // 协议版本  必须写:syntax = "proto3";package protocobuff_Demo; // 关注1:包名,防止不同 .proto 项目间命名 发生冲突option java_package = "com.chenj.protobuf"; 作用:指定生成的类应该放在什么Java包名下
option java_outer_classname = "Demo";//作用:生成对应.java 文件的类名(不能跟下面message的类名相同)
// 关注2:option选项,作用:影响 特定环境下 的处理方式// 关注3:消息模型 作用:真正用于描述 数据结构
// 下面详细说明
// 生成 Person 消息对象(包含多个字段,下面详细说明)
message Person {string name = 1;//(proto3消息定义时,移除了 “required”、 “optional” :)int32 id = 2;//(proto3消息定义时,移除了 “required”、 “optional” :)string email = 3;//(proto3消息定义时,移除了 “required”、 “optional” :)enum PhoneType {MOBILE = 0;HOME = 1;WORK = 2;}message PhoneNumber {string number = 1;PhoneType type = 2 ;//(proto3消息定义时,移除了 default 选项:)}repeated PhoneNumber phone = 4;
}message AddressBook {repeated Person person = 1;
}
  1. 消息对象
    在 ProtocolBuffers 中:
  • 一个消息对象(Message) = 一个 结构化数据
  • 消息对象用 修饰符 message 修饰
  • 消息对象 含有 字段:消息对象(Message)里的 字段 = 结构化数据 里的成员变量

在这里插入图片描述

  1. 字段
    消息对象的字段 组成主要是:字段 = 字段修饰符 + 字段类型 +字段名 +标识号
    在这里插入图片描述
    字段修饰符
    作用:设置该字段解析时的规则

字段类型
字段类型主要有 三 类:

  • 基本数据 类型
  • 枚举 类型
  • 消息对象 类型

枚举类型
作用:为字段指定一个 可能取值的字段集合,该字段只能从 该指定的字段集合里 取值
下面例子,电话号码 可能是手机号、家庭电话号或工作电话号的其中一个,那么就将PhoneType定义为枚举类型,并将加入电话的集合( MOBILE、 HOME、WORK

// 枚举类型需要先定义才能进行使用// 枚举类型 定义enum PhoneType {MOBILE = 0;HOME = 1;WORK = 2;
// 电话类型字段 只能从 这个集合里 取值}// 特别注意:
// 1. 枚举类型的定义可在一个消息对象的内部或外部
// 2. 都可以在 同一.proto文件 中的任何消息对象里使用
// 3. 当枚举类型是在一消息内部定义,希望在 另一个消息中 使用时,需要采用MessageType.EnumType的语法格式message PhoneNumber {required string number = 1;optional PhoneType type = 2 [default = HOME];// 使用枚举类型的字段(设置了默认值)}

2.3 生成代码

首先安装 ProtoBuf 编译器 protoc,这里有详细的安装教程,安装完成后,可以使用以下命令生成 Java 源代码:

protoc --java_out=./src/main/java ./src/main/idl/customer.proto。

2.4序列化原理解析

在这里插入图片描述
Protocol Buffer将 消息里的每个字段 进行编码后,再利用T - L - V 存储方式 进行数据的存储,最终得到的是一个 二进制字节流T - L - V 的数据存储方式即 Tag - Length - Value标识 - 长度 - 字段值 存储方式;以 标识 - 长度 - 字段值 表示单个数据,最终将所有数据拼接成一个 字节流,从而 实现 数据存储 的功能, Length可选存储,如 储存Varint编码数据就不需要存储Length

优点从上图可知,T - L - V存储方式的优点是

  • 不需要分隔符就能分隔开字段,减少了分隔符的使用;
  • 各字段存储得非常紧凑,存储空间利用率非常高;
  • 若字段没有被设置字段值,那么该字段在序列化时的数据中是完全不存在的,即不需要编码;

因为 Protocol Buffer对于数据字段值的 独特编码方式 & T - L - V数据存储方式,使得 Protocol Buffer序列化后数据量体积如此小。

2.5 总结

Protocol Buffer的序列化 & 反序列化简单 & 速度快的原因是:

  • 编码 / 解码 方式简单(只需要简单的数学运算 = 位移等等);
  • 采用 Protocol Buffer 自身的框架代码 和 编译器 共同完成;

Protocol Buffer的数据压缩效果好(即序列化后的数据量体积小)的原因是:

  • 采用了独特的编码方式,如Varint、Zigzag编码方式等等;
  • 采用T - L - V 的数据存储方式:减少了分隔符的使用 & 数据存储得紧凑;

相关内容

热门资讯

关税政策推进受阻,特朗普政府求... 6月2日,美国特朗普政府请求联邦上诉法院阻止此前哥伦比亚特区联邦地区法院裁定其关税政策“违法”的命令...
关税政策推进受阻 特朗普政府求... 当地时间6月2日,美国特朗普政府请求联邦上诉法院阻止此前哥伦比亚特区联邦地区法院裁定其关税政策“违法...
英国央行Catherine M... 英国央行Catherine Mann:必须考虑量化紧缩(QT)和一系列利率政策的影响。
原创 香... 在新加坡香格里拉酒店举行的亚太安全论坛上,美国国防部长赫格塞思(Lloyd Austin)于5月31...
美方掐断C919发动机技术,中... 在国际舞台上,当两大经济体相遇,总会引发一场关于技术、资本和市场的角力。最近,中美之间的博弈又一次走...
6800万镑!埃泽“豪言”震惊... 足坛风云变幻,总有那么些球员,他们的名字与豪门绯闻紧密相连,每一次表态都能在转会市场上掀起波澜。这不...
北京警察连续输错5次密码:这就... 几天前,北京丰台的民警上门拦截电信网络诈骗时,发生了紧张的一幕。被骗事主开门时还在与骗子共享屏幕,刚...
美媒公布最新民调:全球对中国好... 【环球网报道 记者 赵建东】美国Axios新闻网2日援引晨间咨询公司(Morning Consult...
韩国新总统最快4日上任,学者:... 韩国总统大选3日即将迎来正式投票。根据选前多项“封关”民调结果,共同民主党候选人李在明仍以明显优势领...
23亿镑仍被冻结!英政府声明:... 直播吧06月03日讯 英国财政大臣瑞秋-里维斯与外交大臣戴维-拉米发表联合声明,就阿布出售切尔西的2...