资讯专栏INFORMATION COLUMN

使用Envoy 作Sidecar Proxy的微服务模式-5.rate limiter

CocoaChina / 990人阅读

摘要:为安装过滤器的侦听器上的每个新请求调用服务,路由表指定应调用服务。使用了令牌桶算法来限流。

本博客是深入研究Envoy Proxy和Istio.io 以及它如何实现更优雅的方式来连接和管理微服务系列文章的一部分。

这是接下来几个部分的想法(将在发布时更新链接):

断路器(第一部分)

重试/超时(第二部分)

分布式跟踪(第三部分)

Prometheus的指标收集(第四部分)

rate limiter(第五部分)

第五部分 - rate limiter Envoy ratelimit filters

Envoy通过两个过滤器与Ratelimit服务集成:

Network Level Filter: envoy为安装过滤器的侦听器上的每个新连接调用Ratelimit服务。这样,您可以对通过侦听器的每秒连接进行速率限制。

HTTP Level Filter:Envoy为安装过滤器的侦听器上的每个新请求调用Ratelimit服务,路由表指定应调用Ratelimit服务。许多工作都在扩展HTTP过滤器的功能。

envoy 配置 启用 http rate limiter

http rate limiter 当请求的路由或虚拟主机具有与过滤器阶段设置匹配的一个或多个速率限制配置时,HTTP速率限制过滤器将调用速率限制服务。该路由可以选择包括虚拟主机速率限制配置。多个配置可以应用于请求。每个配置都会导致将描述符发送到速率限制服务。

如果调用速率限制服务,并且任何描述符的响应超出限制,则返回429响应。速率限制过滤器还设置x-envoy-ratelimited标头。

果在呼叫速率限制服务中出现错误或速率限制服务返回错误并且failure_mode_deny设置为true,则返回500响应。

全部的配置如下:

  envoy.yaml: |-
    static_resources:
      listeners:
      - address:
          socket_address:
            address: 0.0.0.0
            port_value: 8000
        filter_chains:
        - filters:
          - name: envoy.http_connection_manager
            config:
              codec_type: auto
              stat_prefix: ingress_http
              access_log:
              - name: envoy.file_access_log
                config:
                  path: "/dev/stdout"
                  format: "[ACCESS_LOG][%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%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: gateway
                  domains:
                  - "*"
                  routes:
                  - match:
                      prefix: "/cost"
                    route:
                      cluster: cost
                  rate_limits: # enable rate limit checks for the greeter service
                    actions:
                    - destination_cluster: {}
              http_filters:
              - name: envoy.rate_limit # enable the Rate Limit filter
                config:
                  domain: envoy            
              - name: envoy.router
                config: {}
      clusters:
      - name: cost
        connect_timeout: 0.25s
        type: strict_dns
        lb_policy: round_robin
        hosts:
        - socket_address:
            address: cost.sgt
            port_value: 80
      - name: rate_limit_cluster
        type: strict_dns
        connect_timeout: 0.25s
        lb_policy: round_robin
        http2_protocol_options: {}
        hosts:
        - socket_address:
            address: limiter.sgt
            port_value: 80
    rate_limit_service:
        grpc_service:
            envoy_grpc:
                cluster_name: rate_limit_cluster
            timeout: 0.25s
    admin:
      access_log_path: "/dev/null"
      address:
        socket_address:
          address: 0.0.0.0
          port_value: 9000
          

通过配置文件可以看出,本demo设置的是一个全局的http filter rate limiter。

尽管分布式熔断通常在控制分布式系统中的吞吐量方面非常有效,但有时它不是非常有效并且需要全局速率限制。最常见的情况是当大量主机转发到少量主机并且平均请求延迟较低时(例如,对数据库服务器的连接/请求)。如果目标主机已备份,则下游主机将淹没上游群集。在这种情况下,在每个下游主机上配置足够严格的断路限制是非常困难的,这样系统在典型的请求模式期间将正常运行,但在系统开始出现故障时仍能防止级联故障。全局速率限制是这种情况的一个很好的解决方案。

编写rate limiter 服务

Envoy直接通过gRPC与速率限制服务集成。Envoy要求速率限制服务支持rls.proto中指定的gRPC IDL。有关API如何工作的更多信息,请参阅IDL文档。

本身envoy 只是提供了限流的接口,没有具体的实现,所以必须自己实现一个限流器。下面只是简单实现一下,给大家一个思路。

具体的代码如下:

package main

import (
    "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"
)

// server is used to implement rls.RateLimitService
type server struct {
    bucket *ratelimit.Bucket
}

func (s *server) ShouldRateLimit(ctx context.Context,
    request *rls.RateLimitRequest) (*rls.RateLimitResponse, error) {
    // logic to rate limit every second request
    var overallCode rls.RateLimitResponse_Code
    if s.bucket.TakeAvailable(1) == 0 {
        overallCode = rls.RateLimitResponse_OVER_LIMIT
    } else {
        overallCode = rls.RateLimitResponse_OK
    }

    response := &rls.RateLimitResponse{OverallCode: overallCode}
    return response, nil
}

func main() {
    // create a TCP listener on port 8089
    lis, err := net.Listen("tcp", ":8089")
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    log.Printf("listening on %s", lis.Addr())

    // create a gRPC server and register the RateLimitService server
    s := grpc.NewServer()

    rls.RegisterRateLimitServiceServer(s, &server{
        bucket: ratelimit.NewBucket(100*time.Microsecond, 100),
    })
    reflection.Register(s)
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

具体项目,查阅github。

PS:

使用了令牌桶算法来限流。令牌桶算法(Token Bucket)和 Leaky Bucket 效果一样但方向相反的算法,更加容易理解.随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token(想象和漏洞漏水相反,有个水龙头在不断的加水),如果桶已经满了就不再加了.新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务.

该实现存在单点风险。

Dockerfile均在代码仓库中,大家可以构建镜像自己测试。

结论

本文简单讲了envoy的 rate limit功能,提供了全局限流的配置文件,并简单实现了一个基于令牌桶的限流器。希望能帮助你理解Envoy的限速过滤器如何跟gRPC协议协同工作。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/33136.html

相关文章

  • 使用Envoy Sidecar Proxy的微服务模式-3.分布式追踪

    摘要:在第三部分中,我们将了解如何在服务网格中启用分布式跟踪。在此部署模型中,被部署为服务的在本例中为客户端。会在服务调用之间添加一些追踪,并发送到或您的跟踪提供商目前支持和。这些示例的上游服务是。 本博客是深入研究Envoy Proxy和Istio.io 以及它如何实现更优雅的方式来连接和管理微服务系列文章的一部分。 这是接下来几个部分的想法(将在发布时更新链接): 断路器(第一部分) ...

    Fundebug 评论0 收藏0
  • 使用Envoy Sidecar Proxy的微服务模式-2.超时和重试

    摘要:在第二部分中,我们将详细介绍如何启用其他弹性功能,如超时和重试。在此部署模型中,被部署为服务的在本例中为客户端。这些示例的上游服务是。它们可以帮助传播故障或对可能正在挣扎的内部服务造成类型攻击。此延迟应足以触发超时。 本博客是深入研究Envoy Proxy和Istio.io 以及它如何实现更优雅的方式来连接和管理微服务系列文章的一部分。 这是接下来几个部分的想法(将在发布时更新链接):...

    vibiu 评论0 收藏0
  • 使用Envoy Sidecar Proxy的微服务模式-1.熔断

    摘要:我们将直接向发送流量,以使其帮帮助处理熔断。让我们调用我们的服务我们将看到以下的输出我们也能看到我们五次的调用成功了。 本博客是深入研究Envoy Proxy和Istio.io 以及它如何实现更优雅的方式来连接和管理微服务系列文章的一部分。 这是接下来几个部分的想法(将在发布时更新链接): 断路器(第一部分) 重试/超时(第二部分) 分布式跟踪(第三部分) Prometheus的指标...

    NotFound 评论0 收藏0
  • 使用Envoy Sidecar Proxy的微服务模式-1.熔断

    摘要:我们将直接向发送流量,以使其帮帮助处理熔断。让我们调用我们的服务我们将看到以下的输出我们也能看到我们五次的调用成功了。 本博客是深入研究Envoy Proxy和Istio.io 以及它如何实现更优雅的方式来连接和管理微服务系列文章的一部分。 这是接下来几个部分的想法(将在发布时更新链接): 断路器(第一部分) 重试/超时(第二部分) 分布式跟踪(第三部分) Prometheus的指标...

    Drummor 评论0 收藏0
  • Kubernetes上的Service Mesh实践:用EnvoyFilter扩展Istio

    摘要:宋体宋体是在监听器配置完成之后执行的,用于向中插入用户自定义的。宋体宋体截止目前为止,平台上共有个应用通过提供服务,除了,同时针对其他网络资源也做了严格的隔离,以此来保证不同用户的服务的稳定性。KUN(中文名鲲)是 UCloud 面向内部的基于 Kubernetes 的资源交付平台,提供监控告警、CI/CD、网络双栈、Service Mesh 等能力。在践行 Service Mesh 理念的...

    endless_road 评论0 收藏0

发表评论

0条评论

CocoaChina

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<