点击上方“黑光技术”关注之完美之道,不在无可增加,而在无可删减!
前言
上一篇文章简单体验了一下grpc的golang使用,从环境安装到简单demo的编写,编译和测试,感觉还不错,今天再进一步学习分析其用法和一些要注意的坑。
grpc介绍
grpc一开始由 google 开发,是一款语言中立、平台中立、开源的远程过程调用(RPC)系统。是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本。而且gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。
从学习上来说,grpc的文档真是很全面了,https://grpc.io/docs/ 官网这里各种语言版本的都可以找到,golang的可以看这几篇,这篇的大部分内容都是来自这里的梳理。
Quick Start Guide
gRPC Basics Tutorial
API Reference
Generated Code Reference
另外还有一个中文版的教程:gRPC 官方文档中文版
proto
首先要说一下的还是proto文件的定义,这个定义才是最关键的,这个里面定义了grpc所需要的所有数据结构和服务。
proto文件在其网站也有非常详细的说明,这里我就不展开了,在proto文件中有两种必要的类型,一种就是消息体:message,另外一种就是service。
message的定义和我们以前使用的proto的定义方式和含义是一样的。
service就是定义一个服务,这个对于client和server端代码都需要用,主要作用就是生成服务端和客户端的stub。这里以route_guide.proto这个文件中的例子来说明:
service RouteGuide {rpc GetFeature(Point) returns (Feature) {}rpc ListFeatures(Rectangle) returns (stream Feature) {}rpc RecordRoute(stream Point) returns (RouteSummary) {}rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}}
这里定义了一个service:RouteGuide,这个服务里面有4个rpc服务:
第一个rpc服务是最简单的一种就是给一个参数Point获取一个Feature。这种也是非常常见的一种rpc服务。
第二个rpc服务是给一个参数Point,获取多个Feature,返回值是以repeated field message的形式返回,实际上就是以数据流形式返回一个数组。
第三个rpc服务是给一个message输入流,获取一个返回message
第四个rpc服务是给一个message输入流,获取一个message返回流
使用proto定义一个服务
这个proto文件编译之后会生成一个xx.pb.go的文件,这文件是proto编译之后生成的,主要是针对其中message序列化方法的实现,还有就是生成我们定义的server和client的stub文件,其实在go中就是一个interface。比如官方例子中的就生成了type RouteGuideServer interface和type RouteGuideClient interface,另外两个比较重要的方法,一个是针对客户端的,一个是针对服务端的:
服务端定义
type routeGuideClient struct {// 是对type RouteGuideClient interface的具体实现,routeGuideClient实现了RouteGuideClient的所有方法cc *grpc.ClientConn}func NewRouteGuideClient(cc *grpc.ClientConn) RouteGuideClient {return &routeGuideClient{cc} // 这里返回的就是一个RouteGuideClient类型的实现了,后面就可以用这个客户端中的方法先server端发起调用了}...func RegisterRouteGuideServer(s *grpc.Server, srv RouteGuideServer) { // 这个函数提供了一个RouteGuideServer注册到grpc.Server上。s.RegisterService(&_RouteGuide_serviceDesc, srv) // 是对这个服务的一个grpc.Server的描述,详细的可以看下面的代码...var _RouteGuide_serviceDesc = grpc.ServiceDesc{ServiceName: "routeguide.RouteGuide",HandlerType: (*RouteGuideServer)(nil),Methods: []grpc.MethodDesc{ // 单纯的函数调用接口描述{MethodName: "GetFeature",Handler: _RouteGuide_GetFeature_Handler,},},Streams: []grpc.StreamDesc{ // 有流式数据调用的接口描述{StreamName: "ListFeatures",Handler: _RouteGuide_ListFeatures_Handler,ServerStreams: true,},{StreamName: "RecordRoute",Handler: _RouteGuide_RecordRoute_Handler,ClientStreams: true,},{StreamName: "RouteChat",Handler: _RouteGuide_RouteChat_Handler,ServerStreams: true,ClientStreams: true,},},Metadata: "route_guide.proto",}
server端关键的几句代码可以看看
type routeGuideServer struct {} //定义一个实现体,后面还有具体服务方法的实现...func newServer() *routeGuideServer {s := &routeGuideServer{}return s}...lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", *port))...grpcServer := grpc.NewServer(opts...) // opts是安全证书之类的参数pb.RegisterRouteGuideServer(grpcServer, newServer()) // 注册到grpcServergrpcServer.Serve(lis) // 把监听端口传给server
客户端的关键代码
conn, err := grpc.Dial(*serverAddr, opts...) // 创建连接....client := pb.NewRouteGuideClient(conn) // 传连接返回实例化的客户端,这样就可以直接调用rpc方法了...feature, err := client.GetFeature(context.Background(), point)...
总结
简单来说grpc的开发还是有点原始,在proto的定义和转换为框架代码上都还比较粗。在内部项目中使用的话还是要自己开发不少中间件来补充功能,但是在一般简单服务中grpc是已经足够使用了。
黑光技术文章推荐
-
Golang UnitTest单元测试
-
Golang单元测试之Mock测试
-
Golang官方依赖管理工具dep学习使用
-
Golang信号处理和如何实现进程优雅退出
-
golang的httpserver优雅重启
-
golua虚拟机的使用
-
golang调度机制
-
Envoy源码分析之Dispatcher
-
Envoy源码分析之ThreadLocal
-
自2013到2019年大数据领域发生了什么变化
看完本文有收获?请分享给更多人关注「黑光技术」加星标,关注大数据+微服务看完,赶紧点个“好看”呀
点这里↓↓↓