mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-29 22:06:38 +08:00
80c47f6ff3
在站点详情流量限制中配置 limit_req_per_ip;渲染按 effective rate 生成多 limit_req_zone,并以站点+IP 隔离计数。
6.0 KiB
6.0 KiB
站点级访问频率限制设计
日期:2026-07-20
状态:已评审待实现
方案:站点详情 Limits 暴露 limit_req_per_ip;渲染时按 effective rate 生成多 limit_req_zone,并用站点键隔离 IP 计数
背景
全局默认已有:
openresty_default_limit_conn_per_serveropenresty_default_limit_conn_per_ipopenresty_default_limit_rateopenresty_default_limit_req_per_ip
站点级并发/带宽已在「反代站点详情 → 流量限制」中配置,语义为:空/0 继承、-1 关闭、自定义覆盖。
请求频率(limit_req)后端字段与 merge 已存在,但:
- 前端站点详情未暴露
limit_req_per_ip - 渲染侧仅在全局默认非空时输出单一
limit_req_zone ... rate=全局值,站点自定义 rate 无法真正独立生效(nginx 的 rate 写在 zone 上,不能仅靠 location 覆盖)
目标
- 在仅站点详情「流量限制」区块配置单 IP 请求频率。
- 语义与现有三项一致:空/
0继承全局;-1关闭;合法Nr/s/Nr/m为站点自定义。 - 站点自定义 rate 真正按该 rate 生效(A 站 5r/s、B 站 10r/s 互不影响)。
- 同 IP 在不同站点的频率配额按站点隔离。
- 修改后仍需发布配置版本;Agent 使用与 Server 同源的 render 路径。
非目标
- 在「安全性 → 限流」页增加按站点列表编辑
- 新建站点表单中的频率字段
- 按路径 / URI 差异化频率限制
- 改变
limit_conn_*/limit_rate的现有 zone 与合并模型 - 业务 Zone(顶级域 + 二级域名资源)模型变更
语义
站点字段 limit_req_per_ip(字符串)
| 值 | 含义 |
|---|---|
空 / "0" |
继承全局 openresty_default_limit_req_per_ip |
"-1" |
本站显式关闭频率限制 |
^\d+r/[sm]$(大小写不敏感,存小写) |
本站自定义 rate |
全局默认
| 值 | 含义 |
|---|---|
空 / "0" |
默认关闭;继承方亦不输出 limit_req |
| 合法 rate | 未配置站点的 effective rate |
合并(与现有 mergeLimitRate 一致)
if route == -1: effective = off
else if route is set: effective = route // 合法 rate
else: effective = global // route 空/0
// global 空/0 → off
渲染
问题
nginx limit_req_zone 的 rate= 在 zone 声明时固定;多个站点若 effective rate 不同,必须使用不同 zone。
步骤
- 在
RenderRouteConfig/ main 配置生成前,对全部 route 计算 effectiveLimitReqPerIP。 - 收集非空 effective rate 的去重集合,在
http {}(renderOpenRestyLimitZoneBlock扩展,需能访问 routes 或 precomputed rates)输出:
# 变量键:站点名 + IP,保证跨站点计数隔离
# 实现可用 map 或在 server 内 set 后引用;zone key 采用组合键
limit_req_zone $openflare_req_key zone=openflare_req_<rate_token>:10m rate=<rate>;
rate_token 由 rate 规范化生成(如 10r/s → 10rs,100r/m → 100rm),仅作 zone 名片段,合法 nginx zone 名。
- 每个业务 server 在 access 相关位置之前设置:
set $openflare_req_key "$openflare_waf_site$binary_remote_addr";
(与现有 set $openflare_waf_site "..." 同源 site_name;若某 server 无 waf site 变量则用同一 displayName/site_name。)
renderRouteLimitBlock在 effective rate 非空时输出:
limit_req zone=openflare_req_<rate_token> burst=<calculateBurst> nodelay;
limit_req_status 429;
-
无任何 effective rate 时:不输出任何
limit_req_zone/limit_req(避免引用不存在的 zone)。 -
应用范围与现有 limit 块一致:HTTP/HTTPS 反代
location /、Pages 相关 location;不含 HTTP→HTTPS 重定向-only server。
与旧行为差异
| 项 | 旧 | 新 |
|---|---|---|
| zone 数量 | 全局最多 1 个 | 按不同 effective rate 多个 |
| zone key | $binary_remote_addr |
$openflare_req_key(站点+IP) |
| 站点自定义 rate | 无法真正独立 | 引用对应 rate 的 zone |
快照 JSON 仍保留站点原始值(含空/-1),不把 merge 结果写回 route。
数据与 API
- 列
of_proxy_routes.limit_req_per_ip已存在;无新迁移(若环境已跑过既有迁移)。 - API
Input/View已有字段;normalize / 校验已存在。 - 前端类型与详情表单补齐即可。
前端
仅改站点详情 limits-section.tsx:
- 增加「单 IP 请求频率」输入
- 校验:空、
0、-1、或^\d+r/[sm]$i - 规范化:trim + lower;
0→"" ProxyRouteItem/ProxyRouteMutationPayload增加limit_req_per_ipbuildPayloadFromRoute带上该字段,避免其它区块保存时丢失
文案:与并发/带宽一致(空或 0 继承;-1 关闭;例如 10r/s、100r/m 自定义)。
Agent / 发布
- 配置保存后须发布配置版本
- Agent 本地
RenderJSON;必须部署含本设计 render 的 Agent,否则 source 有字段但 conf 无指令 - 若 Agent 已记录同 version/checksum,升级二进制后需触发重新 apply(重启或强制重同步)
测试
mergeRouteLimitConfig:继承 / 覆盖 /-1(已有则补 rate 断言)- 多站点不同 effective rate:main conf 含多个
limit_req_zone,各 location 引用正确 zone 名 - 全关闭:无
limit_req相关指令 - 仅全局有值:一个 zone + 未自定义站点引用该 zone
- 前端类型与表单校验(手工或既有模式)
验收
- 全局
10r/s,站点空 → 该站 location 有 limit_req,zone rate=10r/s - 站点改
5r/s并发布 → 该站引用 5r/s zone - 站点
-1→ 该站无 limit_req - 两站不同 rate,同 IP 压测互不抢同一配额
实现边界
| 层 | 工作量 |
|---|---|
渲染 pkg/render/openresty |
多 zone + 站点键 + location 引用 |
| 前端详情 Limits + types + payload | 补字段 |
| 后端 API/DB | 已具备,仅回归 |
| 文档/changelog | 用户可见变更记中文 changelog |