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
编写 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
通过启动日志可以看到 Server 运行在 grpcServer 之上,服务也已经注册成功:
greeter/grpc
go run main.go
如果没有报错,即表示启动成功,最后我们可以新开一个 Terminal 窗口通过 curl 命令模拟客户端请求:
localhost:8080