mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-28 05:46:36 +08:00
600a7acdfb
- 删除未经验证的环境要求(Docker 版本号、浏览器条目)与括号废话 - 故障排查改为真实处理路径(升级→重新发布→强制同步→重建 Agent→提交 issue),删除仅开发时用的排障章节 - 删除设计文档中的测试与验收、实现检查清单、贡献者阅读建议等开发内容 - 修正与代码不符的事实:reset-passwd 命令名、证书续签窗口 7 天、Pages 检查间隔 1440 分钟、Relay vhost 端口 8080、SSO 仅支持 OIDC 等 - 去除口语化表述与无意义括号,改写「不是…而是…」句式 - 同步修正文档站链接锚点,构建验证通过
11 KiB
11 KiB
边缘缓存策略设计
你会学到:OpenFlare 边缘 proxy_cache 如何在「该缓存」与「不该缓存」之间对齐 Cloudflare 默认闭环:请求 eligible(扩展名/策略)× 响应可共享缓存(源站 Cache-Control / Expires / Set-Cookie),以及与过往过严请求旁路的差异。
本设计是 系统架构 中「基础缓存」的产品化专章;访问日志中的缓存结果见 观测数据模型 §3.5.1。
1. 目标与非目标
1.1 目标
- 开箱接近 CF 默认:路由开启缓存后,默认只缓存静态扩展名,不默认缓存 HTML;不因请求会话 Cookie / Authorization / 客户端 Cache-Control 一律 BYPASS。
- 该缓存的能命中:带登录 Cookie 的用户访问
/_app/**/*.js等静态资源可出现MISS→HIT。 - 不该缓存的仍挡住:策略不 eligible(等价 CF
DYNAMIC);源站private/no-store;响应带Set-Cookie不入库(对齐 CF OCC 默认);all为高级选项并文档警示。 - 无源站 freshness 时有默认 Edge TTL:对齐 CF 按状态码的默认 TTL(见 §3.5)。
- 可观测一致:继续依赖
$upstream_cache_status→cache_status明细三态。 - 兼容存量:旧路由
cache_policy=url映射为all;策略枚举与迁移规则保持 §5。
1.2 非目标(后续迭代)
- Cache Rules 表达式引擎
- 忽略源站
Cache-Control的强制 Edge TTL(CF Cache Rules「Ignore cache-control」) - Purge(按 URL/前缀/全站)
- 浏览器 TTL 改写、客户端
CF-Cache-Status响应头 - 完整 RFC 条件:
Authorization仅当响应含public/s-maxage/must-revalidate才缓存(需 Lua;本期删除请求侧一律旁路,依赖策略 + 源站头) - HEAD 转 GET 再缓存
- 命中率看板
2. Cloudflare 判定闭环(对齐基准)
CF 默认是 两段决策,不是「请求带 Cookie 就不缓存」。
2.1 阶段 A — 请求时 Eligible
| 条件 | CF 结果 |
|---|---|
| 非 GET | 默认不缓存 |
| 扩展名不在默认可缓存表,且无 Rules 强制 Eligible | DYNAMIC(不查缓存) |
| 扩展名在默认表,或 Rules Eligible | 继续阶段 B |
| 请求 Cookie | 默认不影响 |
| Cache Rules Bypass | DYNAMIC |
CF 默认可缓存扩展名按 扩展名 而非 MIME;默认不缓存 HTML / JSON。
2.2 阶段 B — 响应是否可入库(OCC on,Free/Pro/Biz 默认)
| 条件 | 结果 |
|---|---|
Cache-Control: no-store / private |
不入库 |
public + max-age>0,或未来 Expires |
可缓存 |
| 无 Cache-Control / Expires | 按状态码 默认 Edge TTL 仍可缓存(如 200 → 120m) |
响应 Set-Cookie(默认缓存级别 + OCC) |
不入库,状态倾向 BYPASS |
请求 Authorization |
仅当响应另有 public / s-maxage / must-revalidate 才可缓存(完整条件本期用 Nginx 简化,见 §3.4) |
2.3 状态语义(对照观测)
| CF | 含义 | OpenFlare cache_status |
|---|---|---|
| HIT / STALE / UPDATING / REVALIDATED | 命中类 | 同名或等价 |
| MISS / EXPIRED | 回源取内容 | 同名 |
| BYPASS | 请求时 eligible,响应不可缓存 | BYPASS → UI「未缓存」 |
| DYNAMIC | 请求时不 eligible | 策略 skip 多为 BYPASS 或空 → UI「未缓存」 |
3. 产品语义
3.1 双层开关(不变)
- 全局
openresty_cache_enabled:生成proxy_cache_path等;关闭则路由级缓存指令不生效。 - 路由
cache_enabled:是否在该站点location启用proxy_cache。
两者均开启时才进入缓存逻辑。
3.2 策略枚举
cache_policy |
含义 | 新建默认 | 旧值兼容 |
|---|---|---|---|
static |
仅 URI 匹配标准静态扩展名才 eligible | 是 | — |
all |
过方法旁路后,不限制路径/扩展名(高级,风险类似 CF Cache Everything) | 否 | 存量 url → all |
suffix |
自定义扩展名列表(cache_rules) |
否 | 保持 |
path_prefix |
自定义路径前缀 | 否 | 保持 |
path_exact |
自定义精确路径 | 否 | 保持 |
渲染层:历史值 url 按 all 处理;API/UI 只暴露上表枚举。
3.3 标准静态扩展名(内置)
对齐 CF 默认「不缓存 HTML/JSON」;保留现代前端常用增强项:
css js mjs map
ico cur gif jpg jpeg png webp avif svg svgz
ttf otf woff woff2 eot
mp3 mp4 webm ogg flac
wasm pdf
zip 7z gz tar
- 不含
html/htm/json(对齐 CF 默认不缓存 JSON)。 - 含
map/mjs/wasm(有意增强,提高 sourcemap / ES module / WASM 命中)。 - 匹配:
$uri扩展名,大小写不敏感:
if ($uri !~* \.(?:css|js|…)$) { set $openflare_skip_cache 1; }
3.4 请求侧旁路(对齐 CF 后)
仅保留:
$request_method != GET(含 HEAD,与现网一致;不做 CF 的 HEAD→GET)
删除(过往过严,导致缓存率过低):
- 会话类 Cookie 正则
$http_authorization != ""- 请求
$http_cache_control匹配no-cache|no-store|private
安全如何仍成立:
| 威胁 | 闸门 |
|---|---|
| 误缓存 HTML/API | 默认 static 扩展名(不含 html/json) |
| 个性化内容 | 源站 private / no-store(Nginx 尊重) |
| 响应写会话 | Set-Cookie → 不入库(§3.6) |
all 过宽 |
UI/文档警告:需源站正确 Cache-Control |
| 带 Bearer 的 API | 依赖策略(勿对 API 用 all)+ 源站头;完整 Auth 条件缓存为后续 |
3.5 默认 Edge TTL(无源站 freshness 时)
对齐 CF 无 Cache-Control/Expires 时的状态码默认 TTL,在启用缓存的 location 输出:
| 状态码 | TTL |
|---|---|
| 200, 206, 301 | 120m |
| 302, 303 | 20m |
| 404, 410 | 3m |
proxy_cache_valid 200 206 301 120m;
proxy_cache_valid 302 303 20m;
proxy_cache_valid 404 410 3m;
- 源站提供合法
Cache-Control/Expires时,仍以源站 freshness 为准(不proxy_ignore_headers)。 - 不做强制忽略源站头的 Edge TTL 覆盖。
3.6 响应侧:Set-Cookie 不入库
对齐 CF OCC 默认:eligible 请求若源站返回 Set-Cookie,不写入 proxy_cache(可读路径仍可能 MISS/BYPASS 语义)。
proxy_no_cache $openflare_skip_cache $upstream_http_set_cookie;
(proxy_no_cache 多参数:任一非空且非 "0" 则不写入。)
proxy_cache_bypass 仍仅绑定 $openflare_skip_cache(请求侧 skip);响应侧只影响写入,与 CF「eligible 但响应不可缓存」一致。
3.7 与源站头的关系
- 是否 eligible:策略 + 方法旁路。
- 是否入库 / 存多久:源站
Cache-Control/Expires+ 默认proxy_cache_valid+ Set-Cookie 闸门 + 全局inactive。
4. 渲染与数据流
全局 cache_enabled?
│ no → 不生成 proxy_cache_*
▼ yes
路由 cache_enabled?
│ no → location 无 proxy_cache
▼ yes
set $openflare_skip_cache 0
→ 非 GET → 置 1
→ 策略 if(static/all/suffix/…)→ 可置 1
proxy_cache openflare_cache
proxy_cache_methods GET
proxy_cache_bypass $openflare_skip_cache
proxy_no_cache $openflare_skip_cache $upstream_http_set_cookie
proxy_cache_valid …
→
access.log cache_status=$upstream_cache_status
4.1 策略 → Nginx 条件
| 策略 | 额外条件 |
|---|---|
static |
$uri 不匹配内置扩展名表 → skip |
all |
无额外路径条件 |
suffix |
不匹配 cache_rules 扩展名 → skip |
path_prefix / path_exact |
同现实现 |
4.2 涉及代码面
| 区域 | 路径 |
|---|---|
| 渲染 | pkg/render/openresty/render.go(旁路、Set-Cookie、proxy_cache_valid、扩展名常量) |
| 校验 | internal/apps/openflare/proxy_route/helpers.go |
| 模型/默认 | 创建路由默认 cache_policy=static;读写时 url→all |
| 快照 | config_version 快照规范化 |
| UI | proxy-routes/detail/components/cache-section.tsx |
5. 兼容与迁移
| 数据 | 处理 |
|---|---|
DB 中 cache_policy='' 或 url(且已启用缓存) |
读 / 快照 / 渲染 → all |
| API 写入 enabled 且 policy 为空 | 规范为 all;UI 新建开启时显式提交 static |
| 新建路由 | 开启缓存时默认 static |
| 旁路行为变更 | 破坏性相对旧实现:带 Cookie/Auth 的流量从「未缓存」变为可 HIT;需 重新发布节点配置 后生效 |
| 默认扩展名 | 自表中 移除 json;已依赖缓存 *.json 的站点可改 suffix 自定义或 all |
发布说明: 说明本次对齐 CF 默认模型;命中率预期上升;all 与错误源站头风险需运维自查。
6. UI 文案要点(缓存 Tab)
- 开启缓存后默认:标准静态资源(摘要扩展名,不含 HTML/JSON;含 map/mjs 等)。
- 选项:标准静态 / 所有可缓存 GET(高级)/ 自定义后缀 / 路径前缀 / 精确路径。
- 说明对齐 CF:
- 登录 Cookie 不会单独跳过缓存;
- 源站
private/no-store/ 响应Set-Cookie不会写入边缘缓存; - 无源站缓存头时使用默认 Edge TTL。
- 高级
all:警告「类似 Cache Everything,个性化页面必须由源站声明 private/no-store」。 - 全局 Performance 缓存总开关须开启。
7. 决策矩阵(防漏判)
| 场景 | CF | OpenFlare(本设计) |
|---|---|---|
| GET 静态 + session Cookie + 源站 public max-age | HIT | HIT |
| GET HTML + static 策略 | DYNAMIC | 策略 skip → 未缓存 |
| GET + all + 源站 private | 不入库 | 不入库 |
| GET 静态 + 响应 Set-Cookie | BYPASS(OCC) | 不入库 |
| GET + Authorization + 静态 public | 条件缓存 | 可缓存(简化;依赖源站勿对敏感 API 乱标 public) |
| GET + 无 CC 的 200 静态 | 默认 120m | proxy_cache_valid 120m |
| DevTools Disable cache(请求 no-cache) | 边缘默认可仍 HIT | 边缘默认可仍 HIT |
| POST | 不缓存 | 非 GET skip |
8. 决策记录
| 决策 | 选择 | 原因 |
|---|---|---|
| 请求 Cookie 旁路 | 删除 | 对齐 CF;恢复登录用户静态命中率 |
| 请求 Authorization / Cache-Control 旁路 | 删除 | 对齐 CF 请求 eligible 模型;响应闸门兜底 |
| Set-Cookie | proxy_no_cache 绑定 | 对齐 CF OCC「响应 Set-Cookie 不入库」 |
| 默认 Edge TTL | 按状态码 proxy_cache_valid | 对齐 CF 无头时默认 TTL,避免「永不入库」 |
| 默认表去掉 json | 是 | 对齐 CF 默认不缓存 JSON |
| 保留 map/mjs/wasm | 是 | 现代前端有用命中,有意增强 |
| 默认可缓存范围 | 开启缓存默认 static |
对标 CF,降低 HTML/API 误缓存 |
旧 url |
映射 all |
存量行为不收窄 |
| 完整 Auth 条件 / Purge / Rules | 后续 | 先闭合默认闭环再扩展 |