多语言gRPC开发入门与避坑指南

目录

gRPC相关介绍

什么是gPRC

gPRC的优点

gPRC的缺点

gPRC定位

协议缓冲区(Protocol Buffers)

四种调用方式

gRPC开发三大步骤

第一步:定义和编写proto服务文件

第二步:proto文件转化为gRPC代码

第三步:调用gRPC代码

详细开发细节

Server端-Java

 Client端-Java

Client端-Golang

步骤一:准备插件

步骤二:准备proto服务描述文件

步骤三:基于proto文件生成gRPC代码

步骤四:编写客户端代码调用gRPC

 Client端-Python

步骤一:安装grpc和相关工具:

步骤二:忽略

步骤三:基于proto文件生成gRPC代码

步骤四:编写客户端代码调用gRPC

避坑指南

Java

Golang

Python

总结


gRPC相关介绍

什么是gPRC

基于http2+protocol buffer技术,简单说就是编码压缩+缓存,追求高效率。

gPRC的优点

1、高性能,毕竟是rpc技术,这个优点是我们选择gRPC的主要出发点。
2、报文可在stream上双向流传输,这个是http协议做不到的,用到双向流的场景首选gRPC。

gPRC的缺点

1、开发步骤很复杂! 这个是被gRPC劝退的主要原因,开发过程一不小心就踩坑。
2、目前支持的不充分。简单说就是太新了,像浏览器啥的支持的不好,导致开发调试没那么方便。

gPRC定位

gPRC是CNCF里唯一的传输协议项目,它的定位就是云原生时代分布式、微服务集群的核心底层通信服务。基于这个定位,我们就有必须学习它的理由。

协议缓冲区(Protocol Buffers)

这个是gRPC协议的核心模块,.proto文件、protoc工具、protobuf插件等跟它有关的名词充斥着整个gRPC开发过程。
Protocol Buffers是google推出的一种序列化的协议,它的定位就像json、xml、对象二进制流等一样,是用于对象传输过程中编码解码的。
它比json还要精简,主要体现在编码时丢弃了一些不必要的内容,解码的时候抛弃了全扫描的方式。

四种调用方式

1、同步函数式,一来一回
rpc SayHello(HelloRequest) returns (HelloResponse);
2、 客户端流式,多来一回
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
3、服务端流式,一来多回
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
4、双向流,多来多回
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);

gRPC开发三大步骤

第一步:定义和编写proto服务文件

像定义API一样,直接编写一个.proto后缀的服务描述文件,如下:

syntax = "proto3";option java_multiple_files = true;
option java_package = "com.jingtao.library";
option java_outer_classname = "BookServiceProto";
option objc_class_prefix = "HLW";package mybook;
// The greeting service definition.
service BookService {// Sends a greetingrpc check (RequestData) returns (Book) {}
}// The request message containing the user's name.
message RequestData {string name = 1;
}message Book {string name = 1;string auther = 2;int32 price = 3;
}

syntax定义协议版本
option部分是跟着语言耦合的部分
package定义了服务的包名
service定义了服务的函数
message定义了服务函数需要打的入参、出参等对象

第二步:proto文件转化为gRPC代码

该步骤是把上面的.proto文件通过工具或插件生成可以被程序直接调用的gRPC代码,因为要被程序调用,所以这一步是与语言紧耦合的,不同语言转换的方式各不相同。

第三步:调用gRPC代码

到了第三步就相对轻松了,第二步生成的gRPC文件已经以接口的方式将服务封装好了,我们要干的只是import它,然后调用它。

详细开发细节

Server端-Java

java语言.proto文件转化为gRPC有三种方式

方式一:独立转换
在操作系统中安装转换可视化或者命令工具,例如protoc(下载地址https://github.com/protocolbuffers/protobuf/releases),在操作系统层做好转换后将转换后的代码copy到代码项目中。
方式二:开发工具插件转化
以IDEA为例,转换的插件有GenProtoBuf、Protocol Buffer,而且都是免费的。
方式三:依赖转换
直接在项目中引入相关依赖插件,利用它们生成代码。例如java中的protobuf-java-util

我采用的是方式三,pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>BookFactory</artifactId><version>1.0-SNAPSHOT</version><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><protoc.version>3.12.0</protoc.version><grpc.version>1.56.1</grpc.version></properties><dependencies><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>3.12.0</version></dependency><!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java-util --><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java-util</artifactId><version>3.12.0</version></dependency><!-- https://mvnrepository.com/artifact/io.grpc/grpc-all --><dependency><groupId>io.grpc</groupId><artifactId>grpc-all</artifactId><version>1.56.1</version></dependency></dependencies><build><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.6.2</version></extension></extensions><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.7.0</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.6.1</version><configuration><protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact><protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot><outputDirectory>${project.basedir}/src/main/java/</outputDirectory><clearOutputDirectory>false</clearOutputDirectory></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin></plugins></build></project>

双击Plugin中protobuf的compile生成服务bean,通过custom生成可直接被上层调用的gRPC。

服务端引用并实现grpc代码

        <dependency><groupId>io.grpc</groupId><artifactId>grpc-all</artifactId><version>1.56.1</version></dependency>

服务端代码如下:

package com.jingtao.library;import io.grpc.Grpc;
import io.grpc.InsecureServerCredentials;
import io.grpc.Server;
import io.grpc.stub.StreamObserver;import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;public class BookServer {private static final Logger logger = Logger.getLogger(BookServer.class.getName());private Server server;int port = 8088;private void start() throws IOException {server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()).addService(new BookImpl()).build().start();logger.info("Server started, listening on " + port);Runtime.getRuntime().addShutdownHook(new Thread() {@Overridepublic void run() {// Use stderr here since the logger may have been reset by its JVM shutdown hook.System.err.println("*** shutting down gRPC server since JVM is shutting down");try {BookServer.this.stop();} catch (InterruptedException e) {e.printStackTrace(System.err);}System.err.println("*** server shut down");}});}private void stop() throws InterruptedException {if (server != null) {server.shutdown().awaitTermination(30, TimeUnit.SECONDS);}}static class BookImpl extends BookServiceGrpc.BookServiceImplBase {@Overridepublic void check(RequestData req, StreamObserver<Book> responseObserver) {Book reply = Book.newBuilder().setName(req.getName()).setAuther("Shakespeare").setPrice(35).build();responseObserver.onNext(reply);responseObserver.onCompleted();}}private void blockUntilShutdown() throws InterruptedException {if (server != null) {server.awaitTermination();}}/*** Main launches the server from the command line.*/public static void main(String[] args) throws IOException, InterruptedException {final BookServer server = new BookServer();server.start();server.blockUntilShutdown();}}

 Client端-Java

Java客户端前面部分跟服务端一样,只有最后一步不同:

package com.jingtao.library;import io.grpc.*;import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;public class BookClientor {private static final Logger logger = Logger.getLogger(BookClientor.class.getName());private final BookServiceGrpc.BookServiceBlockingStub blockingStub;public BookClientor(Channel channel) {blockingStub = BookServiceGrpc.newBlockingStub(channel);}public void say(String name) {logger.info("Will try to greet " + name + " ...");RequestData request = RequestData.newBuilder().setName(name).build();Book response;try{response = blockingStub.check(request);}catch (StatusRuntimeException e) {logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());return;}logger.info("Invoke say result is : " + response.getName()+ " " + response.getAuther()+ " " + response.getPrice());}public static void main(String[] args) throws Exception{String user = "les miserables";// Access a service running on the local machine on port 50051String target = "localhost:8088";ManagedChannel channel = Grpc.newChannelBuilder(target, InsecureChannelCredentials.create()).build();try {BookClientor client = new BookClientor(channel);client.say(user);} finally {// ManagedChannels use resources like threads and TCP connections. To prevent leaking these// resources the channel should be shut down when it will no longer be used. If it may be used// again leave it running.channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);}}
}

Client端-Golang

步骤一:准备插件

给protoc准备go相关插件和工具
git clone https://github.com/golang/protobuf.git $GOPATH/src/github.com/golang/protobuf
cd $GOPATH/src/
go install github.com/golang/protobuf/protoc-gen-go@latest
这一步的目标是准备好protoc-gen-go,搞定后一定要确保包含protoc-gen-go的bin在path中,可以被protoc用到。

步骤二:准备proto服务描述文件

注意需要显式的指定所生成gRPC代码的包名
option go_package="./;book";

步骤三:基于proto文件生成gRPC代码

准备好proto文件后,执行以下命令生成go的gRPG文件
protoc -I proto/ --go_out=plugins=grpc:proto proto/book_route.proto

步骤四:编写客户端代码调用gRPC

package bookimport (bookgrpc "book-client-go/proto""fmt""golang.org/x/net/context""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure"
)func MyClient() {conn, err := grpc.Dial(":8088", grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {// handle errorpanic(err)}defer conn.Close()client := bookgrpc.NewBookServiceClient(conn)req := bookgrpc.RequestData{Name: "world",}reply, err := client.Check(context.Background(), &req)if err != nil {fmt.Println("client.bookservice error:", err)return}fmt.Printf("get msg from server:[%v] \n", reply)}

 Client端-Python

步骤一:安装grpc和相关工具:

pip install grpcio
pip install grpcio-tools  
pip install protobuf

步骤二:忽略

python不需要单独设置option_package,因为最终生成的gRPC代码在python中放在哪个目录下就引入哪个目录好了。

步骤三:基于proto文件生成gRPC代码

然后执行以下python命令将proto文件转换为gRPC的python代码
python -m grpc_tools.protoc -I ./ --python_out=./ --grpc_python_out=. ./book_route.proto

步骤四:编写客户端代码调用gRPC

import grpcfrom book import book_route_pb2,book_route_pb2_grpcdef run():conn = grpc.insecure_channel('127.0.0.1:8088')client = book_route_pb2_grpc.BookServiceStub(channel=conn)reqeust = book_route_pb2.RequestData(name='jingtao')respnse = client.check(reqeust)print("received name:", respnse.name)print("received auther:", respnse.auther)print("received:", respnse.price)if __name__ == '__main__':run()

避坑指南

Java

1、java.lang.NoSuchMethodError: java.nio.ByteBuffer.clear()Ljava/nio/ByteBuffer;

代码全部都编译过并切启动成功的前提下,客户端和服务端进行grpc交互时遇到这个报错

核心是jdk版本与grpc依赖包版本不一致导致的
我用的jdk1.8+protoc3.12.0+grpc1.57.0就会出这个错误,换成jdk1.8+protoc3.12.0+grpc1.56.1后问题解决。

 2、UnusedPrivateParameter unused:

通过插件基于proto文件生产的gprc代码中出现了UnusedPrivateParameter编译错误,核心原因是maven导入的依赖版本与实际所需要的依赖版本不一致导致的。

错误配置:

正确配置:

Golang

1、protoc-gen-go: unable to determine Go import path for "book_route.proto"

protoc -I proto/ --go_out=plugins=grpc:proto proto/book_route.proto的时候报错:

原因是我从java项目中直接copy了proto过来,但里面缺少go需要的配置,修改proto后问题解决。
所以gRPC开发过程中proto文件不能直接复制,需要摘选出service和message部分,这是一个比较讨厌的地方。 

Python

1、Cannot unpack file C:\Users\MGTV\AppData\Local\Temp\pip-unpack-iee13adu\simple

执行pip安装grpc时报错,原因是因为pip的源有问题。

开始pip安装网络太慢所以用到代理:
pip install grpcio-i http://pypi.mirrors.ustc.edu.cn/pypi/simple/ --trusted-host pypi.mirrors.ustc.edu.cn
把http://mirrors.aliyun.com/pypi/simple/替换成https://pypi.mirrors.ustc.edu.cn/simple/也解决不了,后来直接用了最原始的命令,没有走代理,问题解决

2、生成的_pd2.py缺少request和response的负载对象导致开发过程中编译不过

这个问题是grpc_tools在1.44版本以后由预定义变成了运行中自动生成对象了,不影响正常运行,这样虽然使代码更简洁了,但是可读性确实变差了。 

总结

本文用java实现了gRPC服务端,然后分别用java、go、python来调用,只给了“一来一回”同步函数式调用,其实gRPC支持4中调用方式,真实情况比复杂的多。但比起对接gRPC来说,开发环境的准备更复杂,坑也很多,希望通过本篇博文能把gRPC开发所有步骤和需要注意的地方都解释清楚。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/75933.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

致远A8+数据库账密信息泄露

声明 本文仅用于技术交流&#xff0c;请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任。 文章作者拥有对此文章的修改和解释权。如欲转载或传播此文章&#xff0c…

【论文阅读24】Better Few-Shot Text Classification with Pre-trained Language Model

论文相关 论文标题&#xff1a;Label prompt for multi-label text classification&#xff08;基于预训练模型对少样本进行文本分类&#xff09; 发表时间&#xff1a;2021 领域&#xff1a;多标签文本分类 发表期刊&#xff1a;ICANN&#xff08;顶级会议&#xff09; 相关代…

Windows环境下VSCode安装PlatformIO Cero报错ERROR: HTTP error 403 while getting

安装PlatformIO插件成功&#xff0c;初始化失败 错误信息判断问题尝试访问https://pypi.tuna.tsinghua.edu.cn/simple/platformio/成功点击文件后报错如下&#xff1a; 解决问题- 换源 &#xff08; Windows下有两个地方需要更改&#xff09;cmd命令行Pip文件 总结&#xff1a;…

Android如何用系统签名打包应用

前言 应用使用系统签名可以在用户不需要手动授权的情况下自动获取权限。适合一些定制系统中集成apk的方案商。 步骤 需要在AndroidManifest.xml中添加共享系统进程属性&#xff1a; android:sharedUserId"android.uid.system"如下图所示&#xff1a; 找到系统定制…

opencv基础40-礼帽运算(原始图像减去其开运算)cv2.MORPH_TOPHAT

礼帽运算是用原始图像减去其开运算图像的操作。礼帽运算能够获取图像的噪声信息&#xff0c;或者得到比原始图像的边缘更亮的边缘信息。 例如&#xff0c;图 8-22 是一个礼帽运算示例&#xff0c;其中&#xff1a; 左图是原始图像。中间的图是开运算图像。右图是原始图像减开运…

车载开发核心技术——SystemUI控制技术

SystemUI是指车载开发中的一个重要组件&#xff0c;它负责管理和控制车机的用户界面和交互功能。本文将详细介绍SystemUI的各项控制技术&#xff0c;包括音量控制、RingtonePlayer、电源管理、任务管理、通知栏和服务定制&#xff0c;并提供相关代码示例和解析。 一、音量控制…

百度Apollo规划算法——OBB障碍物检测代码解析

百度Apollo规划算法——Box障碍物检测代码解析 前言代码代码分析f1f2f3f4f5f6 参考 前言 本文主要分析Apollo代码中函数bool Box::HasOverlap(const Box2d &box) const {}的数学原理。 在阅读此部分代码时&#xff0c;第一遍没看懂return的一堆什么意思&#xff0c;百度之后…

iOS——Block签名

首先来看block结构体对象Block_layout&#xff08;等同于clang编译出来的__Block_byref_a_0&#xff09; #define BLOCK_DESCRIPTOR_1 1 struct Block_descriptor_1 {uintptr_t reserved;uintptr_t size; };#define BLOCK_DESCRIPTOR_2 1 struct Block_descriptor_2 {// requi…

谈谈关于新能源汽车的话题

新能源汽车是指使用新型能源替代传统燃油的汽车&#xff0c;主要包括纯电动汽车、插电式混合动力汽车和燃料电池汽车等。随着环境污染和能源安全问题的日益突出&#xff0c;新能源汽车已经成为全球汽车行业的发展趋势。下面我们来谈谈关于新能源汽车的话题。 首先&#xff0c;新…

uC-OS2 V2.93 STM32L476 移植:环境搭建篇

前言 uC-OS2 是比较经典的 RTOS&#xff0c;如今软件授权已经改为 Apache License Version 2.0&#xff0c;意味着可以免费商用了 当前 uC-OS2 的最新版本是&#xff1a; V2.93&#xff0c;打算研究一下 RTOS 的设计思想&#xff0c;所以想在已有的开发板&#xff1a;NUCLEO-L…

C语言阶段性测试题

【前言】&#xff1a;本部分是C语言初阶学完阶段性测试题&#xff0c;最后一道编程题有一定的难度&#xff0c;需要多去揣摩&#xff0c;代码敲多了&#xff0c;自然就感觉不难了&#xff0c;加油&#xff0c;铁汁们&#xff01;&#xff01;&#xff01; 一、选择题 1.下面程…

【雕爷学编程】Arduino动手做(181)---Maixduino AI开发板12

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

使用 OpenCV 和 Python 卡通化图像-附源码

介绍 在本文中,我们将构建一个有趣的应用程序,它将卡通化提供给它的图像。为了构建这个卡通化器应用程序,我们将使用 python 和 OpenCV。这是机器学习令人兴奋的应用之一。在构建此应用程序时,我们还将了解如何使用 easygui、Tkinter 等库。在这里,您必须选择图像,然后应…

20天学rust(一)和rust say hi

关注我&#xff0c;学习Rust不迷路 工欲善其事&#xff0c;必先利其器。第一节我们先来配置rust需要的环境和安装趁手的工具&#xff0c;然后写一个简单的小程序。 安装 Rust环境 Rust 官方有提供一个叫做 rustup 的工具&#xff0c;专门用于 rust 版本的管理&#xff0c;网…

Modbus TCP转Profinet网关modbus tcp转以太网

大家好&#xff0c;今天我们来聊一聊如何使用捷米特的Profinet转modbusTCP协议转换网关在博图上进行非透传型配置。 1, 首先&#xff0c;我们需要安装捷米特JM-TCP-PN的GSD文件&#xff0c;并根据现场设备情况配置modbusTCP地址。然后&#xff0c;在博图中添加该GSD文件&#x…

Dockerfile构建MySQL镜像(yum方式)

目录 Dockerfile构建MySQL镜像 1、建立工作目录 2、编写Dockerfile文件 3、构建镜像 4、测试容器 Dockerfile构建MySQL镜像 1、建立工作目录 [roothuyang1 ~]# mkdir mysql [roothuyang1 ~]# cd mysql/ 2、编写Dockerfile文件 [roothuyang1 mysql]# vim Dockerfile 配置如…

SegNeXt:重新思考用于语义分割的卷积注意力

&原文信息 原文题目&#xff1a;《SegNeXt: Rethinking Convolutional Attention Design for Semantic Segmentation》 原文引用&#xff1a;Guo M H, Lu C Z, Hou Q, et al. Segnext: Rethinking convolutional attention design for semantic segmentation[J]. Advance…

把网站改为HTTPS访问方法

HTTPS是使用TSL/SSL加密超文本传输协议的扩展&#xff0c;用于跨网络的安全传输。网站更改为HTTPS&#xff0c;直接在网站形象上可以得到提升&#xff0c;更重要的是您的网站肯定会在排名和提升方面受益。机密信息的交换需要受到保护&#xff0c;以阻止未经授权的访问。 加密&a…

组件化、跨平台…未来前端框架将如何演进?

前端框架在过去几年间取得了显著的进步和演进。前端框架也将继续不断地演化&#xff0c;以满足日益复杂的业务需求和用户体验要求。从全球web发展角度看&#xff0c;框架竞争已经从第一阶段的前端框架之争&#xff08;比如Vue、React、Angular等&#xff09;&#xff0c;过渡到…

Flink 系列四 Flink 运行时架构

目录 前言 介绍 1、程序结构 1.1、Source 1.2、Transformation 1.3、Sink 1.4、数据流 2、Flink运行时组件 2.1、Dispatcher 2.2、JobManager 2.3、TaskManager 2.4、ResourceManager 3、任务提交流程 3.1、standalone 模式 3.2、yarn 模式 4、任务调度原理 4…