程序印象

gRPC 之 Interceptors

2018/09/01 Share

gRPC 环境安装 Mac

由于仓库已经转到 github,命令 go get -u google.golang.org/grpc 已经不能正常工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$ brew install libtool
$ brew install automake

# install proto3
$ mkdir tmp
$ cd tmp
$ git clone https://github.com/google/protobuf
$ cd protobuf
$ ./autogen.sh
$ ./configure
$ make
$ make check
$ sudo make install

# install go-grpc, 由于仓库已经转到 github,因此下面命令不能正常工作
# $ go get -u google.golang.org/grpc
$ git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc
$ git clone https://github.com/golang/net.git $GOPATH/src/golang.org/x/net
$ git clone https://github.com/golang/text.git $GOPATH/src/golang.org/x/text
$ git clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto

# $ git clone https://github.com/golang/crypto.git $GOPATH/src/golang.org/x/crypto
# $ git clone https://github.com/golang/sys.git $GOPATH/src/golang.org/x/sys

$ cd $GOPATH/src/ && go install google.golang.org/grpc

$ go get -u github.com/golang/protobuf/{proto,protoc-gen-go}

# go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
# go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
$ go get -u github.com/golang/protobuf/protoc-gen-go

gPRC Interceptors

当前实现的 Interceptors 包括 Auth/Log/Monitor/Trace 等。(auth, logging , trace,message, validation, retries or monitoring),大本营: https://github.com/grpc-ecosystem/go-grpc-middleware

类型两种:

  • UnaryInterceptor
  • StreamInterceptor

常见拦截器列表如下:

  1. Go gRPC Middleware: 提供了拦截器的interceptor链式的功能,可以将多个拦截器组合成一个拦截器链,当然它还提供了其它的功能,所以以gRPC中间件命名。
  2. grpc-multi-interceptor: 是另一个interceptor链式功能的库,也可以将单向的或者流式的拦截器组合。
  3. grpc_auth: 身份验证拦截器
  4. grpc_ctxtags: 为上下文增加Tag map对象
  5. grpc_zap: 支持zap日志框架
  6. grpc_logrus: 支持logrus日志框架
  7. grpc_prometheus: 支持 prometheus
  8. otgrpc: 支持opentracing/zipkin
  9. grpc_opentracing:支持opentracing/zipkin
  10. grpc_retry: 为客户端增加重试的功能
  11. grpc_validator: 为服务器端增加校验的功能
  12. xrequestid: 将request id 设置到context中
  13. go-grpc-interceptor: 解析Accept-Language并设置到context
  14. requestdump: 输出request/response

Prometheus 样例如下:

添加了 Zipkin 与 Logger 的代码样例:

client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package main

import (
"log"
"os"
"time"

"golang.org/x/net/context"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"

)

const (
address = "localhost:50051"
defaultName = "world"
)

func main() {

// Set up a connection to the server.
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBalancerName())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)

// Contact the server and print out its response.
name := defaultName
if len(os.Args) > 1 {
name = os.Args[1]
}

ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.Message)
}

server.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package main

import (
"log"
"net"

"golang.org/x/net/context"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
"google.golang.org/grpc/reflection"
"github.com/sirupsen/logrus"
"github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
"github.com/grpc-ecosystem/go-grpc-middleware"
"github.com/grpc-ecosystem/go-grpc-middleware/tags"

"github.com/opentracing/opentracing-go"
zipkin "github.com/openzipkin-contrib/zipkin-go-opentracing"
"fmt"
"os"
"github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing"
)

const (
port = ":50051"
)

// server is used to implement helloworld.GreeterServer.
type server struct{}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}

var (
logrusLogger *logrus.Logger
customFunc grpc_logrus.CodeToLevel
)

func init(){
// docker run -d -p 9411:9411 -p 9410:9410 openzipkin/zipkin

// create collector.
collector, err := zipkin.NewHTTPCollector("http://localhost:9411/api/v1/spans")
if err != nil {
fmt.Printf("unable to create Zipkin HTTP collector: %+v\n", err)
os.Exit(-1)
}

// create recorder.
recorder := zipkin.NewRecorder(collector, false, "127.0.0.1:50051", "greeter_server")

// create tracer.
tracer, err := zipkin.NewTracer(
recorder,
zipkin.ClientServerSameSpan(true),
zipkin.TraceID128Bit(true),
)
if err != nil {
fmt.Printf("unable to create Zipkin tracer: %+v\n", err)
os.Exit(-1)
}

// explicitly set our tracer to be the default tracer.
opentracing.InitGlobalTracer(tracer)
}

func main() {

// Logrus entry is used, allowing pre-definition of certain fields by the user.
logrusLogger = logrus.New()
logrusLogger.SetFormatter(&logrus.JSONFormatter{})
logrusEntry := logrus.NewEntry(logrusLogger)
// Shared options for the logger, with a custom gRPC code to log level function.

customFunc = grpc_logrus.DefaultCodeToLevel
opts := []grpc_logrus.Option{
grpc_logrus.WithLevels(customFunc),
}

// Shared options for the logger, with a custom duration to log field function.
//opts := []grpc_logrus.Option{
// grpc_logrus.WithDurationField(func(duration time.Duration) (key string, value interface{}) {
// return "grpc.time_ns", duration.Nanoseconds()
// }),
//}

// Make sure that log statements internal to gRPC library are logged using the logrus Logger as well.
grpc_logrus.ReplaceGrpcLogger(logrusEntry)

lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}

// Create a server, make sure we put the grpc_ctxtags context before everything else.
s := grpc.NewServer(
grpc_middleware.WithUnaryServerChain(
grpc_ctxtags.UnaryServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
grpc_logrus.UnaryServerInterceptor(logrusEntry, opts...),
grpc_opentracing.UnaryServerInterceptor(),
),
grpc_middleware.WithStreamServerChain(
grpc_ctxtags.StreamServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
grpc_logrus.StreamServerInterceptor(logrusEntry, opts...),
grpc_opentracing.StreamServerInterceptor(),

),
)

// s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
// Register reflection service on gRPC server.
reflection.Register(s)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}

server 端的产奖配置可以如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import "github.com/grpc-ecosystem/go-grpc-middleware"

myServer := grpc.NewServer(
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
grpc_ctxtags.StreamServerInterceptor(),
grpc_opentracing.StreamServerInterceptor(),
grpc_prometheus.StreamServerInterceptor,
grpc_zap.StreamServerInterceptor(zapLogger),
grpc_auth.StreamServerInterceptor(myAuthFunction),
grpc_recovery.StreamServerInterceptor(),
)),
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
grpc_ctxtags.UnaryServerInterceptor(),
grpc_opentracing.UnaryServerInterceptor(),
grpc_prometheus.UnaryServerInterceptor,
grpc_zap.UnaryServerInterceptor(zapLogger),
grpc_auth.UnaryServerInterceptor(myAuthFunction),
grpc_recovery.UnaryServerInterceptor(),
)),
)

分类如下:

Auth

  • grpc_auth - a customizable (via AuthFunc) piece of auth middleware

Logging

  • grpc_ctxtags - a library that adds a Tag map to context, with data populated from request body
  • grpc_zap - integration of zap logging library into gRPC handlers.
  • grpc_logrus - integration of logrus logging library into gRPC handlers.

Monitoring

Client

  • grpc_retry - a generic gRPC response code retry mechanism, client-side middleware

Server

参考

  1. Golang gRPC实践 连载五 拦截器 Interceptor
  2. Writing gRPC Interceptors in Go
CATALOG
  1. 1. gRPC 环境安装 Mac
  2. 2. gPRC Interceptors
    1. 2.0.1. Auth
    2. 2.0.2. Logging
    3. 2.0.3. Monitoring
    4. 2.0.4. Client
    5. 2.0.5. Server
  • 3. 参考