热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【GO】grpc

【GO】grpc,Go语言社区,Golang程序员人脉社

参考资料

https://www.jianshu.com/p/9ea...
https://www.cnblogs.com/baosh...
http://doc.oschina.net/grpc?t...
https://pkg.go.dev/google.gol...
https://www.jianshu.com/p/b72...
https://grpc.io/docs/language...
https://www.cnblogs.com/ExMan...
https://blog.csdn.net/u011518...
https://grpc.io/docs/language...
https://www.cnblogs.com/aweso...
https://blog.csdn.net/zhangmi...
https://blog.csdn.net/xp17817...

1.概念

RPC(remote procedure call远程过程调用),实际上是提供了一套框架机制,使得位于网络中的不同机器上的应用程序之间可以进行通信相互调用,而且也遵从server/client模型。使用的时候客户端调用server端提供的接口就像是调用本地的函数一样。通常RPC都是通过反射机制来实现的,本文不做深入分析,待后续文章再深入分析RPC的实现原理。

与其他的RPC框架类似,gRPC在服务端提供一个gRPC Server,客户端的库是gRPC Stub。典型的场景是客户端发送请求,调用服务端的接口,客户端和服务端之间的通信协议是基于HTTP2的,支持双工的流式保序消息,性能比较好,同时也很轻量级。

2.优点

既然是vserver/client模型,那么我们直接用restful api不是也可以的吗,为什么还需要RPC(或者gRPC)呢?下面我们就来看看gRPC相对于Restful API到底有哪些优势?gRPC和restful API都提供了一套通信机制,用于server/client模型通信,而且它们都使用http作为底层的传输协议。不过gRPC还是有些特有的优势的,如下:

  • gRPC可以通过protobuf来定义接口,从而可以有更加严格的接口约束条件;
  • 另外,通过protobuf可以将数据序列化为二进制编码,这会减少需要传输的数据量,从而提高性能;
  • gRPC可以方便地支持流式通信(理论上通过http2.0就可以使用streaming模式);
    简单易学,快速开始,能够支持多种语言和平台,双向流式通讯、集成认证模块。

3.使用场景

需要对接口进行严格约束的情况,我们不希望客户端给我们传递任意的数据,尤其是考虑到安全性的因素,我们通常需要对接口进行更加严格的约束。这时gRPC就可以通过protobuf来提供严格的接口约束;

对于性能有更高的要求时。有时我们的服务需要传递大量的数据,而又希望不影响我们的性能,这个时候也可以考虑gRPC服务,因为通过protobuf我们可以将数据压缩编码转化为二进制格式,通常传递的数据量要小得多,而且通过http2我们可以实现异步的请求,从而大大提高了通信效率;

但是,通常我们不会去单独使用gRPC,而是将gRPC作为一个部件进行使用,这是因为在生产环境,我们面对大并发的情况下,需要使用分布式系统来去处理,而`gRPCv并没有提供分布式系统相关的一些必要组件。而且,真正的线上服务还需要提供包括负载均衡,限流熔断,监控报警,服务注册和发现等必要的组件;

接下来还得简单介绍一下Protobuf,因为gRPC使用vprotobuf来定义接口。Protobuf是什么?Protobuf实际是一套类似于Json或者XML的数据传输格式和规范,用于不同应用或进程之间进行通信时使用。通信时所传递的信息是通过Protobuf定义的message数据结构进行打包,然后编译成二进制的码流再进行传输或者存储。

4.Protobuf概念

Protobuf实际是一套类似于Json或者XML的数据传输格式和规范,用于不同应用或进程之间进行通信时使用。通信时所传递的信息是通过Protobuf定义的message数据结构进行打包,然后编译成二进制的码流再进行传输或者存储。

5.Protobuf优点

  • 足够简单;
  • 序列化后体积很小,消息大小只需要XML1/10 ~ 1/3
  • 解析速度快,解析速度比XML快20 ~ 100倍;
  • 多语言支持;
  • 更好的兼容性,Protobuf设计的一个原则就是要能够很好的支持向下或向上兼容;

6.使用Protobuf步骤

  • 定义消息;
  • 初始化消息以及存储传输消息;
  • 读取消息并解析;

Protobuf的消息结构是通过一种叫做Protocol Buffer Language的语言进行定义和描述的,实际上Protocol Buffer Language分为两个版本,版本2和版本3,默认不声明的情况下使用的是版本2,目前推荐使用的是版本3。

采用ProtoBuf作为IDLInterface Definition Language接口定义语言),需要定义servicemessage,生成客户端和服务端代码。用户自己实现服务端代码中的调用接口,并且利用客户端代码来发起请求到服务端。service代表RPC接口,message代表数据结构(里面可以包括不同类型的成员变量,包括字符串、数字、数组、字典等)。message中成员变量后面的数字代表进行二进制编码时候的提示信息,1~15表示热变量,会用较少的字节来编码。默认所有变量都是可选的(optional),repeated则表示数组。service rpc接口只能接受单个message 参数,返回单个message。

7.golang安装gRpc

git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc
git clone https://github.com/golang/net.git $GOPATH/src/golang.org/x/net
git clone https://github.com/golang/text.git $GOPATH/src/golang.org/x/text
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
git clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto

cd $GOPATH/src/
go install google.golang.org/grpc

windows安装:

$ export GO111MODULE=on # Enable module mode
$ go get google.golang.org/protobuf/cmd/protoc-gen-go google.golang.org/grpc/cmd/protoc-gen-go-grpc
$ export PATH="$PATH:$(go env GOPATH)/bin"

问题:
【1】 go get github.com/golang/protobuf/protoc-gen-go的问题
解决链接:https://blog.csdn.net/wwqcher...

【2】 git出现fatal: The remote end hung up unexpectedly
方案:https://blog.csdn.net/qq_3539...
方法:git clone --depth 1 https://github.com/grpc/grpc-...

8.例子

https://www.sohu.com/a/426454...

对于开发者而言:
【1】需要使用protobuf定义接口,即.proto文件

【2】然后使用compile工具生成特定语言的执行代码,比如JAVAC/C++Python等。类似于thrift,为了解决跨语言问题。

【3】启动一个Server端,server端通过侦听指定的port,来等待Client链接请求,通常使用Netty来构建,GRPC内置了Netty的支持。

【4】启动一个或者多个Client端,Client也是基于Netty,Client通过与Server建立TCP长链接,并发送请求;RequestResponse均被封装成HTTP2的stream Frame,通过Netty Channel进行交互。

8.1 定义服务
我们想要实现的是通过gRPC框架进行远程服务调用,首先第一步应该是要有服务。利用之前所掌握的内容,gRPC框架支持对服务的定义和生成。gRPC框架默认使用protocol buffers作为接口定义语言,用于描述网络传输消息结构。除此之外,还可以使用protobuf定义服务接口。

syntax = "proto3";
package message;
//订单请求参数
message OrderRequest {
string orderId = 1;
int64 timeStamp = 2;
}
//订单信息
message OrderInfo {
string OrderId = 1;
string OrderName = 2;
string OrderStatus = 3;
}
//订单服务service定义
service OrderService{
rpc GetOrderInfo(OrderRequest) returns (OrderInfo);
}

通过proto文件定义了数据结构的同时,还定义了要实现的服务接口,GetOrderInfo即是具体服务接口的定义,在GetOrderInfo接口定义中,OrderRequest表示是请求传递的参数,OrderInfo表示处理结果返回数据参数。

8.2 环境准备
定义的proto文件需要通过编译,生成go语言代码文件,供客户端程序和服务端程序使用。可以安装go语言环境中的关于proto的插件。

go get -a github.com/golang/protobuf/protoc-gen-go #-a 参数标示下载好后直接做 go install

可以通过基本编译命令完成对.proto文件的编译.基础编译命令如下:

protoc --go_out=. *.proto

gRPC编译支持

如果定义的.proto文件,如本案例中所示,定义中包含了服务接口的定义,而我们想要使用gRPC框架实现RPC调用。开发者可以采用protocol-gen-go库提供的插件编译功能,生成兼容gRPC框架的golang语言代码。只需要在基本编译命令的基础上,指定插件的参数,告知protoc编译器即可。具体的编译生成兼容gRPC框架的服务代码的命令如下:

protoc --go_out=plugins=grpc:. *.proto

8.3 gRPC实现RPC编程

8.3.1 服务接口实现
.proto定义好服务接口并生成对应的go语言文件后,需要对服务接口做具体的实现。定义服务接口具体由OrderServiceImpl进行实现,并实现GetOrderInfo详细内容,服务实现逻辑与前文所述内容相同。不同点是服务接口参数的变化。详细代码实现如下:

type OrderServiceImpl struct {
}
//具体的方法实现
func (os *OrderServiceImpl) GetOrderInfo(ctx context.Context, request *message.OrderRequest) (*message.OrderInfo, error) {
orderMap := map[string]message.OrderInfo{
"201907300001": message.OrderInfo{OrderId: "201907300001", OrderName: "衣服", OrderStatus: "已付款"},
"201907310001": message.OrderInfo{OrderId: "201907310001", OrderName: "零食", OrderStatus: "已付款"},
"201907310002": message.OrderInfo{OrderId: "201907310002", OrderName: "食品", OrderStatus: "未付款"},
}
var response *message.OrderInfo
current := time.Now().Unix()
if (request.TimeStamp > current) {
*respOnse= message.OrderInfo{OrderId: "0", OrderName: "", OrderStatus: "订单信息异常"}
} else {
result := orderMap[request.OrderId]
if result.OrderId != "" {
fmt.Println(result)
return &result, nil
} else {
return nil, errors.New("server error")
}
}
return response, nil
}

8.3.2 gRPC实现服务端
使用gRPC框架,首先实现服务端的程序。既然使用gRPC框架来实现,就需要调用gRPC进行服务方法的注册以及监听的处理。服务注册和监听处理实现如下:

func main() {
server := grpc.NewServer()
message.RegisterOrderServiceServer(server, new(OrderServiceImpl))
lis, err := net.Listen("tcp", ":8090")
if err != nil {
panic(err.Error())
}
server.Serve(lis)
}

8.3.3 gRPC实现客户端
实现完服务端以后,实现客户端程序。和服务端程序关系对应,调用gRPC框架的方法获取相应的客户端程序,并实现服务的调用,具体编程实现如下:

func main() {
//1、Dail连接
conn, err := grpc.Dial("localhost:8090", grpc.WithInsecure())
if err != nil {
panic(err.Error())
}
defer conn.Close()
orderServiceClient := message.NewOrderServiceClient(conn)
orderRequest := &message.OrderRequest{OrderId: "201907300001", TimeStamp: time.Now().Unix()}
orderInfo, err := orderServiceClient.GetOrderInfo(context.Background(), orderRequest)
if orderInfo != nil {
fmt.Println(orderInfo.GetOrderId())
fmt.Println(orderInfo.GetOrderName())
fmt.Println(orderInfo.GetOrderStatus())
}
}

运行程序

经过上述步骤后,程序及逻辑全部开发完成。程序运行,打印如下结果:

201907300001
衣服
已付款

9.生成.go文件

$ protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative helloworld/helloworld.proto

go_out:生成*.pb.go代码的路径
go-grpc_out:生产*.grpc.pb.go的路径
helloworld/helloworld.proto*.proto的路径

10.遇到的错误

【1】Missing 'go_package' option Go 生成 grpc文件告警
https://www.jianshu.com/p/e05...

【2】No syntax specified for the proto file : xxx.proto
https://blog.csdn.net/weixin_...

【3】proto:2:1: Interpreting non ascii codepoint 226.
https://blog.csdn.net/qq_3845...
https://www.jianshu.com/p/6f1...

【4】 rpc error: code = Unimplemented desc = RPC method not implemented
https://www.cnblogs.com/lavin...

【5】 _grpc.pb.go:14:11: undefined: grpc.SupportPackageIsVersion7
https://blog.csdn.net/yzf2795...

【6】 *.pb.go:222:7: undefined: grpc.ClientConnInterface
https://blog.csdn.net/qq_1607...
go mod中修改版本

syntax = "proto3";// 协议为proto3
option go_package = ".;protoTest";
// 定义发送请求信息
message SimpleRequest{
// 定义发送的参数
// 参数类型 参数名 标识号(不可重复)
string data = 1;
}
// 定义响应信息
message SimpleResponse{
// 定义接收的参数
// 参数类型 参数名 标识号(不可重复)
int32 code = 1;
string value = 2;
}
// 定义我们的服务(可定义多个服务,每个服务可定义多个接口)
service Simple{
rpc Route (SimpleRequest) returns (SimpleResponse){};
}


推荐阅读
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • phpcomposer 那个中文镜像是不是凉了 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
  • Question该提问来源于开源项目:react-native-device-info/react-native-device-info ... [详细]
  • 如果说以比特币为代表的货币区块链技术为1.0,以以太坊为代表的合同区块链技术为2.0,那么实现了完备的权限控制和安全保障的Hyperledger项目毫无疑问代表着区块链技术3.0 ... [详细]
  • 基于.NET Core框架nacos的简单应用
    什么是Nacos?服务(Service)是Nacos世界的一等公民。Nacos支持 ... [详细]
author-avatar
lchakjet
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有