GRPC 网关

本篇主要帮助大家在go-micro服务中使用grpc网关。

GRPC网关grpc-gatewayprotoc的一个插件。它遵循gRPC中的服务定义,生成反向代理服务,这个代理就会把RESTful风格的JSON API转成gRPC请求。

我们使用go-grpc写后台服务。Go-GRPC是客户端与服务端的go-micro、grpc插件包装器。当调用grpc.NewService时,它会返回micro.Service服务。

代码

可以在examples/grpc中查找相关代码。

预置条件

我们需要下面准备工作:

安装protobuf

  1. mkdir tmp
  2. cd tmp
  3. git clone https://github.com/google/protobuf
  4. cd protobuf
  5. ./autogen.sh
  6. ./configure
  7. make
  8. make check
  9. sudo make install

安装插件

  1. go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
  2. go get -u github.com/micro/protobuf/protoc-gen-go

Greeter Service

例子中我们使用go-grpc创建了简单的greeter微服务。

下面的proto文件的代码:

  1. syntax = "proto3";
  2. package go.micro.srv.greeter;
  3. service Say {
  4. rpc Hello(Request) returns (Response) {}
  5. }
  6. message Request {
  7. string name = 1;
  8. }
  9. message Response {
  10. string msg = 1;
  11. }

服务的Go代码:

  1. package main
  2. import (
  3. "log"
  4. "time"
  5. hello "github.com/micro/examples/greeter/srv/proto/hello"
  6. "github.com/micro/go-grpc"
  7. "github.com/micro/go-micro"
  8. "golang.org/x/net/context"
  9. )
  10. type Say struct{}
  11. func (s *Say) Hello(ctx context.Context, req *hello.Request, rsp *hello.Response) error {
  12. log.Print("Received Say.Hello request")
  13. rsp.Msg = "Hello " + req.Name
  14. return nil
  15. }
  16. func main() {
  17. service := grpc.NewService(
  18. micro.Name("go.micro.srv.greeter"),
  19. micro.RegisterTTL(time.Second*30),
  20. micro.RegisterInterval(time.Second*10),
  21. )
  22. // optionally setup command line usage
  23. service.Init()
  24. // Register Handlers
  25. hello.RegisterSayHandler(service.Server(), new(Say))
  26. // Run server
  27. if err := service.Run(); err != nil {
  28. log.Fatal(err)
  29. }
  30. }

GRPC Gateway

GRPC网关使用相同的proto文件配上http选项提供服务

  1. syntax = "proto3";
  2. package greeter;
  3. import "google/api/annotations.proto";
  4. service Say {
  5. rpc Hello(Request) returns (Response) {
  6. option (google.api.http) = {
  7. post: "/greeter/hello"
  8. body: "*"
  9. };
  10. }
  11. }
  12. message Request {
  13. string name = 1;
  14. }
  15. message Response {
  16. string msg = 1;
  17. }

通过下面的proto命令生成grpc的存根和反向代理

  1. protoc -I/usr/local/include -I. \
  2. -I$GOPATH/src \
  3. -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
  4. --go_out=plugins=grpc:. \
  5. path/to/your_service.proto
  1. protoc -I/usr/local/include -I. \
  2. -I$GOPATH/src \
  3. -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
  4. --grpc-gateway_out=logtostderr=true:. \
  5. path/to/your_service.proto

在下面的代码中我们写了一个简单的问候(greeter)服务API。类似的代码也会用来注册其它的端点。切记,网关需要端点地址及服务。

  1. package main
  2. import (
  3. "flag"
  4. "net/http"
  5. "github.com/golang/glog"
  6. "github.com/grpc-ecosystem/grpc-gateway/runtime"
  7. "golang.org/x/net/context"
  8. "google.golang.org/grpc"
  9. hello "github.com/micro/examples/grpc/gateway/proto/hello"
  10. )
  11. var (
  12. // the go.micro.srv.greeter address
  13. endpoint = flag.String("endpoint", "localhost:9090", "go.micro.srv.greeter address")
  14. )
  15. func run() error {
  16. ctx := context.Background()
  17. ctx, cancel := context.WithCancel(ctx)
  18. defer cancel()
  19. mux := runtime.NewServeMux()
  20. opts := []grpc.DialOption{grpc.WithInsecure()}
  21. err := hello.RegisterSayHandlerFromEndpoint(ctx, mux, *endpoint, opts)
  22. if err != nil {
  23. return err
  24. }
  25. return http.ListenAndServe(":8080", mux)
  26. }
  27. func main() {
  28. flag.Parse()
  29. defer glog.Flush()
  30. if err := run(); err != nil {
  31. glog.Fatal(err)
  32. }
  33. }

运行示例

现在运行greeter服务,指定mdns参数,因为现在我们还没有注册中心。

  1. go run examples/grpc/greeter/srv/main.go --registry=mdns --server_address=localhost:9090

运行网关程序,把greeter服务所有端点都放在localhost:9090

  1. go run examples/grpc/gateway/main.go

用Curl命令请求网关

  1. curl -d '{"name": "john"}' http://localhost:8080/greeter/hello

局限性

我们需要向gRPC网关提供使用了服务发现、动态路由、负载均衡的后台micro api服务所在的地址。这降低了集成网关的通用性。

参考github.com/micro/micro了解更多。