Files
photo-live/infra/deploy/cdn-checklist.md
T
浅念 c26d6b9a73 fix(deploy): review fixes — smoke photoId field, web healthcheck wget, outbox table name, cdn key shape
Reviewer findings on p5-prep batch:
1. BLOCKING: prod-smoke.sh visibility grep used "id" but API items
   serialize photoId (cn public.service / ov public-ov.service) — every
   healthy deployment would false-FAIL release gate ④. 4 sites fixed.
2. web/web-ov healthchecks used curl on nginx:alpine (absent) → perpetual
   false-unhealthy; switched to busybox wget.
3. RUNBOOK rollback rule cited nonexistent sync_outbox → outbox_events.
4. cdn-checklist invalidation sample key shape aligned to actual
   variantsObjectKey layout (.../albums/{albumId}/variants/{photoId}/{version}/{variant}.jpg).

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 02:03:44 +08:00

146 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 阿里云全球 CDN 接入核对单(P5-prep Task 3)
> **全部步骤「待凭证执行」**:本清单只固化决策与命令样例,不预设任何已执行
> 状态。凭证/域名到位(G5)后按 T5 逐项勾选。关联:RUNBOOK.md §5.3(无 CDN
> 基线的缓存故障排查)、总纲 P5 行、`docs/plans/2026-09-21-P5-真实环境接入.md` T5。
## 0. 前置决策:图片加速三选一(重要架构核对,登记为 P5 决策项)
**现状(代码事实)**:图片一律走 **OSS presigned GET 直链**(S3 兼容 SigV4 签名,
`SIGNED_URL_TTL_SECONDS=900s`;variants 内容寻址键 `photoId+规格`,公开列表每次
现签 `thumb.url` / `browse.url`)。若 CDN 图片域名开启 **CDN 自己的 URL 鉴权**,
客户端 URL 将出现「CDN 签名参数 + OSS 签名参数」双层签名:CDN 校验自己的鉴权
参数后回源时带原 query 请求 OSS,OSS 再验自己的签名——两层参数互不冲突但
**缓存键含全部 query**,每个 900s 签名版本各成一册缓存,命中率崩塌;若为命中率
忽略 query,鉴权语义又互相残废。三个候选方案:
| 方案 | 内容 | 评估 |
| --- | --- | --- |
| a) 图片域名 CDN 仅缓存不鉴权 | 关 CDN 鉴权 + 忽略 query 参数缓存,依赖「OSS presign 过期」兜底 | **失效语义劣化**:presign 过期只约束回源,CDN 缓存内对象在 TTL 内仍可命中;忽略 query 后鉴权退化为「对象键不可猜」(cuid 随机,强度可接受但低于签名);隐藏照片失效窗口 = CDN 缓存 TTL,需配合主动失效。仅缓存静态 variants 可接受,收益有限 |
| b) CDN 鉴权 + 回源 OSS 私有桶 | 图片域名开 CDN URL 鉴权(B 型),回源用阿里云「CDN 授权访问 OSS 私有 Bucket」(§2),服务端 `presignGet` 改签 CDN 鉴权 URL | **正解但需改造**:签名安全模型从「OSS SigV4」迁到「CDN 鉴权」,`packages/storage` 的 presignGet 需按环境切换签名后端(或双签并存灰度);改造量集中在 storage 适配层 + 契约(URL 形态变化对前端透明,仍是无差别 URL 字符串)。**图片加速收益明确后采用** |
| **c) 【推荐起步】保持 presigned 直链 + CDN 仅加速 viewer 静态资源** | 只建 viewer 域名加速区(§1 Zone 1),图片域名 Zone(§1 Zone 2)暂不接入 | **最小改动、签名安全模型不变、零代码**;图片加速收益(900s 内重复读同图省回源带宽)先观察 OSS 流量账单再评估 b |
**推荐:c 起步**,图片流量账单 / 海外首屏时延数据到位后按 b 改造(a 不推荐,
失效语义与鉴权强度双损)。已登记为 P5 决策项(T5 内定案)。
## 1. 添加加速域名(待凭证执行;两 Zone)
| # | 加速域名 | 业务 | 源站 | 状态 |
| --- | --- | --- | --- | --- |
| Zone 1 | `<ov viewer 域名>`(如 photo.example.com) | viewer/admin SPA 静态 + `/v1/` API 透传 | ov 服务器 OpenResty 公网 IP(源站协议 https 回源 8089 需开白名单) | ☐ 待凭证执行 |
| Zone 2 | `<图片域名>`(如 img.example.com,CNAME 至同一 OSS 桶) | OSS 图片加速 | OSS Bucket(私有,需 §2 回源授权) | ☐ 待凭证执行(**方案 c 起步 = 本 Zone 暂缓创建**) |
每个 Zone 通用步骤(控制台:CDN → 域名管理 → 添加域名,业务类型「图片小
文件」/「小文件下载」;全球加速 = 不限区域或选「全球」):
- [ ] 添加域名 + 选择业务类型 + 源站信息(Zone 1 填 ov 服务器 IP;Zone 2 选
OSS 域名源站)
- [ ] CNAME 解析(DNS 服务商把域名 CNAME 到 CDN 分配的 `*.w.kunlun*.com`)
- [ ] HTTPS:申请/绑定证书 + 开启「强制 HTTPS」+(可选)HTTP/2
- [ ] 回源 Host 按默认(Zone 2 回源 Host = OSS 桶域名,控制台自动处理)
## 2. 源站 = OSS 私有 Bucket 回源授权(仅 Zone 2 / 方案 b 时需要;待凭证执行)
阿里云 CDN 回源私有 OSS 需授权二选一:
| 方式 | 操作 | 适用 |
| --- | --- | --- |
| 方式一:控制台一键 OSS 授权 | CDN 控制台源站配置时点「授权」,按提示同意创建 `AliyunCDNDefaultRole`(云账号级,授予 CDN 读 OSS 权限) | 最快,个人账号推荐 |
| 方式二:自定义 RAM 角色 | RAM 控制台创建角色(受信实体=CDN)+ 最小权限策略(仅目标桶 `oss:GetObject`)+ CDN 源站配置选该角色 | 多项目共用账号、需权限隔离时 |
- [ ] 按 §0 决策结果确定是否执行本节(方案 c 起步则整节跳过)
## 3. URL 鉴权选型(仅 Zone 2 / 方案 b;待凭证执行)
| 型式 | URL 形态 | 特点 |
| --- | --- | --- |
| A 型 | `md5(<uri>-<timestamp>-<rand>-<uid>-<key>)` 拼接,时间戳进 MD5 不可读 | 更防猜测,但排障时无法从 URL 直接看出过期时刻 |
| **B 型【推荐】** | `http://…/<uri>-<timestamp>-<md5hash>`,时间戳明文 | **时间戳在 URL 可读可调试**(一眼判过期);CDN 控制台配置简单(主备 key 各一个);鉴权粒度与 A 型同级 |
推荐 B 型理由:现场排障(观众报「图裂」)能直接从 URL 读出时间戳判断是否过期
窗口问题;主备 key 支持平滑轮换。**与现有 presigned GET 的关系**:方案 b 下
`presignGet` 输出从 OSS SigV4 URL 改为 CDN B 型鉴权 URL(§0 表格);方案 c 下
无任何 URL 鉴权变更(Zone 1 静态资源不鉴权,本来就公开)。
- [ ] 若定案方案 b:Zone 2 配置 B 型鉴权 + 主备 key(`openssl rand -hex 32`)
- [ ] 服务端 presignGet 签名后端改造排期(storage 适配层 + 测试)
## 4. 缓存规则表(Zone 1;待凭证执行)
原则:**源站 photo-live-web 已对内容寻址路径发 `Cache-Control: immutable`**
(`infra/deploy/nginx.conf.template`),CDN 遵循源站头即可,无需重配长 TTL。
计划占位稿中的「/assets/ 7d」按此修正为遵循源站 immutable(内容寻址键允许,
发新版 = 新 URL,无失效问题)。
| 路径 | CDN 缓存策略 | 依据 |
| --- | --- | --- |
| `/embed/v1/*` | 遵循源站:immutable 一年 | 版本目录即内容版本(nginx 同规则) |
| `/assets/*`、`/admin/assets/*` | 遵循源站:immutable 一年 | vite 内容寻址产物 |
| `/`、`/index.html`、`/admin/`、`/admin/index.html`、SPA 回退路径 | **不缓存**(no-cache,每次回源) | 发布新版必须立即生效,HTML 引用新 hash 的 assets |
| `/v1/*`(API/WS) | **不缓存** + 透传 `x-request-id` 头 | 动态 API;WS 经 CDN 需在 CDN 侧确认支持或对 `/v1/realtime` 单独跳过 CDN(建议 DNS 直连源站,见 §7 注意) |
- [ ] 按上表在 CDN 控制台配置缓存规则(HTML/回退路径显式 no-cache 兜底——
源站对 `index.html` 未显式发 no-cache 头,CDN 侧补齐这道保险)
- [ ] 验证:`curl -sI https://<域名>/ | grep -i cache` 确认未命中缓存
## 5. 失效 / 预热 API 样例(待凭证执行)
阿里云 CDN OpenAPI 需 AccessKey 签名(ACS3-HMAC-SHA256),raw curl 组签名繁琐,
**推荐 aliyun CLI 形态**(`aliyun` CLI 配置凭证后即用;curl 等价样例在凭证到位
后按官方签名文档补齐——本节全部待凭证执行):
```bash
# 隐藏照片 → 失效该照片全部 variants 路径(对象键含 photoId 与内容版本;
# 方案 b 下才需要——variants 是 immutable 缓存,隐藏 = 主动失效 + 公开 API 404 双保险)
# 多 URL 用换行分隔(RefreshObjectCatches/PreloadObjectCaches 的 ObjectPath 约定)
aliyun cdn RefreshObjectCaches \
--ObjectPath "$(printf '%s\n%s' \
'https://<图片域名>/photo-live/prod/albums/<albumId>/variants/<photoId>/<version>/thumb.jpg' \
'https://<图片域名>/photo-live/prod/albums/<albumId>/variants/<photoId>/<version>/browse.jpg')" \
--ObjectType File
# 新活动发布 → 预热首页与首屏静态资源(viewer 域名,降低冷缓存首访时延)
aliyun cdn PreloadObjectCaches \
--ObjectPath "$(printf '%s\n%s' \
'https://<viewer域名>/assets/<新版本hash>.js' \
'https://<viewer域名>/assets/<新版本hash>.css')"
# 目录级失效(发版后 SPA HTML 变更;范围大时用,注意每日失效配额)
aliyun cdn RefreshObjectCaches --ObjectPath "https://<viewer域名>/" --ObjectType Directory
```
- [ ] 隐藏照片失效窗口验证(方案 b 时):上传 → 公开可读 → 隐藏 → 立即请求
variants URL:公开 API 应 404(PHOTO_NOT_PUBLIC),CDN 失效执行完成后
图片 URL 应 403/404;**失效前的窗口 = 设计允许的失效窗口**(对齐 P4a
契约决策与 RUNBOOK §5.3,CDN 侧窗口上限 = 失效 API 生效延迟,需实测
登记进 RUNBOOK)
- [ ] 发版后预热纳入发布检查单(RUNBOOK §1 增补一行,待 CDN 实际接入后回填)
## 6. 冷缓存测试点(海外多地域时延记录表模板)
各地域单点拨测(冷缓存 = 首次请求回源;建议每地域 `curl` 3 次取中位),模板:
| 地域(测试点) | 测试方式 | 冷缓存 TTFB/总时延 | 热缓存复测 | 时间 | 备注 |
| --- | --- | --- | --- | --- | --- |
| 新加坡 | `curl -s -o /dev/null -w '%{time_starttransfer} %{time_total}\n' https://<viewer域名>/` | ___ / ___ | ___ | ___ | |
| 东京 | 同上 | ___ / ___ | ___ | ___ | |
| 法兰克福 | 同上 | ___ / ___ | ___ | ___ | |
| 美西(硅谷) | 同上 | ___ / ___ | ___ | ___ | |
| 美东(弗吉尼亚) | 同上 | ___ / ___ | ___ | ___ | |
| 国内对照(杭州) | 同上 | ___ / ___ | ___ | ___ | 不走全球 CDN 国内段时的对照基线 |
可选公共拨测源:阿里云云监控站点监控(多地域)、第三方(如 GTmetrix / WebPageTest)
留档截图。记录表随 T5 产出归档进 P5 验收记录。
## 7. 注意事项与边界
- **WS(`/v1/realtime`)不适合过 CDN**:长连接透传稳定性依赖 CDN 支持;建议
viewer 前端 WS 地址直连源站域名(或单独一个不接 CDN 的子域),CDN 只加速
静态与普通 API。核对前端 realtime 连接 URL 的构造(P5 T4/T5 联合验证项)。
- Zone 1 源站是 ov 服务器 OpenResty:CDN 回源 IP 段需加入 OpenResty 白名单
(1Panel 防火墙),并确认回源走 https(证书已就绪)。
- 速率/配额:CDN 每日失效/预热有配额(控制台可见),发版高频期优先用文件级
精确失效;目录级失效作为兜底。
- 全部步骤执行前保持「无 CDN」基线可用(RUNBOOK §5.3),CDN 故障时 DNS 切回
直连即回滚(T8 演练项之一)。