gRPC学习之五:gRPC

Wesley13
• 阅读 711

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

RPC学习系列文章链接

  1. 在CentOS7部署和设置GO
  2. GO的gRPC开发环境准备
  3. 初试GO版gRPC开发
  4. 实战四类服务方法
  5. gRPC-Gateway实战
  6. gRPC-Gateway集成swagger

本篇概览

  • 本文《gRPC学习》系列的第五篇,gRPC常用于服务端之间的相互调用,如果想把服务暴露给前端,虽然动手修改服务端也能实现,但似乎增加了不少工作量,此时还可以选择gRPC-Gateway方式来快速将gRPC服务以http的方式暴露出来;
  • gRPC-Gateway原理如下图,借助grpc-gateway插件,可以基于proto文件生成反向代理(Reverse Proxy)的代码,这个反向代理运行起来后,对外提供RESTful服务,收到RESTful请求后通过gRPC调用原来的gRPC服务:
    gRPC学习之五:gRPC
  • 本文展示了gRPC-Gateway环境搭建、开发、验证的整个过程,由以下步骤组成:
  1. 极速搭建gRPC-Gateway环境;
  2. 编写proto文件;
  3. 根据proto文件生成gRPC、gRPC-Gateway源码;
  4. 添加业务代码;
  5. 编译、运行、验证;

提前说明文件和目录

  • 本次实战在$GOPATH/src目录下新增文件夹helloworld,里面总共有以下内容:

    [golang@centos7 src]$ tree helloworld/ helloworld/ ├── gateway │ └── helloworld.gw.go ├── helloworld.pb.go ├── helloworld.pb.gw.go ├── helloworld.proto ├── helloworld.swagger.json └── server └── server.go

  • 准备工作完成,接下来正式开始开发;

前提条件

  • 本文的所有操作都没有用到root账号,而是前文创建的golang账号;
  • 请参照以下两篇文章将GO环境和gRPC环境搭建好:
  1. 在CentOS7部署和设置GO
  2. GO的gRPC开发环境准备

极速搭建gRPC-Gateway环境

  • 所谓的搭建gRPC-Gateway环境,其实是完成以下三件事:
    gRPC学习之五:gRPC
  1. 在搭建环境时参考了一些网上的文章,结果遇到了各种问题一直没有成功(我当然不会认为文章有问题,必须认识到是自己能力不足的原因所致);

  2. 经过反复折腾后终于成功后,我把所有操作做成一个shell脚本,执行以下命令即可完成上图中的所有操作:

    curl -o install-grpc-gateway.sh
    https://raw.githubusercontent.com/zq2599/blog_demos/master/files/install-grpc-gateway.sh
    && chmod a+x ./install-grpc-gateway.sh
    && ./install-grpc-gateway.sh

  3. 进入$GOPATH/bin目录,可见新增两个文件protoc-gen-grpc-gateway和protoc-gen-swagger:

    [golang@centos7 ~]$ cd $GOPATH/bin [golang@centos7 bin]$ ls -al 总用量 26708 drwxrwxr-x. 2 golang golang 98 12月 19 08:59 . drwxrwxr-x. 5 golang golang 39 12月 19 08:21 .. -rwxr-x---. 1 golang golang 5253272 12月 19 08:20 protoc -rwxrwxr-x. 1 golang golang 8461147 12月 19 08:21 protoc-gen-go -rwxrwxr-x. 1 golang golang 6717463 12月 19 08:59 protoc-gen-grpc-gateway -rwxrwxr-x. 1 golang golang 6908535 12月 19 08:59 protoc-gen-swagger

  • 现在环境准备好了,开始开发;

编写proto文件

  • 在$GOPATH/src目录下,新建文件夹helloworld,里面新建文件helloworld.proto,内容如下,有几处要注意的地方稍后会说:

    // 协议类型 syntax = "proto3";

    // 包名 package helloworld;

    import "google/api/annotations.proto";

    // 定义的服务名 service Greeter {

    // 具体的远程服务方法 rpc SayHello (HelloRequest) returns (HelloReply) {

    option (google.api.http) = {
    
    
    
      post: "/helloworld"
      body: "*"
    };
    

    } }

    // SayHello方法的入参,只有一个字符串字段 message HelloRequest {

    string name = 1; }

    // SayHello方法的返回值,只有一个字符串字段 message HelloReply {

    string message = 1; }

  • 上述proto文件有以下几处要注意的地方:

  1. 整个文件其实就是以 《初试GO版gRPC开发》一文中的helloworld.proto为基础,增加了两处内容;
  2. 增加的第一处,是用import关键词导入google/api/annotations.proto;
  3. 增加的第二处,是SayHello方法的声明处,增加了option配置,作用是配置SayHello方法对外暴露的RESTful接口的信息;
  4. 在使用protoc-gen-grpc-gateway的时候,上述两处配置会被识别到并生成对应的代码;

根据proto文件生成gRPC、gRPC-Gateway源码

  1. proto文件编写完成,接下来是生成gRPC、gRPC-Gateway的源码;

  2. 生成gRPC源码的命令咱们前面的文章中已经用过,如下:

    protoc -I.
    -I$GOPATH/src
    -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis
    --go_out=plugins=grpc:.
    helloworld.proto

  3. 执行完成后会在当前目录生成helloworld.pb.go文件;

  4. 执行生成gRPC-Gateway源码的命令:

    protoc -I.
    -I$GOPATH/src
    -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis
    --grpc-gateway_out=logtostderr=true:.
    helloworld.proto

  5. 执行完成后会在当前目录生成helloworld.pb.gw.go文件;

  6. 执行生成swagger文件的命令:

    protoc -I.
    -I$GOPATH/src
    -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis
    --swagger_out=logtostderr=true:.
    helloworld.proto

  7. 执行完成后会在当前目录生成helloworld.swagger.json文件;

  8. 至此,helloworld目录下一共有这些内容:

    [golang@centos7 src]$ tree helloworld/ helloworld/ ├── helloworld.pb.go ├── helloworld.pb.gw.go ├── helloworld.proto └── helloworld.swagger.json

    0 directories, 4 files

  9. 接下来开始编码,把运行整个服务所需的代码补全;

  10. 由于篇幅限制,本文暂不提及swagger相关的开发和验证,因此生成的helloworld.swagger.json文件本篇用不上,留待下一篇文章使用;

编写服务端代码server.go并启动

  1. 接下来编写服务端代码server.go,这个和《初试GO版gRPC开发》中的server.go内容一样;

  2. 在$GOPATH/src/helloworld目录下新建文件夹server,在此文件夹下新建server.go,内容如下,已经添加详细注释:

    package main

    import ( "context" "log" "net" "google.golang.org/grpc" pb "helloworld" )

    const ( port = ":50051" )

    // 定义结构体,在调用注册api的时候作为入参, // 该结构体会带上SayHello方法,里面是业务代码 // 这样远程调用时就执行了业务代码了 type server struct {

    // pb.go中自动生成的,是个空结构体
    pb.UnimplementedGreeterServer
    

    }

    // 业务代码在此写,客户端远程调用SayHello时, // 会执行这里的代码 func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {

    // 打印请求参数
    log.Printf("Received: %v", in.GetName())
    // 实例化结构体HelloReply,作为返回值
    return &pb.HelloReply{
    

    Message: "Hello " + in.GetName()}, nil }

    func main() {

    // 要监听的协议和端口
    lis, err := net.Listen("tcp", port)
    if err != nil {
    
    
    
        log.Fatalf("failed to listen: %v", err)
    }
    
    // 实例化gRPC server结构体
    s := grpc.NewServer()
    
    // 服务注册
    pb.RegisterGreeterServer(s, &server{
    

    })

    log.Println("开始监听,等待远程调用...")
    
    if err := s.Serve(lis); err != nil {
    
    
    
        log.Fatalf("failed to serve: %v", err)
    }
    

    }

  3. 在server.go所在目录执行go run server.go,控制台提示如下:

    [golang@centos7 server]$ go run server.go 2020/12/13 08:20:32 开始监听,等待远程调用...

  4. 此时gRPC的服务端已启动,可以响应远程调用,接下来开发反向代理(Reverse Proxy);

编写反向代理(Reverse Proxy)代码helloworld.gw.go并启动

  • 接下来编反向代理(Reverse Proxy)代码helloworld.gw.go;

  • 在$GOPATH/src/helloworld目录下新建文件夹gateway,在此文件夹下新建helloworld.gw.go,内容如下,有几处要注意的地方稍后会说明:

    package main

    import ( "flag" "fmt" "net/http" gw "helloworld" "github.com/grpc-ecosystem/grpc-gateway/runtime" "golang.org/x/net/context" "google.golang.org/grpc" )

    var ( echoEndpoint = flag.String("echo_endpoint", "localhost:50051", "endpoint of YourService") )

    func run() error {

    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()
    mux := runtime.NewServeMux()
    opts := []grpc.DialOption{
    

    grpc.WithInsecure()} err := gw.RegisterGreeterHandlerFromEndpoint(ctx, mux, *echoEndpoint, opts) if err != nil { return err } return http.ListenAndServe(":9090", mux) }

    func main() {

    if err := run(); err != nil {
    
    
    
        fmt.Print(err.Error())
    }
    

    }

  1. 第一处要注意的地方,是调用http.ListenAndServe监听9090端口,这是对外提供RESTful服务的端口;
  2. 第二处要注意的地方,是echoEndpoint配置了将外部RESTful请求转发到server.go提供gRPC服务的入口处;
  3. 第三处要注意的地方,是调用了自动生成代码中的RegisterGreeterHandlerFromEndpoint方法完成上下游调用的绑定;
  • 在hellowworld.gw.go所在目录执行go run hellowworld.gw.go,开始监听9090端口的web请求;

验证

  1. 在本机上验证,用curl发送请求:

    curl
    -X POST
    -d '{"name": "will"}'
    192.168.133.203:9090/helloworld

  2. 收到响应如下,这是来自server.go的内容,可见http请求通过Reserve Proxy到达了真实的gRPC服务提供者,并顺利返回给调用方:

    {

    "message":"Hello will"}

  3. 去看server.go的日志如下:

    [golang@centos7 server]$ go run server.go 2020/12/19 14:16:47 开始监听,等待远程调用... 2020/12/19 14:24:35 Received: will

  4. 还可以在其他机器上通过postman验证,记得关闭服务所在机器的防火墙,请求和响应如下,注意按数字顺序设置和观察:
    gRPC学习之五:gRPC

  • 至此,将gRPC服务快速暴露为RESTful服务的实战就完成了,如果您正在做这方面的尝试,希望本文能给您一些参考,接下来的文章咱们一起把swagger补全,让开发和联调更加高效;

你不孤单,欣宸原创一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列

欢迎关注公众号:程序员欣宸

微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界…

本文同步分享在 博客“程序员欣宸”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Kurento实战之一:KMS部署和体验
欢迎访问我的GitHub这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog\_demos(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgithub.com%2Fzq2599%2Fblog_demos)
Stella981 Stella981
3年前
Kurento实战之二:快速部署和体验
欢迎访问我的GitHub这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog\_demos(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgithub.com%2Fzq2599%2Fblog_demos)
Stella981 Stella981
3年前
OpenFaaS实战之四:模板操作(template)
欢迎访问我的GitHub这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog\_demos(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgithub.com%2Fzq2599%2Fblog_demos)
Wesley13 Wesley13
3年前
gRPC学习之二:GO的gRPC开发环境准备
欢迎访问我的GitHub这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog\_demos(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgithub.com%2Fzq2599%2Fblog_demos)
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这