ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Higress cluster-key-rate-limit 插件:基于 Key 的 Redis 集群级限流配置全指南

Higress cluster-key-rate-limit 插件:基于 Key 的 Redis 集群级限流配置全指南 Higress cluster-key-rate-limit 插件基于 Key 的 Redis 集群级限流配置全指南【免费下载链接】higress AI Gateway | AI Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/hi/higresscluster-key-rate-limit是 Higress 内置的 Go 语言 Wasm 插件源码位于 plugins/wasm-go/extensions/cluster-key-rate-limit基于 Redis 实现集群级限流适用于需要跨多个 Higress Gateway 实例进行全局一致速率限制的场景。本文将完整讲解其三种限流模式、全部配置字段、源码级实现原理、可复制的配置示例与常见陷阱读完即可在生产环境正确配置、排障并理解其底层行为。功能说明该插件支持三种限流模式规则级全局限流基于相同的rule_name和global_threshold配置对整个自定义规则组施加统一的限流阈值Key 级动态限流根据请求中动态提取的 Key如 URL 参数、请求头、客户端 IP、Consumer 名称或 Cookie 字段进行分组限流混合限流同时配置global_threshold全局兜底和rule_items按维度细分所有命中的规则叠加生效任一触发即拒绝请求。运行属性插件执行阶段默认阶段Default phase插件执行优先级20行为变更说明无版本号变化⚠️ 自本次更新起rule_items的匹配语义从first-match-wins命中第一条即返回改为all-match OR 叠加所有命中规则都评估任一触发即拒绝。同时解除了global_threshold与rule_items的互斥约束支持混合配置。老配置单条rule_items或仅global_threshold行为不变老配置多条rule_items期望短路匹配行为会变——所有命中规则都会评估Redis key 格式新增{rule_name}hash tag 以兼容 Redis Cluster旧计数器数据不兼容。该行为在源码中有明确对应onHttpRequestHeaders通过collectMatchedRules一次性收集所有命中规则再通过单个 Lua 脚本原子执行多 key 的 check incr见 main.go任一计数器超过阈值即触发拒绝。配置说明配置项类型必填默认值说明rule_namestring是-限流规则名称用于构造 Redis key格式为rule_name:rate_limit_type:key_name:key_valueglobal_thresholdObject否global_threshold与rule_items至少配置一项可同时配置-对整个自定义规则组进行限流rule_itemsarray of object否至少一项可同时配置-限流规则项最多支持10 条。所有满足匹配条件的rule_item都会参与限流规则之间是或关系任一触发即拒绝规则的执行顺序不影响最终结果。详见下文rule_items多规则匹配语义show_limit_quota_headerbool否false响应头中是否显示X-RateLimit-Limit限制的总请求数和X-RateLimit-Remaining剩余还可以发送的请求数rejected_codeint否429请求被限流时返回的 HTTP 状态码rejected_msgstring否Too many requests请求被限流时返回的响应体redisobject是-Redis 相关配置global_threshold配置字段配置项类型必填默认值说明query_per_secondint否query_per_second、query_per_minute、query_per_hour、query_per_day中选填一项-允许每秒请求次数query_per_minuteint否同上-允许每分钟请求次数query_per_hourint否同上-允许每小时请求次数query_per_dayint否同上-允许每天请求次数从源码实现看config/config.go四个时间窗口字段是互斥的——解析时按map遍历顺序取第一个存在的字段阈值必须为正整数否则配置解析直接失败并返回明确错误。rule_items配置字段配置项类型必填默认值说明limit_by_headerstring否limit_by_*中选填一项-配置获取限流键值的来源 HTTP 请求头名称limit_by_paramstring否limit_by_*中选填一项-配置获取限流键值的来源 URL 参数名称limit_by_consumerstring否limit_by_*中选填一项-根据 Consumer 名称进行限流无需添加实际值limit_by_cookiestring否limit_by_*中选填一项-配置获取限流键值的来源 Cookie 中 key 名称limit_by_per_headerstring否limit_by_*中选填一项-按每个请求头值分别计算限流。limit_keys不能是字面量名称只接受*或regexp:...精确匹配请改用limit_by_header去掉per_limit_by_per_paramstring否limit_by_*中选填一项-按每个参数值分别计算限流。limit_keys只接受*或regexp:...精确匹配请改用limit_by_param去掉per_limit_by_per_consumerstring否limit_by_*中选填一项-按每个 Consumer 分别计算限流。limit_keys只接受*或regexp:...精确匹配请改用limit_by_consumer去掉per_limit_by_per_cookiestring否limit_by_*中选填一项-按每个 Cookie 值分别计算限流。limit_keys只接受*或regexp:...精确匹配请改用limit_by_cookie去掉per_limit_by_per_ipstring否limit_by_*中选填一项-选择客户端 IP 来源from-header-header_name或from-remote-addr。IP/CIDR 值放在limit_keys[].key中limit_keysarray of object是-配置匹配到的 key 值的限流阈值源码层面config/config.golimit_by_*字段在一个rule_item内只取第一个非空命中项limit_by_consumer/limit_by_per_consumer固定从请求头x-mse-consumer读取 Consumer 名称常量ConsumerHeader因此字段值本身可为空字符串limit_by_per_ip的取值必须以from-header-开头或恰好等于from-remote-addr否则解析报错。rule_items多规则匹配语义rule_items是一个数组。所有满足匹配条件的rule_item都会被评估规则之间是或关系任一触发即拒绝请求。规则的执行顺序不影响最终结果。rule_items数组最多支持10条源码常量MaxRuleItems 10见 config/config.go超过即报rule_items length N exceeds maximum 10。每条rule_item会为每个匹配的limit_keys产生独立的 Redis 计数器。多规则场景下的 X-RateLimit-* 响应头当多条规则同时命中但均未触发且show_limit_quota_header: true时X-RateLimit-Limit/X-RateLimit-Remaining取自剩余比例最小约束最紧的命中规则X-RateLimit-Reset触发限流时返回取自第一个触发的规则按rule_items数组顺序全局规则优先。该逻辑在 main.go 中通过比较(threshold - current) / threshold选出 tightest 规则实现。limit_keys配置字段配置项类型必填默认值说明keystring是-非per_类型接受精确字面量limit_by_per_header、limit_by_per_param、limit_by_per_consumer、limit_by_per_cookie只接受regexp:...或*limit_by_per_ip接受 IP 地址或 CIDR 网段query_per_secondint否query_per_second、query_per_minute、query_per_hour、query_per_day中选填一项-允许每秒请求次数query_per_minuteint否同上-允许每分钟请求次数query_per_hourint否同上-允许每小时请求次数query_per_dayint否同上-允许每天请求次数redis配置字段配置项类型必填默认值说明service_namestring是-Redis 服务的完整限定域名FQDN含服务类型例如my-redis.dns、redis.my-ns.svc.cluster.localservice_portint否静态服务 80其他服务 6379Redis 服务端口usernamestring否-Redis 认证用户名passwordstring否-Redis 认证密码timeoutint否1000毫秒Redis 连接超时时间毫秒databaseint否0使用的 Redis 数据库 ID如配置1对应SELECT 1端口默认逻辑在 config/config.go 中service_name以.static结尾时默认 80否则默认 6379。若控制台生成的静态服务实际指向 Redis 的 6379 端口需要显式配置service_port: 6379相关排查见 rate-limit-plugin-faq-en.md 第 4 节。源码级实现原理Redis key 结构与 Redis Cluster 兼容插件在 Redis 中的计数器 key 使用统一前缀higress-cluster-key-rate-limit并引入{rule_name}hash tag 保证同一规则组的多个 key 落在 Redis Cluster 的同一 slot从而支持多 key 原子操作见 main.go全局限流higress-cluster-key-rate-limit:{rule_name}:global_threshold:时间窗口规则限流higress-cluster-key-rate-limit:{rule_name}:限流类型:时间窗口:限流key名称:限流key对应的实际值这也是行为变更说明中旧计数器数据不兼容的原因——老格式 key 不带{rule_name}hash tag。单次往返原子计数MultiKeyFixedWindowScript请求处理阶段将全部命中规则的 key、阈值、窗口打包通过一个 Lua 脚本MultiKeyFixedWindowScript一次 RedisEVAL完成所有计数器的检查 自增对每个 key先get当前计数并取ttl若ttl 0则按窗口重置当前值超过阈值则不再自增直接返回{threshold, current, ttl}未超阈值则原子incr首次计数为 1 时设置expire窗口。脚本全文与调用入口见 main.go 与onHttpRequestHeaders。这种多规则合并一次 Redis 往返的设计正是混合模式与多规则叠加能够低开销落地的关键。限流维度提取逻辑hitRateRuleItemmain.go按限流类型提取实际值header 直接读请求头param 解析 URL 查询串取第一个值consumer 读x-mse-consumer请求头cookie 通过ExtractCookieValueByKey解析per_ip 从指定 header 或source.address属性取客户端 IP并用iptree做 IP/CIDR 匹配util/utils.go。非per_类型做精确字符串比较per_类型用*全匹配与预编译正则做选择器匹配。配置示例自定义规则组全局限流rule_name: routeA-global-limit-rule global_threshold: query_per_minute: 1000 # 该规则组每分钟最多 1000 次请求 redis: service_name: redis.static show_limit_quota_header: true按请求参数apikey限流rule_name: routeA-request-param-limit-rule rule_items: - limit_by_param: apikey limit_keys: - key: 9a342114-ba8a-11ec-b1bf-00163e1250b5 query_per_minute: 10 - key: a6a6d7f2-ba8a-11ec-bec2-00163e1250b5 query_per_hour: 100 - limit_by_per_param: apikey limit_keys: # 正则匹配所有以 a 开头的字符串每个 apikey 每秒 10 次 - key: regexp:^a.* query_per_second: 10 # 正则匹配所有以 b 开头的字符串每个 apikey 每分钟 100 次 - key: regexp:^b.* query_per_minute: 100 # 兜底规则匹配所有请求每个 apikey 每小时 1000 次 - key: * query_per_hour: 1000 redis: service_name: redis.static show_limit_quota_header: true该示例中两条rule_item精确值限流 正则/兜底限流同时命中时叠加生效完整复现了all-match OR语义。按请求头x-ca-key限流rule_name: routeA-request-header-limit-rule rule_items: - limit_by_header: x-ca-key limit_keys: - key: 102234 query_per_minute: 10 - key: 308239 query_per_hour: 10 - limit_by_per_header: x-ca-key limit_keys: # 正则匹配所有以 a 开头的字符串每个 key 每秒 10 次 - key: regexp:^a.* query_per_second: 10 # 正则匹配所有以 b 开头的字符串每个 key 每分钟 100 次 - key: regexp:^b.* query_per_minute: 100 # 兜底规则匹配所有请求每个 key 每小时 1000 次 - key: * query_per_hour: 1000 redis: service_name: redis.static show_limit_quota_header: true按从x-forwarded-for头提取的客户端 IP 限流rule_name: routeA-client-ip-limit-rule rule_items: - limit_by_per_ip: from-header-x-forwarded-for limit_keys: # 精确 IP 匹配 - key: 1.1.1.1 query_per_day: 10 # CIDR 网段匹配该网段内每个 IP 每天 100 次 - key: 1.1.1.0/24 query_per_day: 100 # 所有 IP 的兜底规则每个 IP 每天 1000 次 - key: 0.0.0.0/0 query_per_day: 1000 redis: service_name: redis.static show_limit_quota_header: true按 Consumer 限流rule_name: routeA-consumer-limit-rule rule_items: - limit_by_consumer: limit_keys: - key: consumer1 query_per_second: 10 - key: consumer2 query_per_hour: 100 - limit_by_per_consumer: limit_keys: # 正则匹配所有以 a 开头的 consumer 名称每个 consumer 每秒 10 次 - key: regexp:^a.* query_per_second: 10 # 正则匹配所有以 b 开头的 consumer 名称每个 consumer 每分钟 100 次 - key: regexp:^b.* query_per_minute: 100 # 兜底规则匹配所有 consumer每个 consumer 每小时 1000 次 - key: * query_per_hour: 1000 redis: service_name: redis.static show_limit_quota_header: true按 Cookie 值限流rule_name: routeA-cookie-limit-rule rule_items: - limit_by_cookie: key1 limit_keys: - key: value1 query_per_minute: 10 - key: value2 query_per_hour: 100 - limit_by_per_cookie: key1 limit_keys: # 正则匹配所有以 a 开头的 cookie 值每个值每秒 10 次 - key: regexp:^a.* query_per_second: 10 # 正则匹配所有以 b 开头的 cookie 值每个值每分钟 100 次 - key: regexp:^b.* query_per_minute: 100 # 兜底规则匹配所有 cookie 值每个值每小时 1000 次 - key: * query_per_hour: 1000 rejected_code: 200 rejected_msg: {code:-1,msg:Too many requests} redis: service_name: redis.static show_limit_quota_header: true此示例同时演示了自定义拒绝行为将rejected_code改为 200、rejected_msg改为 JSON 响应体适用于需要软限流业务自行解析响应体的网关场景。常见陷阱limit_by_per_consumer下使用字面量 consumer 名称per_*语义是为每个实际值建立独立配额桶其limit_keys是选择器只接受*或regexp:...精确字面量应使用非per_变体。# ❌ 错误per_consumer 的 limit_keys 只接受 * 或 regexp:... rule_items: - limit_by_per_consumer: limit_keys: - key: alice query_per_day: 100 # ✅ 正确精确名称匹配去掉 per_ rule_items: - limit_by_consumer: limit_keys: - key: alice query_per_day: 100对应的解析报错形如the limit_by_per_consumer restriction must start with regexp: or be exactly * (got alice); to match an exact name, use the non-per variant limit_by_consumer instead (limit_keys stay the same)。CIDR 放进limit_by_per_ip字段limit_by_per_ip只负责选择 IP 来源from-header-name或from-remote-addr它不是 CIDR 字段IP/CIDR 必须放进limit_keys[].key。# ❌ 错误limit_by_per_ip 选择 IP 来源不是 CIDR 字段 rule_items: - limit_by_per_ip: 0.0.0.0/0 # ✅ 正确把 CIDR 放进 limit_keys rule_items: - limit_by_per_ip: from-remote-addr limit_keys: - key: 0.0.0.0/0 query_per_day: 1000缺少limit_keys每条rule_item都必须提供至少一个limit_keys条目及请求阈值否则整条规则被解析器拒绝# ❌ 错误整个 rule_item 被拒绝 rule_items: - limit_by_per_ip: from-remote-addr # ✅ 正确至少提供一个 key 和请求阈值 rule_items: - limit_by_per_ip: from-remote-addr limit_keys: - key: 0.0.0.0/0 query_per_day: 1000缺失时报错会附带该类型的最小合法示例如missing limit_keys in config for limit_by_per_ip; add at least one entry, e.g. key: 0.0.0.0/0该示例由exampleLimitKeyForType按类型生成config/config.go。per_*与非per_*的选择速查目标字段limit_keys[].key限制单个精确 header 值limit_by_header字面量每个 header 值分别限流limit_by_per_header*或regexp:...限制单个精确参数值limit_by_param字面量每个参数值分别限流limit_by_per_param*或regexp:...限制单个精确 consumerlimit_by_consumerConsumer 字面量每个 consumer 分别限流limit_by_per_consumer*或regexp:...限制单个精确 Cookie 值limit_by_cookie字面量每个 Cookie 值分别限流limit_by_per_cookie*或regexp:...limit_by_per_ip特殊它选择 IP 来源CIDR 仍放在limit_keys。诊断完整的限流排查配方见 Rate-limit Plugin FAQ适用于cluster-key-rate-limit与ai-token-ratelimit两个插件。以下是速查表症状优先检查请求始终返回 200Redis 中没有限流 key没有规则命中或配置解析失败导致规则未加载Redis cluster 的cx_connect_fail大于 0端口、凭据或网络连通性Wasm 的update_rejected/config_fail持续增长解析器拒绝了推送的配置需查看具体的网关日志报错kubectl -n higress-system logs gateway-pod --tail2000 \ | grep -Ei cluster-key-rate-limit|limit_by_per_|missing limit_keys|must start with补充要点config_dump中能看到配置只证明控制面已下发不代表数据面插件已加载生效需要结合/stats、/clusters和网关日志交叉验证通过SCAN未发现限流 key单独并不构成 Redis 故障证据——规则未命中或数据面解析拒绝也会导致无 key 产生Redis 集群名由service_name与service_port推导为outbound|port||service_name排查连接问题时先在/clusters中定位该条目诊断命令速查curl -s 127.0.0.1:15000/stats?filterwasm|redis|update_rejected|config_fail|cx_查看 Wasm 配置与 Redis 连接指标redis-cli --scan --pattern *ratelimit*在生产环境用 SCAN 而非阻塞式 KEYS。测试与配置契约的保障该插件的配置契约由单元测试与集成测试双重锁定config/config_test.go 覆盖缺失rule_name、负阈值、缺limit_keys、rule_items超过 10 条、缺失limit_by_*字段、自定义rejected_code/rejected_msg、show_limit_quota_header、以及全局 规则混合配置等场景TestParseClusterKeyRateLimitConfig_ActionableLimitKeyErrors验证错误信息必须包含可操作的修正建议如per_变体迁移提示、CIDR 示例main_test.go 通过 mock Redis 验证global_threshold、limit_by_param、limit_by_header、limit_by_consumer等维度的请求处理与拒绝行为。FAQ 的开发者章节rate-limit-plugin-faq-en.md 第 6 节明确了该插件的语义契约非per_类型把limit_keys当作精确值非 IP 的per_*类型把它们当作*/正则选择器limit_by_per_ip把字段当作 IP 来源而limit_keys当作 IP/CIDR 值——理解这一契约是正确配置与排障的前提。【免费下载链接】higress AI Gateway | AI Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/hi/higress创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表