摘要:路由表指定应为安装过滤器的侦听器上的每个新请求调用一个服务。 采用令牌桶算法进行限流。
本博客是深入研究 Envoy Proxy 和 Istio.io 并解释如何以更复杂的方式连接和管理微服务的系列文章的一部分。部门。
以下是接下来几部分的一些想法(链接发布后我将立即更新):
断路器(第 1 部分)
重新尝试/超时(第 2 部分)
分布式跟踪(第 3 部分)
收集 Prometheus 指标(第 4 部分)
速率限制器(第 5 部分)
p>第 5 部分 - 速率限制器Envoy 速率限制过滤器
Envoy 通过两个过滤器与 Ratelimit 服务集成:
网络级别过滤器:Envoy 调用 Ratelimit 服务来: 对于安装了过滤器的侦听器上的每个新连接。 这样就可以通过监听器限制每秒的连接数。
HTTP 级别过滤器:Envoy 为安装了过滤器的侦听器上的每个新请求调用 Ratelimit 服务。 路由表指定应调用 Ratelimit 服务。 大量工作用于扩展 HTTP 过滤器的功能。
envoy 配置启用 http 速率限制器
http 速率限制器 与请求的路由或虚拟主机的过滤器阶段设置相匹配的一个或多个速率限制器设置 如果是这样,过滤器将调用 HTTP速率限制器。 限速服务。 该路由可以选择包括虚拟主机的速率限制配置。 可以将多个配置应用于单个请求。 每个配置都会向速率限制服务发送一个描述符。
如果调用限速服务并且任何描述符的响应超出限制,则返回429响应。 速率限制过滤器还设置 x-envoy-ratelimited 标头。
如果对速率限制服务的调用遇到错误,或者速率限制服务返回错误且 failure_mode_deny 设置为 true,则返回 500 响应。
整体配置如下。
envoy.yaml: |- static_resources:listeners:- 地址:socket_address: 地址:0.0.0.0 port_value:8000 filter_chains: - 过滤器: - 名称: envoy.http_connection_manager 配置: codec_type: auto stat_prefix: ingress_http access_log: - 名称: envoy.file_access_log 配置: 路径: "/dev/stdout" 格式: "[ACCESS_LOG][%START_TIME] %] "%REQ(:METHOD)% %REQ( X-ENVOY-ORIGINAL-PATH?:PATH)%%PROTOCOL%"%RESPONSE_CODE%%RESPONSE_FLAGS%%BYTES_RECEIVED%%BYTES_SENT%%DURATION%%RESP(-服务-时间)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ (:AUTHORITY)%" "%UPSTREAM_HOST%" "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%"" Route_config: name: local_route virtual_hosts: - name: 网关域: - "*" Route: - 匹配: 前缀: "/cost "route:cluster:costrate_limits:#启用greeter服务的速率限制检查操作:-destination_cluster:{} http_filters:-name:envoy.rate_limit#启用速率限制过滤器设置:域:envoy - 名称:envoy.router 配置:{} 集群:- 名称:Cost connect_timeout:0.25 秒 类型:strict_dns lb_policy:round_robin 主机:- 套接字地址:address:cost.sgt 端口值:80 - 名称:rate_limit_cluster 类型:strict_dns connect_timeout:0.25 秒 lb_policy:round_robin http2_protocol_options:{} 主机:- 套接字地址:地址:limiter.sgt port_value:80rate_limit_service:grpc_service:envoy_grpc:集群名称:rate_limit_cluster 超时:0.25 秒管理员:Access_Log_Path:“/dev/null”地址:socket_address:address: 0.0.0.0 port_value: 9000
从配置文件中可以看到,这个demo配置了一个全局的http过滤速率限制器。
分布式线路阻塞通常对于控制分布式系统的吞吐量非常有效,但在某些情况下效果较差,需要全局速率限制。 最常见的情况是当大量主机转发到少量主机并且平均请求延迟较低时(例如,到数据库服务器的连接/请求)。 如果目标主机有备份,则下游主机会洪泛上游集群。 在这种情况下,如果系统开始出现故障,则很难在每个下游主机上设置足够严格的断路限制以防止级联故障,同时仍然允许系统针对典型的请求模式正常运行。 全局速率限制很好地解决了这种情况。
写入速率限制器服务
Envoy 通过 gRPC 直接与速率限制器服务集成。 Envoy 需要支持 rls.proto 中指定的 gRPC IDL 的速率限制服务。 有关 API 如何工作的更多信息,请参阅 IDL 文档。
Envoy 本身只提供了限流接口,并没有具体的实现,所以你必须自己实现限流器。 下面是一个简单的实现,可以给您一个想法。
具体代码如下。
package mainimport ( "log" "net" "time" rls "github.com/envoyproxy/go-control-plane /envoy /service/ratelimit/v2" "github.com/ juju/ratelimit" "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/reflection") //服务器用于实现rls.RateLimitServicetype。 每秒限制请求数 var totalCode rls.RateLimitResponse_Code if s.bucket.TakeAvailable(1) == 0 {overallCode = rls.RateLimitResponse_OVER_LIMIT } else {overallCode = rls.RateLimitResponse_OK } 将返回 Response := &rls.RateLimitResponse{OverallCode:overallCode} 。 nil}func main() { // 在端口 8089 创建 TCP 监听 lis, err := net.Listen("tcp", ":8089") if err != nil { log.Fatalf("监听失败 did: % v", err) } log.Printf("listening on %s", lis.Addr()) // 创建一个 gRPC 服务器并注册 RateLimitService 服务器 s := grpc.NewServer() rls.RegisterRateLimitServiceServer(s, &server{bucket:ratelimit.NewBucket(100*time.Microsecond, 100), })reflection.Register(s) if err := s .Serve (squirrel); err != nil { log.Fatalf("failed toserve: %v", err) }}
检查 github 上的具体项目。
PS:
采用令牌桶算法来限制当前流量。 令牌桶和漏桶算法效果相同但方向相反,更容易理解。 随着时间的推移,系统以固定的 1/QPS 时间间隔移动到桶中(对于 QPS=100,间隔为 10 毫秒),并将令牌添加到桶中(想象一下泄漏的逆过程)有一个水龙头(这意味着您不断加水)。 如果桶已满,则不会再添加令牌。 当新的请求到来时,令牌就会被窃取。 如果没有可获取的代币,您将被阻止。 或拒绝服务。
此实现存在单点风险。
Dockerfile 全部位于代码存储库中,因此您可以构建映像并自行测试。
结论
本文简要介绍了 Envoy 的限流功能,提供了全局限流配置文件,并提供了一种简单的方法来实现基于令牌桶的限流器。 我们希望这可以帮助您了解 Envoy 的速率限制过滤器如何与 gRPC 协议配合使用。
评论前必须登录!
注册