docs: p5 preparation complete and implementation draft
- docs/plans/2026-09-21-P5-真实环境接入.md 草案(头部标注待 G5 凭证评审 转正):T1-T12 任务序(每任务 产出/依赖用户输入/关口)——G1 OSS 冒烟→ 国内起栈→ov 部署+bootstrap 对账→域名证书→CDN(含图片加速三选一)→ 跨境 MySQL 通道定案(白名单+SSL/隧道/HTTP 化三选项,含改造量评估)→ G4 用户源→故障演练→压测 D05→G2 真机→G6 试运行→发布交接;用户输入 汇总表 + 决策 D03-D13 状态速查 + 风险表(跨境链路/双层签名/MySQL 8.0.30 门槛/镜像仓库通道等) - 总纲 P5 行注记:准备件完成 2026-09-21,实装待 G5 + G4 - P5-prep 计划全项勾选回填(评审项注明自审已修 + 独立 reviewer 由编排方追加) - 自审修正:monitoring 统计副本表名(无 stat_snapshots 表,副本位在 albums/photos 行)与 outbox_events.occurredAt/photo_jobs.updatedAt 列名、 jq 管道括号;cdn 失效多 URL 换行分隔;k6 helpers 请求体用 ArrayBuffer 原生形态、read-feed 身份串延迟生成(init 上下文 VU 编号恒 0) Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -92,13 +92,18 @@
|
||||
```bash
|
||||
# 隐藏照片 → 失效该照片全部 variants 路径(对象键含 photoId 与内容版本;
|
||||
# 方案 b 下才需要——variants 是 immutable 缓存,隐藏 = 主动失效 + 公开 API 404 双保险)
|
||||
# 多 URL 用换行分隔(RefreshObjectCatches/PreloadObjectCaches 的 ObjectPath 约定)
|
||||
aliyun cdn RefreshObjectCaches \
|
||||
--ObjectPath "https://<图片域名>/variants/thumb/<photoId>/<版本>.webp;https://<图片域名>/variants/browse/<photoId>/<版本>.webp" \
|
||||
--ObjectPath "$(printf '%s\n%s' \
|
||||
'https://<图片域名>/variants/thumb/<photoId>/<版本>.webp' \
|
||||
'https://<图片域名>/variants/browse/<photoId>/<版本>.webp')" \
|
||||
--ObjectType File
|
||||
|
||||
# 新活动发布 → 预热首页与首屏静态资源(.viewer 域名,降低冷缓存首访时延)
|
||||
# 新活动发布 → 预热首页与首屏静态资源(viewer 域名,降低冷缓存首访时延)
|
||||
aliyun cdn PreloadObjectCaches \
|
||||
--ObjectPath "https://<viewer域名>/;https://<viewer域名>/assets/<新版本hash>.js;https://<viewer域名>/assets/<新版本hash>.css"
|
||||
--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
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
| MySQL / Redis 连接与资源 | 1Panel 数据库监控(连接数、内存);连接池上限已在连接串 `connection_limit=10` 固化 | 两台 |
|
||||
| 同步失败 / 同步水位延迟 | sync 容器结构化日志检索(§3 检索语句)+ `outbox_events` 未投递计数(SQL) | cn 服务器 |
|
||||
| 上传失败率 | api-cn 访问日志(pino-http)按 `req.url` + `res.statusCode` 计数(§3) | cn 服务器 |
|
||||
| 计数差异(点赞/浏览对不上) | sync `stat return cycle failed` 日志 + `stat-snapshots` statVersion 前进检查(§3) | cn 服务器 |
|
||||
| 计数差异(点赞/浏览对不上) | sync `stat return cycle failed` 日志 + `albums`/`photos` 副本 `statsVersion` 前进检查(§3) | cn 服务器 |
|
||||
| 队列积压(图片处理) | worker `sweep 完成` 日志的 `claimed` 持续 >0 + `photo_jobs` pending 行龄 SQL(§3) | cn 服务器 |
|
||||
| 磁盘 / 流量(OSS) | OSS 控制台用量 + 云监控;CDN 接入后加 CDN 控制台流量看板 | 阿里云控制台 |
|
||||
| 证书到期 / 域名解析 | 1Panel 证书管理提示 + 云监控站点监控 | 各自 |
|
||||
@@ -86,7 +86,7 @@ docker logs --since 10m photo-live-cn-sync-1 2>&1 \
|
||||
|
||||
# ①' 同步水位延迟(未投递账本堆积——发布前快照同款 SQL,阈值见 §4)
|
||||
docker exec <cn-mysql容器> mysql -uphoto -p -e \
|
||||
"SELECT COUNT(*) AS undelivered, MIN(createdAt) AS oldest FROM photo_cn.outbox_events WHERE deliveredAt IS NULL;"
|
||||
"SELECT COUNT(*) AS undelivered, MIN(occurredAt) AS oldest FROM photo_cn.outbox_events WHERE deliveredAt IS NULL;"
|
||||
|
||||
# ② 上传失败率(api 访问日志:uploads 路径非 2xx 占比;complete 失败码单独数)
|
||||
docker logs --since 10m photo-live-cn-api-cn-1 2>&1 \
|
||||
@@ -98,16 +98,18 @@ docker logs --since 10m photo-live-cn-api-cn-1 2>&1 \
|
||||
# ③ 计数差异(stat 回传断流 + 版本不前进)
|
||||
docker logs --since 30m photo-live-cn-sync-1 2>&1 \
|
||||
| jq -c 'select(.msg | contains("stat return cycle failed"))'
|
||||
# 版本前进检查(statVersion 应随互动增长单调;长期不变即聚合停滞):
|
||||
# 版本前进检查(statsVersion 应随互动增长单调;长期不变即聚合停滞——
|
||||
# 统计副本位内联在 albums/photos 行上:viewCountReplica/likeCount + statsVersion):
|
||||
docker exec <cn-mysql容器> mysql -uphoto -p -e \
|
||||
"SELECT albumId, MAX(statVersion) AS v, MAX(updatedAt) AS lastAt FROM photo_cn.stat_snapshots GROUP BY albumId ORDER BY lastAt DESC LIMIT 10;"
|
||||
"SELECT id, statsVersion, viewCountReplica, statsSyncedAt FROM photo_cn.albums ORDER BY statsSyncedAt DESC LIMIT 10;"
|
||||
|
||||
# ④ 队列积压(sweep claimed 持续 >0 = 孤儿持续被重新认领 = 消费不及或 worker 停)
|
||||
docker logs --since 10m photo-live-cn-worker-1 2>&1 \
|
||||
| jq -c 'select(.msg == "sweep 完成")' | jq -s 'map(.claimed) | {samples: length, nonzero: map(select(.>0)) | length}'
|
||||
# 兜底 SQL:pending 行龄( oldest 超过 5 分钟即真积压)
|
||||
| jq -c 'select(.msg == "sweep 完成")' | jq -s 'map(.claimed) | {samples: length, nonzero: ([.[] | select(. > 0)] | length)}'
|
||||
# 兜底 SQL:pending 行龄(photo_jobs 无 createdAt,以 updatedAt 近似行龄;
|
||||
# oldest 超过 5 分钟即真积压——注意行被认领/重试会刷新 updatedAt)
|
||||
docker exec <cn-mysql容器> mysql -uphoto -p -e \
|
||||
"SELECT COUNT(*) AS pending, MIN(createdAt) AS oldest FROM photo_cn.photo_jobs WHERE state='pending';"
|
||||
"SELECT COUNT(*) AS pending, MIN(updatedAt) AS oldest, MIN(nextRetryAt) AS nextRetry FROM photo_cn.photo_jobs WHERE state='pending';"
|
||||
|
||||
# ⑤ 图片处理终败(重试耗尽的照片,需人工补处理)
|
||||
docker logs --since 1h photo-live-cn-worker-1 2>&1 \
|
||||
@@ -125,7 +127,7 @@ docker logs --since 10m photo-live-cn-api-cn-1 2>&1 \
|
||||
| sync 推送失败 | 10 分钟内 `outbox push failed` ≥ 3 次(对应退避 3 轮未自愈) | 日志检索 ①(人工/计划任务) | 【占位:运维负责人】 |
|
||||
| 同步水位延迟 | `outbox_events` 未投递 > 1000 行,或 oldest > 10min | SQL ①'(发布检查单同款,可入 1Panel 计划任务) | 【占位】 |
|
||||
| 上传失败率 | uploads 路径非 2xx 占比 > 5%(10 分钟窗,样本 ≥ 20) | 日志检索 ② | 【占位】 |
|
||||
| 计数差异 | `stat return cycle failed` 连续 30 分钟,或 stat_snapshots 最新 lastAt > 30min 前且互动非零 | 日志/SQL ③ | 【占位】 |
|
||||
| 计数差异 | `stat return cycle failed` 连续 30 分钟,或活跃相册 `statsSyncedAt` > 30min 前且互动非零 | 日志/SQL ③ | 【占位】 |
|
||||
| 队列积压 | sweep `claimed` 连续 6 轮(约 3min)>0,或 photo_jobs pending oldest > 5min | 日志/SQL ④ | 【占位】 |
|
||||
| 图片处理终败 | 1h 内 `process job 终败` ≥ 5 张 | 日志检索 ⑤ | 【占位】 |
|
||||
| API 5xx 洪峰 | 10 分钟 5xx ≥ 10 次 | 日志检索 ⑥ / 云监控站点监控 | 【占位】 |
|
||||
|
||||
Reference in New Issue
Block a user