grpc在java中的使用(客户端相关)

简单介绍一下rpc

RPC是Remote Procedure Call的简称,中文叫远程过程调用。

说的白话一点,可以这么理解:现在有两台服务器A和B。部署在A服务器上的应用,想调用部署在B服务器上的另一个应用提供的方法,由于不在一个内存空间,不能直接调用,需要通过网络来达到调用的效果。

现在,我们在A服务的一个本地方法中封装调用B的逻辑,然后只需要在本地使用这个方法,就达到了调用B的效果。

对使用者来说,屏蔽了细节。你只需要知道调用这个方法返回的结果,而无需关注底层逻辑。

那,从封装的那个方法角度来看,调用B之前我们需要知道什么?

当然是一些约定啊。比如,

调用的语义,也可以理解为接口规范。(比如RESTful)

网络传输协议 (比如HTTP)

数据序列化反序列化规范(比如JSON)。

有了这些约定,我就知道如何给你发数据,发什么样的数据,你返回给我的又是什么样的数据。

在这里插入图片描述

从上图中可以看出,RPC是一种客户端-服务端(Client/Server)模式。

从某种角度来看,所有本身应用程序之外的调用都可以归类为RPC。无论是微服务、第三方HTTP接口,还是读写数据库中间件Mysql、Redis。

HTTP 和 RPC 有什么区别?

首先这个问题本身不太严谨。

HTTP只是一个通信协议,工作在OSI第七层。

而RPC是一个完整的远程调用方案。它包含了:接口规范、传输协议、数据序列化反序列化规范。

这样看,RPC和 HTTP的关系只可能是包含关系。为什么是可能?因为RPC传输协议那块我可以不基于HTTP呀。

所以这个问题应该改成:基于HTTP的远程调用方案 (如:HTTP+RESTful+JSON) 和直接使用RPC远程调用方案有什么区别?

RPC 和 gRPC 有什么关系?

gRPC是由 google开发的一个高性能、通用的开源RPC框架,主要面向移动应用开发且基于HTTP/2协议标准而设计,同时支持大多数流行的编程语言。

gRPC基于 HTTP/2协议传输。而HTTP/2相比HTTP1.x,有以下一些优势:

用于数据传输的二进制分帧
HTTP/2采用二进制格式传输协议,而非HTTP/1.x的文本格式。

在这里插入图片描述

多路复用
HTTP/2支持通过同一个连接发送多个并发的请求。

而HTTP/1.x虽然通过pipeline也能并发请求,但多个请求之间的响应依然会被阻塞。

e653367aa7d3b3cd3a6e5f46c69cebb9.png
img

服务端推送
服务端推送是一种在客户端请求之前发送数据的机制。在HTTP/2中,服务器可以对客户端的一个请求发送多个响应。而不像HTTP/1.X一样,只能通过客户端发起request,服务端才产生对应的response。

减少网络流量的头部压缩。
HTTP/2对消息头进行了压缩传输,能够节省消息头占用的网络流量。

gRPC 是如何进行远程调用的?

官网有一张图:

3b16653448df01f0aeeea7bbb90961ad.png
img

从上图和文档中可以看出,用gRPC来进行远程调用服务,客户端(client) 仅仅需要gRPC Stub(为啥叫存根?) ,通过Proto Request向gRPC Server发起服务调用,然后 gRPC Server通过Proto Response(s)将调用结果返回给调用的client。

关于Protobuf

Protobuf是Protocol Buffers的简称,gRPC使用Protocol Buffers作为序列化协议。Protocol Buffers是Google公司开发的一种数据描述语言,用于描述一种轻便高效的结构化数据存储格式,它是一种与语言、平台无关 、可扩展的序列化结构数据。它的定位类似于JSON、XML,但是比他们更小、更快、更简单,于2008年对外开源。Protobuf可以用于结构化数据串行化,或者说序列化。它的设计非常适用于在网络通讯中的数据载体,很适合做数据存储或 RPC 数据交换格式,它序列化出来的数据量少再加上以 K-V 的方式来存储数据,对消息的版本兼容性非常强,可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。开发者可以通过Protobuf附带的工具生成代码并实现将结构化数据序列化的功能。

下面对照着一个.proto文件简单介绍下Protobuf的语法

syntax = "proto3";
enum OrderBy{
  	Order_Desc = 0;
  	Order_Asc = 1;
}
message SearchRequest {  
	string query = 1;  
	int32 page_number = 2;  
	int32 result_per_page = 3;
	OrderBy order_by = 4;
}

.proto文件的第一行指定了使用 proto3语法。如果省略protocol buffer编译器默认使用 proto2语法。他必须是文件中非空非注释行的第一行。

SearchRequest定义中指定了三个字段(name/value键值对),每个字段都会有名称和类型。

指定字段类型

上面的例子中,所有的字段都是标量类型的两个整型(pagenumber和resultper_page)和一个字符串型(query)。不过你还可以给字段指定复合类型,包括枚举类型和其他message类型

指定字段编号

在message定义中每个字段都有一个唯一的编号,这些编号被用来在二进制消息体中识别你定义的这些字段,一旦你的message类型被用到后就不应该在修改这些编号了。注意在将message编码成二进制消息体时字段编号1-15将会占用1个字节,16-2047将占用两个字节。所以在一些频繁使用用的message中,你应该总是先使用前面1-15字段编号。

你可以指定的最小编号是1,最大是2E29 - 1(536,870,911)。其中19000到19999是给protocol buffers实现保留的字段标号,定义message时不能使用。同样的你也不能重复使用任何当前message定义里已经使用过和预留的字段编号。

定义字段的规则

message的字段必须符合以下规则:

singular:一个遵循singular规则的字段,在一个结构良好的message消息体(编码后的message)可以有0或1个该字段(但是不可以有多个)。这是proto3语法的默认字段规则。(这个理解起来有些晦涩,举例来说上面例子中四个字段都是singular类型的字段,在编码后的消息体中可以有0或者1个query字段,但不会有多个。)

repeated:遵循repeated规则的字段在消息体重可以有任意多个该字段值,这些值的顺序在消息体重可以保持(就是数组类型的字段)

添加更多消息类型

在单个 .proto文件中可以定义多个message,这在定义多个相关message时非常有用。比如说,我们定义 SearchRequest对应的响应message SearchResponse ,把它加到之前的 .proto文件中。

message SearchRequest {  
	string query = 1;  
	int32 page_number = 2;  
	int32 result_per_page = 3;
	OrderBy order_by = 4;
}
message SearchResponse { ...}

添加注释

.proto文件中的注释和C,C++的注释风格相同,使用// 和 /* … */

标量类型

在这里插入图片描述

默认值

当时一个被编码的message体中不存在某个message定义中的singular字段时,在message体解析成的对象中,相应字段会被设置为message定义中该字段的默认值。默认值依类型而定:

对于字符串,默认值为空字符串。

对于字节,默认值为空字节。

对于bools,默认值为false。

对于数字类型,默认值为零。

对于枚举,默认值是第一个定义的枚举值,该值必须为0。

对于消息字段,未设置该字段。它的确切值取决于语言。有关详细信息,请参阅代码生成指南。

通过proto文件生成java代码

参考:配置 Gradle 从 Protobuf 生成 Java 代码

参考:
什么是 gRPC ?
gRPC基础–Protobuf编码格式详解

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值