test(loadtest),docs: monitoring, cdn checklist and k6 framework

- monitoring.md: 指标→实现映射(1Panel+云监控+结构化日志,不引入额外监控
  系统);pino 字段表如实列自代码(访问日志 req.id/res.statusCode/
  responseTime + sync/worker 自定义 msg 字段);六类告警 jq 检索语句与
  阈值建议总表;日志保留(compose json-file 10m×3 已设 + 每日归档建议)
- cdn-checklist.md: 全步骤待凭证执行;图片加速三选一架构核对(双层签名
  冲突分析,推荐 c 起步=CDN 仅加速 viewer 静态、presigned 直链不变,
  图片收益后评估 b=CDN 鉴权+私有桶回源授权);缓存规则对齐源站 immutable;
  失效/预热 CLI 样例与多地域冷缓存测试点模板
- loadtest/: k6 框架——read-feed.js(N 观众四 mix:latest/hot 分页+大图+
  点赞+浏览,ramp 阶段)、upload-burst.js(M 并发上传全链含 complete 与
  发布/同步可选轮询,兼作数据种子)、lib/helpers.js(登录/建册/上传全链
  +内嵌 JPEG fixture 与 prod-smoke 同源)、README(运行方式/参数表/
  P95 输出解读对齐计划 §6 候选指标;D05 未定→阈值占位注释)

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-21 01:52:47 +08:00
parent a79fff5b9c
commit f71a887f17
6 changed files with 924 additions and 0 deletions
+140
View File
@@ -0,0 +1,140 @@
# 阿里云全球 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 双保险)
aliyun cdn RefreshObjectCaches \
--ObjectPath "https://<图片域名>/variants/thumb/<photoId>/<版本>.webp;https://<图片域名>/variants/browse/<photoId>/<版本>.webp" \
--ObjectType File
# 新活动发布 → 预热首页与首屏静态资源(.viewer 域名,降低冷缓存首访时延)
aliyun cdn PreloadObjectCaches \
--ObjectPath "https://<viewer域名>/;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 演练项之一)。
+152
View File
@@ -0,0 +1,152 @@
# 监控告警方案(P5-prep Task 3)
> 适用对象:photo-live 双地域生产栈(编排见 `docker-compose.cn.yml` /
> `docker-compose-ov.yml`)。**治理决策(登记):P5 起步不引入额外监控系统**
>(Prometheus/Grafana/ELK 均不上)——1Panel 应用监控 + 云监控 + 结构化日志
> 检索三件套覆盖本阶段全部指标面;业务量或团队规模变化时再评估升级,
> 届时优先补「日志聚合 + 指标导出」,而非替换现有日志结构。
## 1. 指标 → 实现方式映射总表
| 指标 | 实现方式 | 位置 |
| --- | --- | --- |
| 服务存活 / health | 容器 healthcheck(api-cn/api-ov/web 有 `/v1/health` 探针;worker/sync 无 HTTP 面,以进程存活 + restart 策略承担)+ 1Panel 容器状态页 | 两台 1Panel |
| 容器重启次数 | 1Panel 容器监控(重启计数突增 = crash loop) | 两台 1Panel |
| CPU / 内存 / 磁盘容量 | 1Panel 应用监控 + 主机概览;云监控(ECS 自带)做兜底告警 | 两台 |
| 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 服务器 |
| 队列积压(图片处理) | worker `sweep 完成` 日志的 `claimed` 持续 >0 + `photo_jobs` pending 行龄 SQL(§3) | cn 服务器 |
| 磁盘 / 流量(OSS) | OSS 控制台用量 + 云监控;CDN 接入后加 CDN 控制台流量看板 | 阿里云控制台 |
| 证书到期 / 域名解析 | 1Panel 证书管理提示 + 云监控站点监控 | 各自 |
要点:**业务指标不带独立监控系统,全部落在结构化日志检索**。三端(api /
worker / sync)日志均为 pino JSON 单行 stdout,`docker logs` 直接可查;字段
口径见 §2(如实列自代码,非设想)。
## 2. pino 结构化日志字段表
日志器装配(代码事实):api = `nestjs-pino` + `pino-http`(`services/api/src/
shared/logger-options.ts`,每请求自动访问日志);worker / sync = 原生 pino
(`services/worker/src/main.ts` / `services/sync/src/main.ts`)。级别映射 pino
数值:20=debug 30=info 40=warn 50=error。凭据打码:`req.headers.authorization`
与 `req.headers.cookie` 已按 `logger-options.ts` redact 为 `[REDACTED]`。
### 2.1 通用字段(每行日志必有)
| 字段 | 来源 | 示例 / 说明 |
| --- | --- | --- |
| `level` | pino | `30`(数值;人读用 `docker logs … \| jq -r '.level'` 映射) |
| `time` | pino | Unix 毫秒时间戳 |
| `pid` / `hostname` | pino | 进程 / 容器主机名(排障定位容器) |
| `msg` | 各调用点 | 人类可读消息(检索主键,见表 2.3) |
| `context` | nestjs-pino(仅 api) | Nest Logger 上下文名,如 `AllExceptionsFilter`、`UserSyncService` |
### 2.2 HTTP 访问日志字段(api 每请求一行,pino-http 自动打点)
| 字段 | 说明 |
| --- | --- |
| `req.id` | 请求 ID:透传上游 `x-request-id` 或现生成 UUID;**同时回写响应头 `x-request-id`**,全链路排障锚点(`request-id.middleware.ts`) |
| `req.method` / `req.url` | 方法与含 query 的路径(如 `GET /v1/public/albums/tok/photos?limit=30`) |
| `req.headers` | 已 redact 授权头/Cookie |
| `req.remoteAddress` / `req.remotePort` | 客户端地址(反代后是网关地址,trust proxy 登记为 P5 项) |
| `res.statusCode` | 响应状态码(错误率计数的取数字段) |
| `responseTime` | 服务端耗时毫秒(粗粒度性能观测;精测用压测框架 `loadtest/`) |
| `msg` | 固定 `request completed` |
### 2.3 业务/后台进程自定义字段(msg 为检索主键,如实列自调用点)
| 进程 | `msg`(检索用) | 级别 | 自定义字段 | 语义 |
| --- | --- | --- | --- | --- |
| sync | `outbox batch pushed` | info | `picked`(取数)`acceptedEventIds[]`(ov 确认)`applied`(实际应用) | 推送健康;`picked≥batchSize` 连续出现 = 排积压 |
| sync | `outbox push failed(整批未标记,下轮重推)` | error | `err` `failureStreak` `backoffMs` | **同步失败告警主信号**;连续出现 = cn→ov 中断 |
| sync | `reconcile cycle failed(幂等安全,下轮再试)` | error | `err` | 对账循环失败(5min 一轮自愈) |
| sync | `stat snapshots returned` | info | `picked` `snapshots` `accepted` | 统计回传健康;长期不出现 = ov 聚合停滞 |
| sync | `stat return cycle failed(未确认行留待下轮重发,幂等安全)` | error | `err` | **计数差异告警信号**(回传断流) |
| sync | `sync sender + reconciler + stat-return started` | info | `cnApiUrl` `ovApiUrl` `intervalMs` `batchSize` `reconcileIntervalMs` `statReturnIntervalMs` | 启动自描述(排障先看这行核对 env) |
| sync | `env 非正整数,回退契约默认值` / `缺少内部同步密钥,发送器退出` | warn / error | `name,raw` / `env` | 配置异常 |
| worker | `process job 完成` | info | `photoId` `jobId` `outcome` | 单照片流水线完成 |
| worker | `process job 终败(重试耗尽)` | error | `photoId` `jobId` `errorCode` | **图片处理失败告警**(errorCode 对照契约错误码) |
| worker | `sweep 完成` | info | `claimed`(本轮认领孤儿)`enqueueFailures` `staleReEnqueued` | **队列积压观测锚**:稳态应恒为 `claimed:0` |
| worker | `sweep 轮次异常` / `photo-process 入队失败(sweep 将补偿)` | error/warn | `err` / `photoId` | 补偿通道异常 |
| worker | `redis 连接异常(ioredis 自动重连)` | warn | `label` `err` | Redis 闪断(自愈,频发则查 Redis) |
| api | `ApiException <status> -> <code> (requestId=…)` | warn | 消息内嵌 code 与 requestId | 业务异常计数(含上传 complete 失败码) |
| api | `HttpException …` / `Unhandled exception …` | warn/error | 同上 + stack | 非业务异常(5xx 必查 requestId 关联访问日志行) |
## 3. 每类告警的检索语句样例(docker logs + jq,两台服务器上直接执行)
容器名约定(compose 项目名前缀):`photo-live-cn-sync-1` /
`photo-live-cn-worker-1` / `photo-live-cn-api-cn-1`(ov:`photo-live-ov-api-ov-1`)。
```bash
# ① 同步失败(告警口径:近 10 分钟出现 error 级 outbox push failed)
docker logs --since 10m photo-live-cn-sync-1 2>&1 \
| jq -c 'select(.msg | contains("outbox push failed"))'
# ①' 同步水位延迟(未投递账本堆积——发布前快照同款 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;"
# ② 上传失败率(api 访问日志:uploads 路径非 2xx 占比;complete 失败码单独数)
docker logs --since 10m photo-live-cn-api-cn-1 2>&1 \
| jq -c 'select(.msg=="request completed" and (.req.url | contains("/v1/uploads")) and (.res.statusCode < 200 or .res.statusCode > 299))'
# 业务失败码(ALBUM_UPLOAD_DISABLED / UPLOAD_SESSION_CONFLICT / UPLOAD_VERIFY_FAILED 等):
docker logs --since 10m photo-live-cn-api-cn-1 2>&1 \
| jq -r 'select(.msg | startswith("ApiException")) | .msg' | sort | uniq -c | sort -rn
# ③ 计数差异(stat 回传断流 + 版本不前进)
docker logs --since 30m photo-live-cn-sync-1 2>&1 \
| jq -c 'select(.msg | contains("stat return cycle failed"))'
# 版本前进检查(statVersion 应随互动增长单调;长期不变即聚合停滞):
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;"
# ④ 队列积压(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 分钟即真积压)
docker exec <cn-mysql容器> mysql -uphoto -p -e \
"SELECT COUNT(*) AS pending, MIN(createdAt) AS oldest FROM photo_cn.photo_jobs WHERE state='pending';"
# ⑤ 图片处理终败(重试耗尽的照片,需人工补处理)
docker logs --since 1h photo-live-cn-worker-1 2>&1 \
| jq -c 'select(.msg | contains("process job 终败"))'
# ⑥ 5xx 洪峰(api 全量非 5xx 校验;冒烟/压测期配合使用)
docker logs --since 10m photo-live-cn-api-cn-1 2>&1 \
| jq -c 'select(.msg=="request completed" and .res.statusCode >= 500)'
```
## 4. 告警项总表(阈值 = P5 起步建议值,试运行后按观测校准)
| 告警项 | 阈值建议 | 检测方式 | 接收人 |
| --- | --- | --- | --- |
| 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 ③ | 【占位】 |
| 队列积压 | sweep `claimed` 连续 6 轮(约 3min)>0,或 photo_jobs pending oldest > 5min | 日志/SQL ④ | 【占位】 |
| 图片处理终败 | 1h 内 `process job 终败` ≥ 5 张 | 日志检索 ⑤ | 【占位】 |
| API 5xx 洪峰 | 10 分钟 5xx ≥ 10 次 | 日志检索 ⑥ / 云监控站点监控 | 【占位】 |
| 容器重启 | 1Panel 重启计数 1h 内 +3(crash loop) | 1Panel 应用监控 | 【占位】 |
| 磁盘容量 | 1Panel 磁盘 > 80% 告警 / > 90% 严重 | 1Panel 主机监控(自带阈值告警) | 【占位】 |
| ECS / 网络可用性 | ping / 站点探测失败 | 阿里云监控(站点监控免费档即可) | 【占位】 |
| OSS 流量异常 | 月度流量突增(对比基线 ×3) | OSS 控制台 + 云监控账单告警 | 【占位】 |
| 证书到期 | 剩余 < 14 天 | 1Panel 证书管理 / 云监控 | 【占位】 |
> 1Panel 计划任务可承载 SQL 类巡检(①'/③/④ 的 SQL + 失败时发通知),把
> 「人工检索」升级为「定时巡检」零新增组件;通知通道用 1Panel 的通知设置。
## 5. 日志保留策略
- **已固化**(compose 两栈统一 `x-logging`):docker json-file 轮转
`max-size=10m × max-file=3`,单容器上限约 30MB,六容器合计 ~180MB 上限,
磁盘不会被日志撑爆。轮转之外无中心化留存——重启/删除容器丢历史,属已知取舍。
- **建议归档(P5 试运行起执行)**:1Panel 计划任务每日低峰
`docker logs <容器> --since 24h > /opt/photo-live/logs/<容器>-$(date +%F).json`
后 gzip 存本地 30 天(约每天几 MB),异常事件窗口按 RUNBOOK §1 的「水位与
账本快照登记」随发布记录另存。归档目录加入 1Panel 备份计划即可,不建独立
日志系统。
- 排障现场优先用 `--since` 缩窗 + §3 jq 语句;跨容器串事件用 `req.id` /
`requestId=`(响应头同值,用户报障时让前端从 DevTools 复制即可定位)。