花椒服务端 gRPC 开发实践
基于标准化的 IDL(ProtoBuf)来生成服务器端和客户端代码,支持多种主流开发语言。同时可以更好的支持团队与团队之间的接口设计,开发,测试,协作等。
基于 HTTP/2 设计,支持双向流,多路复用,头部压缩。
支持流式发送和响应,批量传输数据,提升性能。
ProtoBuf 序列化数据抓包、调试难度较大。我们使用服务端注入方式提供了用户或设备过滤,请求及返回值日志捕获,并开发对应后台模拟抓包展示。
相比 JSON, 对前端不够友好。gRPC 生态提供了 Gateway 的方式为 gRPC 服务代理出 RESTful 接口。
ProtoBuf 提供了非常强的扩展性,可以为 protoc 开发定制插件,从而扩展 proto 文件的功能及描述性。
HTTP 源 IP 添加到 gRPC 的 X-Forwarded-For 请求头
HTTP 请求 Host 添加到 gRPC 的 X-Forwarded-Host 请求头
HTTP 请求头 Authorization 添加到 gRPC 的 authorization 请求头
HTTP 请求头带 Grpc-Metadata- 前缀的映射到 gRPC 的 metadata(key 名不带前缀)
GET /index HTTP/1.1
grpc-metadata-platform: ios
grpc-metadata-device_id: xxxxxxxxx
grpc-metadata-timestamp: 1562641496
grpc-metadata-locale: en_US
grpc-metadata-version: 1.0.0
grpc-metadata-user_id:
grpc-metadata-user_token:
Host: gateway.hostame.com
var base = BaseClient(host: 'rpc.hostame.com', port: 443, secure: true);
final md = await base.metadata;
final stub = AuthClient(base.channel, options: CallOptions(metadata: md));
svrMux := &ServerMux{
...
ServeMux: http.NewServeMux(),
}
svrMux.svr = grpc.NewServer(
grpc.UnaryInterceptor(
middleware.ChainUnaryServer(
recovery.UnaryServerInterceptor(recovery.WithRecoveryHandler(svrMux.recoveryHandler)),
prometheus.UnaryServerInterceptor, // prometheus 统计
svrMux.UnaryResponseInterceptor(),
proto.UnaryServerInterceptor(), // metadata 解析
log.UnaryServerInterceptor(conf.GlobalCallback()), // 访问日志
auth.UnaryServerInterceptor(conf.GlobalCallback()), // 接口鉴权
validator.UnaryServerInterceptor(), // 请求参数校验
)),
grpc.StreamInterceptor(
middleware.ChainStreamServer(
...
)))
svrMux.mux = runtime.NewServeMux(
runtime.WithMarshalerOption(runtime.MIMEWildcard, json.Proto), // json 设置
runtime.WithProtoErrorHandler(svrMux.protoErrorHandler), // 错误处理
runtime.WithStreamErrorHandler(svrMux.streamErrorHandler),
)
// gRPC gateway mux
svrMux.ServeMux.Handle("/", svrMux.mux)
github.com/golang/protobuf
github.com/grpc-ecosystem/go-grpc-middleware
github.com/grpc-ecosystem/go-grpc-prometheus
github.com/grpc-ecosystem/grpc-gateway
github.com/lnnujxxy/protoc-gen-validate
github.com/youlu-cn/grpc-gen
go.uber.org/zap
google.golang.org/grpc
type Component interface {
// 组件名称
Name() string
// 初始化存储
InitStorage() error
// 初始化注册 gRPC
InitGRPC(svc Service) error
// 初始化注册 gateway
InitGateway(svc Service) error
// cron 回调
StorageCron()
}
base.Init(context.TODO(), cfg, &global.Callback{
Authenticator: &auth.Callback{},
LogCapture: &log.Capture{},
})
base.DefaultServer.AddPublicServer(rpcPort, gatewayPort, setting.TLSConfig)
base.DefaultServer.RegisterComponent(&user.Component{})
base.DefaultServer.RegisterComponent(&push.Component{})
...
base.DefaultServer.Serve()
// 消息类型注释,支持多行,
// 支持 markdown 语法:
//
// > blockquote
//
// | Syntax | Description |
// | ----------- | ----------- |
// | Header | Title |
// | Paragraph | Text |
message ExampleMessage {
uint64 id = 1; // 字段注释,简洁
}
// 服务说明,支持 markdown 语法
//
// 1. First item
// 2. Second item
// 3. Third item
//
// ```json
// {
// "firstName": "John",
// "lastName": "Smith",
// "age": 25
// }
// ```
service Example {
option (auth.visible) = {
scope: PUBLIC_SCOPE // Service scope:仅内网可见或对外可见
};
// 方法说明,支持 markdown
//
// - [x] Write the press release
// - [ ] Update the website
// - [ ] Contact the media
rpc test (ExampleMessage) returns (ExampleMessage) {
option (auth.access) = {
level: LOW_ACCESS_LEVEL // 接口请求权限
};
option (google.api.http) = {
post: "/example/test"
body: "*"
};
}
}
gengo:
@protoc -Iproto \
-I${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
-I${GOPATH}/src/github.com/lnnujxxy/protoc-gen-validate \
-I${GOPATH}/src/github.com/youlu-cn/grpc-gen/protoc-gen-auth \
--go_out=plugins=grpc:go/pb \
--grpc-gateway_out=logtostderr=true:go/pb \
--validate_out="lang=go:go/pb" \
--auth_out="lang=go:go/pb" \
proto/*.proto
ifeq ($(shell uname), Darwin)
PROTO_ROOT_DIR = $(shell brew --prefix)/Cellar/protobuf/*
else
PROTO_ROOT_DIR = /usr/local
endif
gendart:
@protoc --dart_out=dart/front_user/lib/src/generated $(PROTO_ROOT_DIR)/include/google/protobuf/*.proto
@protoc -Iproto \
-I${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
-I${GOPATH}/src/github.com/lnnujxxy/protoc-gen-validate \
-I${GOPATH}/src/github.com/youlu-cn/grpc-gen/protoc-gen-auth \
--dart_out=grpc:dart/user/lib proto/*.proto
dependencies:
flutter:
sdk: flutter
protobuf: ^0.13.4
grpc: ^1.0.1
user:
git:
url: [email protected]:project/repo.git
path: dart/user
gendoc:
@protoc -Iproto \
-I${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
-I${GOPATH}/src/github.com/lnnujxxy/protoc-gen-validate \
-I${GOPATH}/src/github.com/youlu-cn/grpc-gen/protoc-gen-auth \
--markdown_out=":doc" \
proto/*.proto
gRPC Streaming
框架层集成全链路 Trace 支持
迭代优化框架,提供对应脚手架,简化新组件/服务创建及开发流程