Go Micro 框架增补篇:集成 gRPC 网关对外提供服务

grpc-protobuf

gRPC 是由一个 Google 公司开发的、基于 HTTP/2 和 Protobuf 的高性能开源通用 RPC 框架,且支持多种语言,如 Go、Java、Python、PHP、Node.js、C++、C#、Ruby、Dart、Android Java、Object-C 等,我们可以直接通过该框架构建微服务,也可以在 Go Micro 框架中集成它来提供 gRPC 网关对外提供服务,下面我们简单演示下如何在 Go Micro 框架中实现 gRPC 网关并通过 gRPC 编写后台服务。

准备工作

helloproto-gen-grpc-gateway
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
bin

proto-gen-grpc-gateway

编写 gRPC 服务

github.com/micro/go-micro/service/grpchello/srcgreeterhellogreeterprotogreeter.proto
syntax = "proto3";
package greeter;

service Greeter {
	rpc Hello(Request) returns (Response) {}
}

message Request {
	string name = 1;
}

message Response {
	string msg = 1;
}
greeter
protoc --proto_path=. --micro_out=. --go_out=. proto/greeter.proto
greetermain.go
package main

import (
    "context"
    "github.com/micro/go-micro"
    "github.com/micro/go-micro/service/grpc"
    greeter "greeter/proto"
    "log"
)

type Greeter struct {}

func (g *Greeter) Hello(ctx context.Context, req *greeter.Request, rsp *greeter.Response) error {
    log.Println("获取 Greeter.Request 请求")
    rsp.Msg = "你好," + req.Name
    return nil
}

func main()  {
    service := grpc.NewService(
        micro.Name("go.micro.srv.greeter.grpc"),
    )

    service.Init()

    greeter.RegisterGreeterHandler(service.Server(), new(Greeter))

    if err := service.Run(); err != nil {
        log.Fatalln(err)
    }
}
hello/main.gogrpc.NewService()grpcClientgrpcServer

实现 gRPC 网关

完成服务端代码编写后,我们再来实现 gRPC 网关,客户端请求会首先到达 gRPC 网关,再由 gRPC 网关将请求转发给上面启动的服务(将 HTTP 请求转化为 gRPC 调用)。

greetergrpcgreeterprotoprotogreeter.proto
syntax = "proto3";
package grpc.gateway.greeter;

import "google/api/annotations.proto";

service Greeter {
	rpc Hello(Request) returns (Response) {
		option (google.api.http) = {
			post: "/greeter/hello"
			body: "*"
		};
	}
}

message Request {
	string name = 1;
}

message Response {
	string msg = 1;
}
greeter/grpc
protoc -I/usr/local/include -I. \
  -I../../ \
  -I../../github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
  --go_out=plugins=grpc:. \
  proto/greeter.proto
protoc -I/usr/local/include -I. \
  -I../../ \
  -I../../github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
  --grpc-gateway_out=logtostderr=true:. \
  proto/greeter.proto
grpcmain.go
package main

import (
    "flag"
    "github.com/golang/glog"
    "github.com/grpc-ecosystem/grpc-gateway/runtime"
    "golang.org/x/net/context"
    "google.golang.org/grpc"
    greeter "greeter/grpc/proto"
    "net/http"
)

var (
    // greeter 服务运行地址和端口
    endpoint = flag.String("endpoint", "localhost:9090", "greeter service address")
)

func run() error {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()

    mux := runtime.NewServeMux()
    opts := []grpc.DialOption{grpc.WithInsecure()}

    err := greeter.RegisterGreeterHandlerFromEndpoint(ctx, mux, *endpoint, opts)
    if err != nil {
        return err
    }

    return http.ListenAndServe(":8080", mux)
}

func main() {
    flag.Parse()

    defer glog.Flush()

    if err := run(); err != nil {
        glog.Fatal(err)
    }
}

测试服务调用

至此,我们就已经完成了 gRPC 后台服务和网关代码的编写,最后我们来简单测试下通过 gRPC 网关对 gRPC 服务进行调用。

我们基于 Consul 作为注册中心,所以要现在系统中确保 Consul 已经启动:

consul agent -dev
localhost:9090greeter/grpc
go run ../main.go --registry=consul --server_address=localhost:9090

启动 gRPC 服务

通过启动日志可以看到 Server 运行在 grpcServer 之上,服务也已经注册成功:

查看服务是否注册

greeter/grpc
go run main.go

如果没有报错,即表示启动成功,最后我们可以新开一个 Terminal 窗口通过 curl 命令模拟客户端请求:

客户端请求

localhost:8080