尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Envoy HTTP 全局限流过滤器(HTTP Rate Limit Filter)实战指南:配置、Descriptor 编排与源码原理

Envoy HTTP 全局限流过滤器(HTTP Rate Limit Filter)实战指南:配置、Descriptor 编排与源码原理 Envoy HTTP 全局限流过滤器HTTP Rate Limit Filter实战指南配置、Descriptor 编排与源码原理【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy本文是 Envoy 中HTTP 全局限流过滤器envoy.filters.http.ratelimit的完整技术指南。它面向希望把请求级限流下发给外部 gRPC 限流服务、实现多实例全局一致的限流策略的网关与代理开发者围绕 rate_limit_filter.rst 展开结合 rate_limit.proto、route_components.proto 与 ratelimit.cc 源码讲解过滤器如何被触发、Descriptor 如何由 Action 编排生成、限流判定后如何返回 429/500、如何输出统计与动态元数据。读完本文你将能独立完成从过滤器声明、路由级限流策略到自定义 Descriptor 扩展的完整配置并理解其底层实现。前置全局限流的架构定位在进入过滤器配置之前先明确它属于 Envoy 全局限流Global Rate Limiting体系。与分布式熔断circuit breaking不同全局限流适合大量下游主机向少数上游转发、单机熔断阈值难以全局统一的场景典型如数据库连接池。其架构概览见 global_rate_limiting.rstEnvoy 通过 gRPC 与一个外部限流服务通信服务端按 Envoy 提交的domain descriptor判定是否超限。Envoy 提供两类全局限流入口网络层过滤器在监听器上对每个新建连接调用限流服务连接级限流HTTP 层过滤器即本文主角在路由表指定调用全局限流服务时对每个 HTTP 请求调用限流服务请求级限流。同时 Envoy 还支持 本地限流local rate limit官方建议两者搭配本地令牌桶先粗粒度吸收突发流量全局限流再做细粒度校准形成两级限流。过滤器声明与核心配置项HTTP 限流过滤器使用类型 URLtype.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit其 proto 定义位于 rate_limit.proto对应的实现文件为 ratelimit.cc 与 config.cc。一个最小的过滤器声明如下http_filters: - name: envoy.filters.http.ratelimit typed_config: type: type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit domain: foo enable_retry_after_header: true rate_limit_service: transport_api_version: V3 grpc_service: envoy_grpc: cluster_name: rate_limit_service下面是 proto 中定义的核心字段及其语义均为当前仓库 rate_limit.proto 的官方说明字段类型默认/约束说明domainstring必填min_len: 1调用限流服务时使用的限流域名服务端用它区分不同租户/场景stageuint320取值范围 0–10过滤器只处理路由或虚拟主机上stage相同的限流配置request_typestringboth过滤器生效的请求类型internal/external/both。内部请求指x-envoy-internal为 true 的请求timeoutDuration20ms限流服务 RPC 超时设为 0 表示无限不超时failure_mode_denyboolfalse限流服务不可达/报错时是否失败关闭拒绝流量返回 500failure_mode_deny_percentRuntimeFractionalPercent未设置用运行时百分比覆盖failure_mode_deny实现50% 拒绝、50% 放行的灰度失败策略rate_limit_serviceRateLimitServiceConfig必填外部限流服务连接配置gRPC 集群等未配置则调用立即成功rate_limited_statusHttpStatus429被限流时返回给下游的自定义状态码若配置 400 则仍用 429status_on_errorHttpStatus500限流服务出错且failure_mode_deny开启时返回的状态码disable_x_envoy_ratelimited_headerboolfalse置 true 后不再输出x-envoy-ratelimited头头缺失时请求可能被视为可重试enable_x_ratelimit_headersenumOFF启用 draft RFC 03 风格的X-RateLimit-Limit/Remaining/Reset头response_headers_to_add列表最多 10 项对被限流请求的每个响应追加的 HTTP 头rate_limited_as_resource_exhaustedboolfalse对 gRPC 请求被限流时返回RESOURCE_EXHAUSTED而非默认UNAVAILABLEHTTP 码仍为 200stat_prefixstring空统计名前缀用于区分过滤器链中多个 ratelimit 过滤器filter_enabled/filter_enforcedRuntimeFractionalPercent未设置分别控制对多少比例的请求发起限流检查与对多少比例的限流结果执行未设置时回退到运行时键metadata_namespacestringenvoy.filters.http.ratelimit限流响应动态元数据的存储命名空间enable_retry_after_headerboolfalse见下文Retry-After 头rate_limits列表空在过滤器上直接内嵌限流配置优先于路由/虚拟主机级配置过滤器的工作流程源码视角从 ratelimit.cc 的initiateCall()可以看出触发逻辑先按request_type判断请求内外部类型不匹配直接放行通过populateRateLimitDescriptors()基于当前请求上下文生成 descriptor 列表只要 descriptor 非空就调用限流客户端client_-limit()发起异步 gRPC 调用并进入Calling状态暂停解码直至收到限流服务响应。在complete()ratelimit.cc中按限流服务返回的状态分派OK递增ok计数继续转发OverLimit递增over_limit计数按配置写入x-envoy-ratelimited头并调用sendLocalReply()返回rate_limited_status默认 429Error若failure_mode_deny或运行时百分比为真则返回status_on_error默认 500并标记RateLimitServiceError响应标志否则放行并递增failure_mode_allowed计数。timeout在 config.cc 中被解析未配置时取PROTOBUF_GET_MS_OR_DEFAULT(proto_config, timeout, 20)即默认 20ms0 转换为nullopt无限超时。过滤器工厂通过LEGACY_REGISTER_FACTORY(..., envoy.rate_limit)注册config.cc。Descriptor 与 Action 编排Composing Actions基本概念限流服务按descriptor判定限流。一个 descriptor 是若干 descriptor entry 的向量形如(key, value)。路由或虚拟主机上的每一条 :ref:限流配置RateLimitenvoy_v3_api_msg_config.route.v3.RateLimit包含一个或多个action每个 action 生成一个 descriptor entry所有 entry 按配置书写顺序依次追加组成最终的 descriptor。如果某个 action 无法追加 entry见下文示例 2则该配置不会生成 descriptor即跳过本次限流检查。RateLimit消息与RateLimit.Action的完整字段定义在 route_components.proto。当前支持的内置 Action 包括Action生成的 descriptor entry说明source_cluster(source_cluster, 本地服务集群)来自--service-cluster启动参数destination_cluster(destination_cluster, 路由目标集群)来自cluster/weighted_clusters/cluster_headerrequest_headers(descriptor_key, 请求头值)按header_name取请求头值skip_if_absent控制头缺失时的行为query_parameters(descriptor_key, 查询参数值)按query_parameter_name取查询参数值remote_address(remote_address, x-forwarded-for 中的可信地址)依赖可信转发的客户端地址masked_remote_address(masked_remote_address, 掩码后的地址)IPv4 掩码长度默认 32、IPv6 默认 128可分别用v4_prefix_mask_len/v6_prefix_mask_len调整如 /24 得到192.168.1.0/24generic_key(generic_key, descriptor_value)静态值支持访问日志格式符替换header_value_match/query_parameter_value_match按匹配结果生成仅当请求头/查询参数匹配指定条件如expect_match、value、正则时才追加 entrydynamic_metadata(descriptor_key, 动态元数据值)从 stream 动态元数据取值extension由扩展决定自定义 descriptor producer见后文每条限流配置还可附带stage匹配过滤器 stage默认 0、disable_key设置运行时键ratelimit.disable_key.http_filter_enabled可动态关闭该条配置、limitoverride见下文、hits_addend按固定值或格式化串增加每次请求的命中数上限 10 亿is_negative_hits可让其为负值用于回补配额。示例 1组合两个 Action目标 descriptor(generic_key, some_value0) (source_cluster, from_cluster)对应的路由配置见 rate-limit-routes.yaml 的/route0routes: - match: prefix: /route0 route: host_rewrite_literal: upstream.com cluster: upstream_com rate_limits: - actions: - source_cluster: {} - generic_key: descriptor_value: some_value0注意 action 的书写顺序就是 entry 的追加顺序先source_cluster得到(source_cluster, from_cluster)再generic_key得到(generic_key, some_value0)与目标 descriptor 完全一致。若两者顺序颠倒生成的 descriptor 也会颠倒导致服务端规则不匹配——顺序敏感是编排 descriptor 时的关键约束。示例 2Action 不追加 entry 时整个 descriptor 被丢弃/route1的配置rate-limit-routes.yamlrate_limits: - actions: - source_cluster: {} - remote_address: {} - generic_key: descriptor_value: some_value1remote_address取的是x-forwarded-for中的可信地址。因此请求未携带x-forwarded-for→remote_address无法生成 entry → 整个配置不产生 descriptor本次请求不会调用限流服务请求携带x-forwarded-for→ 生成完整 descriptor(generic_key, some_value1) (remote_address, trusted address from x-forwarded-for) (source_cluster, from_cluster)Rate Limit Override动态覆盖服务端静态配额每条限流配置可通过limit字段route_components.proto附带一个override把限流额度直接追加进 descriptor 一起发给限流服务从而覆盖服务端静态配置的阈值。override 有两种来源dynamic_metadata从指定 MetadataKey 下的动态元数据读取rate_limit静态覆盖直接指定requests_per_unit与unit。动态元数据方式要求取值是含整数字段requests_per_unit与字符串字段unit的结构且unit必须可解析为RateLimitUnit枚举如HOUR、SECOND、MINUTE、DAY等。若 key 不存在或取值不合法override 会被静默忽略退回服务端静态配置。/route2的示例rate-limit-routes.yamlrate_limits: - actions: - generic_key: descriptor_value: some_value2 limit: dynamic_metadata: metadata_key: key: test.filter.key path: - key: test配合如下动态元数据例如由前置过滤器写入test.filter.key命名空间test.filter.key: test: requests_per_unit: 42 unit: HOUR此时限流服务会收到一个42 次/小时的 override并将其附加到some_value2的 descriptor 上。该机制常用于按用户/租户维度下发个性化配额。Descriptor 扩展自定义 descriptor producerdescriptor 是可扩展的除内置 Action 外还支持通过extension引入自定义 producer计算 descriptorexpr 扩展使用envoy.extensions.rate_limit_descriptors.expr.v3.Descriptor可将任意 请求属性如request.method作为 descriptor 值。/route3的示例rate-limit-routes.yamlrate_limits: - actions: - extension: name: custom typed_config: type: type.googleapis.com/envoy.extensions.rate_limit_descriptors.expr.v3.Descriptor descriptor_key: my_descriptor_name text: request.method请求为POST时生成 entry(my_descriptor_name, POST)实现按 HTTP 方法维度限流。HTTP 匹配输入matching input扩展可直接把 HTTP matching input 函数 当作 descriptor producer。/route4的示例rate-limit-routes.yamlrate_limits: - actions: - extension: name: custom typed_config: type: type.googleapis.com/envoy.type.matcher.v3.HttpRequestHeaderMatchInput header_name: x-header-name该配置生成 key 为custom、value 为请求头x-header-name取值的 entry。边界行为请求头缺失 → 不生成 entry整个 descriptor 不产生跳过限流检查请求头存在但值为空字符串 → descriptor 正常生成但不追加该 entry。限流响应的头与状态码语义x-envoy-ratelimited 头只要任一 descriptor 被判定超限过滤器就返回rate_limited_status默认 429并设置x-envoy-ratelimited: true响应头除非disable_x_envoy_ratelimited_header为 true。该头的作用是告诉调用方这次 429 是限流导致的若去掉它请求可能被重试逻辑视为可重试。对应实现见 ratelimit.cc。Retry-After 头当enable_retry_after_header为 true 且过滤器执行了 429 限流时响应会携带Retry-After头取值为限流服务返回的所有超限 descriptor 状态中最大的duration_until_reset秒且最小钳制为 1 秒。这样保证延迟足够长能让服务端上报的每个超限规则都完成重置。需要注意的头行为限流服务若自行返回Retry-After头过滤器不会覆盖它以下情况不输出该头上游自身产生的 429非过滤器限流、未执行限流、配置了非 429 的自定义rate_limited_status、服务端未返回任何超限 descriptor 状态该选项默认关闭。对应配置示例过滤器级domain: foo enable_retry_after_header: true rate_limit_service: transport_api_version: V3 grpc_service: envoy_grpc: cluster_name: rate_limit_service自定义状态码与响应头rate_limited_status允许把 429 换成其他状态码但 400 的值会被强制回退为 429status_on_error决定限流服务出错且失败关闭时返回的状态默认 500response_headers_to_add可为每个被限流的响应追加最多 10 个自定义头如携带用户可见的配额提示。统计指标Statistics限流过滤器在命名空间cluster.route target cluster.ratelimit.optional stat prefix.下输出计数器429或配置的rate_limited_status响应会同时计入所在集群的动态 HTTP 统计。核心指标如下名称类型说明okCounter限流服务返回未超限的响应总数errorCounter联系限流服务时出错的总次数over_limitCounter限流服务返回超限的响应总数failure_mode_allowedCounter出错但被放行的请求总数failure_mode_deny为 false 时这些计数在 ratelimit.cc 中随状态分派递增failure_mode_allowed仅在 Error 且config_-failureModeAllow()为真时递增ratelimit.cc。动态元数据输出当限流服务返回的RateLimitResponse填充了dynamic_metadata字段时过滤器会以不透明的google.protobuf.Struct形式把它写入请求的流动态元数据默认命名空间为envoy.filters.http.ratelimit可通过过滤器配置的metadata_namespace修改。写入逻辑见 ratelimit.cc仅当dynamic_metadata非空时执行setDynamicMetadata()。下游过滤器或 access log、外部鉴权等即可基于该元数据做后续决策。运行时Runtime控制过滤器支持以下运行时设置运行时键作用默认值ratelimit.route_key.http_filter_enabled对给定route_key的请求中调用限流服务的百分比route_key来自限流配置的disable_key字段100此外过滤器配置中的filter_enabled/filter_enforced分别映射到运行时键ratelimit.http_filter_enabled与ratelimit.http_filter_enforcing默认 100%用于灰度量级放量failure_mode_deny_percent使用键ratelimit.failure_mode_deny_percent覆盖failure_mode_deny。这些运行时判断的兜底实现见 ratelimit.cc。路由/虚拟主机级配置与优先级限流配置可以挂在三个层级ratelimit.cc 中的populateRateLimitDescriptors()明确了优先级typed_per_filter_configRoute/VirtualHost 上的RateLimitPerRoute中内嵌的rate_limits优先级最高若存在则完全忽略路由与虚拟主机级配置其domain字段还会覆盖过滤器级 domain其次是过滤器配置RateLimit自带的rate_limits字段proto 第 17 字段设置后忽略路由/虚拟主机级配置注意此层级不支持stage、dynamic_metadataaction、disable_key与limitoverride 四个能力最后是路由RouteAction.rate_limits与虚拟主机VirtualHost.rate_limits级配置其中路由可通过include_vh_rate_limits选择是否附带虚拟主机配置。RateLimitPerRoute还提供vh_rate_limits枚举控制虚拟主机级限流的并入策略rate_limit.protoOVERRIDE默认路由有自有限流策略时使用路由的否则回退虚拟主机INCLUDE即使路由有策略也同时并入虚拟主机策略IGNORE忽略虚拟主机策略。每一条限流配置只要命中过滤器stage都会生成一个独立 descriptor 发送给限流服务因此一个请求可以匹配多条配置、触发多次限流判定最终只要任一 descriptor 超限就返回 429。完整可运行示例把上述要素拼装成一个端到端可验证的配置完整版本见 rate-limit-routes.yamlstatic_resources: listeners: - name: listener_0 address: socket_address: protocol: TCP address: 0.0.0.0 port_value: 10000 filter_chains: - filters: - name: envoy.filters.network.http_connection_manager typed_config: type: type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager stat_prefix: ingress_http route_config: name: local_route virtual_hosts: - name: local_service domains: [*] routes: - match: prefix: /route0 route: host_rewrite_literal: upstream.com cluster: upstream_com rate_limits: - actions: - source_cluster: {} - generic_key: descriptor_value: some_value0 http_filters: - name: envoy.filters.http.ratelimit typed_config: type: type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit domain: foo rate_limit_service: transport_api_version: V3 grpc_service: envoy_grpc: cluster_name: rate_limit_service - name: envoy.filters.http.router typed_config: type: type.googleapis.com/envoy.extensions.filters.http.router.v3.Router clusters: - name: upstream_com type: LOGICAL_DNS dns_lookup_family: V4_ONLY lb_policy: ROUND_ROBIN load_assignment: cluster_name: service_upstream_com endpoints: - lb_endpoints: - endpoint: address: socket_address: address: upstream.com port_value: 443 transport_socket: name: envoy.transport_sockets.tls typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext sni: upstream.com注意过滤器链中限流过滤器必须放在router 过滤器之前这与complete()中sendLocalReply直接终结请求的实现一致若已转发则无法本地回复。限流服务端如 Envoy 官方提供的 Go 参考实现基于 Redis 后端需要按domain descriptor配置对应的限流规则Envoy 侧只负责生成 descriptor 并转发判定结果。小结Envoy HTTP 全局限流过滤器的核心心智模型可以概括为三句话descriptor 决定一切路由/虚拟主机/过滤器内嵌配置中的 action 按序组装 descriptor任何 action 失败都会使该条配置整体跳过extension 与 override 让 descriptor 具备按请求属性、动态元数据个性化生成的能力判定结果决定行为超限 → 429 x-envoy-ratelimited可选Retry-After、自定义状态码与响应头服务不可达 → 默认 500 失败关闭或按运行时百分比放行可观测性完备ok / error / over_limit / failure_mode_allowed四类计数 动态元数据输出配合运行时键即可在不停机的情况下灰度调整限流启用比例与执行比例。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表