grpc-ecosystem/go-grpc-middleware
GitHub: grpc-ecosystem/go-grpc-middleware
该项目为 Go 语言的 gRPC 提供了一套开箱即用的拦截器中间件库,涵盖认证、可观测性、重试和限流等通用功能,帮助开发者以链式调用的方式统一管理微服务的横切关注点。
Stars: 6760 | Forks: 744
# Go gRPC Middleware
[](https://github.com/grpc-ecosystem/go-grpc-middleware/actions?query=branch%3Av2) [](https://goreportcard.com/report/github.com/grpc-ecosystem/go-grpc-middleware) [](https://godoc.org/github.com/grpc-ecosystem/go-grpc-middleware/v2) [](LICENSE) [](https://gophers.slack.com/archives/CNJL30P4P)
本仓库包含了 [gRPC Go](https://github.com/grpc/grpc-go) 中间件:拦截器、辅助工具和实用程序。
## 中间件
[gRPC Go](https://github.com/grpc/grpc-go) 支持“拦截器”,即在 gRPC 服务器上将请求传递给用户应用程序逻辑之前执行,或者在 gRPC 客户端上围绕用户调用执行的[中间件](https://medium.com/@matryer/writing-middleware-in-golang-and-how-go-makes-it-so-much-fun-4375c1246e81#.gv7tdlghs)。这是实现通用模式的绝佳方式:认证、日志记录、链路追踪、指标监控、验证、重试、速率限制等,它们可以作为出色的通用构建块,让你能够轻松构建多个微服务。
特别是对于可观测性信号(日志记录、链路追踪、指标监控),拦截器提供了半自动化的插桩(instrumentation)功能,这不仅提高了可观测性的一致性,还允许使用出色的关联技术(例如,日志中的 exemplars 和 trace ID)。演示请参见[示例](examples)。
本仓库提供了实现 gRPC 拦截器的现成中间件及示例。在某些情况下,专门的项目已经提供了出色的拦截器,因此本仓库不再包含这些内容,我们会在[拦截器](#interceptors)列表中附上它们的链接。
拦截器的另一个出色特性是支持链式调用。例如,你可以在下面找到一个包含完整可观测性关联、认证和 panic 恢复的服务器端拦截器链示例:
```
grpcSrv := grpc.NewServer(
grpc.StatsHandler(otelgrpc.NewServerHandler()),
grpc.ChainUnaryInterceptor(
srvMetrics.UnaryServerInterceptor(
grpcprom.WithExemplarFromContext(exemplarFromContext),
grpcprom.WithLabelsFromContext(labelsFromContext),
),
logging.UnaryServerInterceptor(interceptorLogger(rpcLogger), logging.WithFieldsFromContext(logTraceID)),
selector.UnaryServerInterceptor(auth.UnaryServerInterceptor(authFn), selector.MatchFunc(allButHealthZ)),
recovery.UnaryServerInterceptor(recovery.WithRecoveryHandler(grpcPanicRecoveryHandler)),
),
grpc.ChainStreamInterceptor(
srvMetrics.StreamServerInterceptor(
grpcprom.WithExemplarFromContext(exemplarFromContext),
grpcprom.WithLabelsFromContext(labelsFromContext),
),
logging.StreamServerInterceptor(interceptorLogger(rpcLogger), logging.WithFieldsFromContext(logTraceID)),
selector.StreamServerInterceptor(auth.StreamServerInterceptor(authFn), selector.MatchFunc(allButHealthZ)),
recovery.StreamServerInterceptor(recovery.WithRecoveryHandler(grpcPanicRecoveryHandler)),
),
)
```
这种模式为你所有的 gRPC 方法提供了干净且显式的共享功能。完整的、可编译的示例可以在[示例](examples)目录中找到。
## 拦截器
此列表涵盖了用户在 Go 微服务中使用的已知拦截器(包括本仓库内和外部项目)。点击每一项可以查看 `examples_test.go` 中的扩展示例(也可在 [pkg.go.dev](https://godoc.org/github.com/grpc-ecosystem/go-grpc-middleware/v2) 上找到)。
所有路径都应支持使用 `go get `。
#### 认证
- [`github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth`](interceptors/auth) - 可通过 `AuthFunc` 自定义的认证中间件。
- (外部) [`google.golang.org/grpc/authz`](https://github.com/grpc/grpc-go/blob/master/authz/grpc_authz_server_interceptors.go) - 更复杂、可通过认证策略(类似 RBAC)进行自定义的认证中间件。
#### 可观测性
- 指标:
- [`github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus`⚡](providers/prometheus) - 客户端和服务器端的 Prometheus 监控中间件。支持 exemplars。现已从弃用的 [`go-grpc-prometheus`](https://github.com/grpc-ecosystem/go-grpc-prometheus) 迁移。
- (外部) [`go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc`](https://go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc) - 官方 OpenTelemetry 拦截器(指标和链路追踪)。
- 使用 [`github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging`](interceptors/logging) 进行日志记录 - 提供扩展按请求日志记录的可自定义日志中间件。它需要日志适配器,请参阅 [`interceptors/logging/examples`](interceptors/logging/examples) 中的示例,支持 `go-kit`、`log`、`logr`、`logrus`、`slog`、`zap` 和 `zerolog`。
- 注意:带有 [context](https://pkg.go.dev/context) 字段注入的拦截器需要在适配器函数之前进行链式调用。
- 链路追踪:
- (外部) [`go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc`](https://go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc) - [示例](examples)中所使用的官方 OpenTelemetry 拦截器(指标和链路追踪)。
- (外部) [`github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing`](https://pkg.go.dev/github.com/grpc-ecosystem/go-grpc-middleware@v1.4.0/tracing/opentracing) - 如果你仍然需要,可使用已弃用的 [OpenTracing](http://opentracing.io/) 客户端和服务器端拦截器!
#### 客户端
- [`github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/retry`](interceptors/retry) - 通用的 gRPC 响应码重试机制,客户端中间件。
- 注意:grpc-go 也支持带有高级策略的本地重试 (https://github.com/grpc/grpc-go/blob/v1.54.0/examples/features/retry/client/main.go)
- [`github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/timeout`](interceptors/timeout) - 通用的 gRPC 请求超时机制,客户端中间件。
#### 服务器端
- [`github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/validator`](interceptors/validator) - 基于 `.proto` 选项进行代码生成的入站消息验证。
- [`github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery`](interceptors/recovery) - 将 panic 转换为 gRPC 错误(请确保将其用作“最后”一个拦截器,以确保 panic 不会跳过其他拦截器)。
- [`github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/ratelimit`](interceptors/ratelimit) - 通过自定义限流器进行 gRPC 速率限制。
- [`github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/protovalidate`](interceptors/protovalidate) - 通过 [protovalidate-go](https://github.com/bufbuild/protovalidate) 基于 `.proto` 选项进行消息验证。
#### 过滤拦截器
- [`github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/selector`](interceptors/selector) - 允许用户在特定条件下(如匹配服务方法)选择指定的一个或多个拦截器。
## 前置条件
- **[Go](https://golang.org)**:支持最近**三个主要**[版本](https://golang.org/doc/devel/release.html)中的任意一个。
## 本仓库结构
主要的拦截器位于 [`interceptors` 目录](interceptors)的子目录中,例如 [`interceptors/validator`](interceptors/validator)、[`interceptors/auth`](interceptors/auth) 或 [`interceptors/logging`](interceptors/logging)。
某些拦截器或拦截器工具需要依赖于大量依赖项的特定代码。这些代码作为独立的 Go 模块放置在 `providers` 目录中,并具有独立的版本控制。例如,[`providers/prometheus`](providers/prometheus) 提供了指标中间件(目前没有“interceptor/metrics”)。单独的模块在 `go.mod` 中可能稍微难以发现和管理版本,但它使得核心拦截器在依赖项方面变得极其精简。
[`interceptors` 目录](interceptors)还包含了接受 [`Reporter`](interceptors/reporter.go) 接口的通用拦截器,该接口让你能够轻松创建自定义中间件。
你可能已经注意到,本仓库包含多个不同版本的模块([Go 模块特性](https://github.com/golang/go/wiki/Modules#faqs--multi-module-repositories))。当前模块请参阅 [versions.yaml](versions.yaml)。我们拥有版本为 2.x.y 的主模块以及版本较低的 providers 模块。由于主模块是 v2,其模块路径以 `v2` 结尾:
```
go get github.com/grpc-ecosystem/go-grpc-middleware/v2/
```
对于 providers 模块和包,由于它们是 v1,路径中没有添加版本号,例如:
```
go get github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus
```
## 相比 v1 的变更
[go-grpc-middleware v1](https://pkg.go.dev/github.com/grpc-ecosystem/go-grpc-middleware) 创建于 2015 年左右,并成为了 gRPC 用户的热门选择。然而,此后许多事情都发生了变化。v2 相比 v1 的主要变更如下:
- 在“providers”中提供了独立、多个 Go 模块的路径。如果需要,这允许将来为特定的中间件添加专门的 providers。这使得拦截器可以在不依赖核心框架地狱的情况下进行扩展(例如,如果你使用其他指标 provider,你真的想导入 prometheus 吗?)。这提供了更高的可扩展性。
- 移除了 Loggers。[`interceptors/logging`](interceptors/logging) 得到了简化,为每个 logger 编写适配器变得非常简单。为了方便起见,我们将在 [`interceptors/logging/examples`](interceptors/logging/examples) 中维护流行 providers 的示例,但这些示例旨在供复制使用,而不是直接导入。
- 移除了 `grpc_opentracing` 拦截器。这是因为链路追踪插桩已经演进。OpenTracing 已被弃用,OpenTelemetry 现在提供了一个[更出色的链路追踪拦截器](https://go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc)。
- 移除了 `grpc_ctxtags` 拦截器。可以使用 `logging.InjectFields` 将自定义标签添加到日志字段中。在实践中,用于添加日志字段的 Proto 选项显得很笨重,而且我们如今没看到它的任何用途,因此将其移除了。
- 从 https://github.com/grpc-ecosystem/go-grpc-prometheus 引入了最强大的拦截器之一(该仓库现已弃用)。这种整合使得维护更容易、使用更便捷,并且 API 保持一致。
- 移除了链式拦截器,因为 `grpc` 已经实现了一个。
- 迁移到了新的 proto API (google.golang.org/protobuf)。
- 移除了所有的“deciders”,即那些根据 gRPC 服务名称和方法(又称“fullMethodName”)决定操作行为的函数(!)。请使用 [`github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/selector`](interceptors/selector) 拦截器来选择什么方法、类型或服务应使用什么拦截器。
- 不再使用蛇形(snake case)命名的包名。我们现在使用具有单一词汇且意义明确的包名。如果包名发生冲突,我们建议添加 grpc 前缀,例如 `grpcprom "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus"`。
- 所有选项(如果有)均采用 `.With