# 后端服务设计(第一阶段 · 印尼市场 · 1 万并发观看) > 版本 v1.0 · 配套 [第一阶段 PRD](./prd-phase1.md) · 现有实现见 [架构设计](./architecture-design.md) > 目标口径:**10,000 路并发播放不劣化**(对应 DAU 约 25–35 万),首发印尼。 ## 1. 目标与约束 **业务目标**:日活规模下 1 万路并发观看流畅(首帧 P95 < 1.5s、卡顿率 < 2%),分集收费闭环准确无误,创作者上传到可播放全自动。 **工程约束**: 1. 首发印尼,用户全部在东南亚,服务端与内容必须就近部署,不能用国内机房直连。 2. 团队是 14–16 人的 MVP 团队,运维只有 1 人,所以不做微服务拆分,保持模块化单体。 3. 数字商品必须走 Apple IAP / Google Play Billing,服务端只做校验与权益发放。 4. 成本敏感:视频流量是最大成本项,码率与缓存策略从一开始就要按成本设计。 ## 2. 现状盘点与差距 当前实现:7 个 Maven 模块的模块化单体,`fruitshorts-admin-api`(8080) + `fruitshorts-app-api`(8081), MyBatis-Plus + PostgreSQL,媒资落本地磁盘 `data/uploads`,静态文件直出,无转码、无 CDN、无缓存层、无消息队列。 | 能力 | 现状 | 目标 | 优先级 | | --- | --- | --- | --- | | 媒资存储 | 本地磁盘,随机器走 | 对象存储(S3 兼容)+ 生命周期分层 | P0 | | 视频分发 | 源站直出原文件 | 转码成 HLS 多码率 + CDN 分发 + 签名 URL | P0 | | 缓存 | 无 | Redis + 本地 Caffeine 二级缓存 | P0 | | 异步 | 无 | 消息队列(转码任务、计数、埋点、对账) | P0 | | 数据库 | 单实例单库 | 主库 + 只读副本,热点与日志表分区 | P1 | | 播放鉴权 | 免费集直接给地址 | 票据 + 签名 URL + 有效期 + 吊销 | P0 | | 限流熔断 | 无 | 网关级限流 + 按接口降级 | P0 | | 支付 | 未实现 | 订单状态机 + 票据校验 + 对账 | P0 | | 可观测 | 慢请求日志 | 指标 + 链路追踪 + 告警 + 看板 | P1 | 结论:现有代码是功能验证级,架构骨架(模块划分、鉴权、内容与媒资模型)可以直接复用, 但"视频从源站直出"这一点在 1 万并发下会立刻打爆,必须替换成 CDN + 签名 URL。 ## 3. 容量规划 ### 3.1 码率阶梯与带宽 印尼以 4G 为主、资费敏感,码率阶梯压到偏低档位: | 档位 | 分辨率 | 视频 | 音频 | 合计 | 预期占比 | | --- | --- | --- | --- | --- | --- | | 360p | 640x360 | 400 kbps | 64 kbps | ~0.47 Mbps | 40% | | 480p | 854x480 | 800 kbps | 64 kbps | ~0.87 Mbps | 45% | | 720p | 1280x720 | 1600 kbps | 96 kbps | ~1.70 Mbps | 12% | | 1080p | 1920x1080 | 3200 kbps | 128 kbps | ~3.30 Mbps | 3% | 按占比加权,平均码率约 **0.88 Mbps**。 - 10,000 路并发出口带宽约 **8.8 Gbps** - 叠加首段突发、重连与预加载(+30%),峰值 **约 11–12 Gbps** - CDN 命中率按 98% 计,回源带宽 **约 240 Mbps** 源站只需 2 台带 1 Gbps 出口的机器即可承载回源,不需要为每个观众准备源站带宽。 这条推导是整个设计的关键:**播放流量必须由 CDN 承担,源站只回源 2%**。 ### 3.2 接口 QPS | 链路 | 估算方式 | 平均 | 峰值(x3,20:00–23:00 WIB) | | --- | --- | --- | --- | | 首页/发现/详情 | 每活跃用户每分钟 2 次 | ~333 QPS | ~1,000 QPS | | 播放票据签发 | 每集一次,平均 4 分钟/集 | ~42 QPS | ~125 QPS | | 播放进度上报 | 每 10 秒一次 | 1,000 QPS | 3,000 QPS | | 埋点/播放计数 | 客户端按 30s 合批 | ~330 QPS | ~1,000 QPS | 结论: - **读接口** 经 Redis + 本地缓存后,4–8 个 API 副本足够(单副本可撑 1,500+ QPS)。 - **进度上报不直接打库**:写 Redis,后台任务按 `user+drama` 合并后批量 UPSERT,落库压力降到 100 QPS 量级。 - **埋点与计数走消息队列**,消费者聚合后写回,不用事务强一致。 ### 3.3 存储与转码 按第一阶段 300 部 x 60 集 x 单集 2 分钟估算: | 项 | 计算 | 容量 | | --- | --- | --- | | 原片(1080p) | 18,000 集 x ~50 MB | ~0.9 TB | | 转码产物(4 档 HLS) | 18,000 集 x ~95 MB | ~1.7 TB | | 封面/截图/字幕 | — | ~0.1 TB | | **合计** | | **约 3 TB** | 转码算力:单集 1080p 转 4 档约 8 分钟机时,首月入库 18,000 集约 2,400 小时; 100 核并行约 24 小时跑完。**按需弹性即可,不需要常驻转码集群**,但必须排队限流,避免抢在线服务的 CPU。 ### 3.4 成本与单位经济性 假设 DAU 30 万、人均日观看 40 分钟、平均码率 0.88 Mbps: | 项 | 月度量/成本 | 说明 | | --- | --- | --- | | CDN 流量 | 约 79 TB/天,约 2,300 TB/月,**$50k–75k** | 按东南亚 $0.022–0.032/GB,**最大成本项** | | 对象存储 | 3 TB,约 $60–100 | 冷热分层后更低 | | 数据库 / Redis / MQ | $300–800 | 主从 + 只读副本 + 集群缓存 | | API 与后台计算 | $400–1,200 | 4–8 副本 + 弹性转码 | | 短信 OTP | $500–2,000 | 按 $0.02–0.08/条,必须频控 | | 监控 / 日志 / APM | $100–300 | | | **合计** | **约 $52k–79k/月** | CDN 占绝大部分可变成本 | 单位经济性(决定商业模型是否成立): - 单集 2 分钟、0.88 Mbps,约 13 MB 流量,CDN 成本约 **$0.0004** - 单集解锁(按 30 金币约 $0.03),视频成本约占解锁收入 **1.5%** 推论: 1. 金币解锁模式下视频成本可忽略;真正的压力来自第二阶段的广告模式(ARPU 低一个数量级时 CDN 会变成主要成本)。 2. 因此第一阶段就要把平均码率、缓存命中率、CDN 单价做成**看板与告警**(单位播放成本 $/千次播放)。 3. 把平均码率从 0.88 压到 0.6 Mbps(更多 360p、更激进的 ABR 起播策略)可直接省掉约 30% 的 CDN 账单,比任何架构优化都有效。 ## 4. 部署与网络拓扑 ``` 印尼用户 (iOS / Android) | 1. 接口请求(JSON, HTTPS) v CDN / 全球加速 --- 2. 视频分片与静态资源(HLS,签名 URL,命中率 >=98%) | ^ | 回源(约 2%) | v | 区域入口 (Jakarta) | |- API 网关:TLS、限流、鉴权、WAF | |- app-api x4-8(K8s HPA) | |- admin-api x2(可放新加坡/内网,仅内部使用) | |- worker(转码调度、计数聚合、对账、清理) | | |- PostgreSQL(主 + 只读副本) |- Redis(集群:缓存 / 票据 / 进度缓冲 / 限流) |- 消息队列(转码任务、埋点、计数、对账事件) |- 对象存储 OSS(S3 兼容)--- 转码产物 -----------+ ``` **区域选择**:首选**雅加达**(阿里云 / 腾讯云 / AWS 均有区域),退路是新加坡 (ap-southeast-1,到雅加达 RTT 约 20–30ms,仍可接受)。依据是到用户 RTT、CDN 覆盖与本地 PoP 价格、数据驻留要求。 **为什么要 API 网关**:限流、IP 黑名单、WAF、灰度都放在网关层,业务服务不必各自实现一遍。 **国内团队访问生产**:运营后台走独立入口 + 内网跳板,不要与 C 端出口混用。 ## 5. 服务划分与演进 第一阶段**保持模块化单体**,按业务域划清边界,为后续拆分留缝: | 模块 | 职责 | 未来拆分优先级 | | --- | --- | --- | | user | 账号、凭证、会话、资料、风控 | 中 | | content | 短剧、剧集、分类、标签、榜单 | 低 | | media | 上传、转码、媒资、播放票据 | **高**(与 CDN/转码强绑定) | | playback | 进度、记录、收藏、下载授权 | 中 | | interaction | 评论、点赞、举报、分享 | 低 | | commerce | 商品、订单、钱包、权益、对账 | **高**(支付需审计隔离) | | creator | 创作者入驻、内容提交、数据看板 | 中 | | admin/system | RBAC、菜单、审计、配置 | 低 | 拆分只在这两个条件下发生:**独立扩缩容需求**或**合规隔离需求**。其余情况一律不加服务。 ## 6. 数据模型与存储 核心表(现有 `sql/schema.sql` 已有基础,"新增"为需要补充的部分): - 内容域:`drama`、`drama_episode`、`drama_category`、`content_banner`,已具备。 - 媒资域:`media_asset`、`media_upload_task` 已具备;**新增** `transcode_task`、`media_rendition`(多码率产物)。 - 用户域:**新增** `app_user`、`user_credential`、`user_session`、`user_profile`(当前只有后台管理员表)。 - 播放域:**新增** `watch_progress`(user+drama 唯一)、`watch_history`(按月分区)、`user_favorite`、`playback_ticket`。 - 互动域:**新增** `comment`、`comment_reply`、`user_like`、`report`、`blocklist`。 - 交易域:**新增** `product`、`order`、`order_event`、`wallet`、`coin_ledger`、`entitlement`、`receipt`。 - 创作者域:**新增** `creator`、`creator_document`、`content_submission`、`audit_record`。 存储策略: - 大表分区:`watch_history`、`order_event`、`coin_ledger`、`playback_event` 按月分区,保留 12–24 个月。 - 冷热分离:长期不播放的媒资转低频/归档存储,源站只保留热内容。 - 读写分离:报表、导出、后台检索走只读副本,避免影响 C 端。 - 连接池:Hikari 每副本 20–30 连接,按副本数 x 连接数留足 PG `max_connections` 余量。 ## 7. 关键链路设计 ### 7.1 播放与地址签发(第一阶段最重要的改造) 1. 客户端请求 `/app/episodes/{id}/play`,服务端判定权益(已购 > 活动免费 > 免费集 > 试看 > 金币可扣 > 需充值)。 2. 可播放时签发**短时效签名 URL**(建议 15 分钟),签名绑定 `episodeId + userId + 清晰度 + 过期时间`。 3. 返回 HLS master playlist 地址(CDN 域名),CDN 校验签名后才回源。 4. 签名校验失败、过期或用户被吊销,直接 403,客户端提示重新获取。 5. 防盗链:Referer/UA 白名单 + 单账号同时在播设备数限制(建议 1–2 台)。 关键点:客户端拿不到可长期复用的裸地址,也不会出现"服务端扛视频"的情况。 ### 7.2 上传与转码流水线 ``` 创作者分片直传 OSS(STS 临时凭证) -> 合并校验(MD5 / 时长 / 编码探测) -> 写 transcode_task(排队) -> worker 拉起 FFmpeg 或云转码:4 档 HLS + 封面 + 字幕封装 -> 回调写 media_rendition -> CDN 预热 -> 状态回写创作者中心(可发布) ``` 失败重试 3 次并记录原因;转码队列与在线服务隔离(独立节点池或命名空间),避免抢占资源。 ### 7.3 支付与权益 1. 客户端拿到商店票据后提交 `/app/orders/verify`。 2. 服务端**必须**再调 Apple / Google 校验接口二次验证,不信任客户端上报。 3. 订单状态机幂等:以 `(platform, transactionId)` 唯一键去重,重复回调只返回既有结果。 4. 权益发放与订单在同一事务;发放失败进补偿队列,T+1 内自动修复并留痕。 5. 退款与撤销事件(App Store Server Notifications / Google RTDN)触发权益回收或欠款标记,写 `coin_ledger`。 6. 每日对账:拉取商店账单与本地订单比对,差异进入人工处理队列并告警。 ### 7.4 观看进度与记录 - 客户端每 10s 上报一次;服务端写 Redis(`progress:{user}:{drama}`),不直接写库。 - 后台任务每 30s 把 Redis 中的变更按剧合并,批量 UPSERT 到 `watch_progress`(每用户每剧一行)。 - `watch_history` 按事件追加、按月分区,用于"最近观看"与后续推荐。 - 冲突规则:以 `updatedAt` 较新者为准;同秒冲突取进度较大者,避免进度倒退。 ### 7.5 计数与埋点 播放数、完播数、点赞数一律走消息队列,消费者按窗口聚合后定时写回计数表。 读取计数走缓存,允许秒级最终一致,不允许为了强一致把写压力压到主库。 ## 8. 高并发与稳定性手段 | 手段 | 落点 | | --- | --- | | 多级缓存 | 客户端本地缓存 > CDN > Redis > Caffeine 本地缓存 > PG | | 读缓存 | 首页/详情/分类结果缓存 30–300s,运营改动通过版本号主动失效 | | 异步化 | 进度、计数、埋点、转码、对账全部异步 | | 合批 | 进度上报合并写、计数聚合写、日志批量落盘 | | 限流 | 网关按 IP/设备/用户三维限流,重点保护 OTP 与票据签发 | | 熔断降级 | 短信通道、商店校验、审核供应商失败时降级并告警;播放链路的降级是"降码率"而不是"不可播" | | 幂等 | 订单、回调、注册、上传合并全部幂等键化 | | 游标分页 | 列表接口用 cursor 而非深 offset,避免大偏移查询 | | 连接管理 | 视频分片走 CDN,API 走 HTTP/2 keep-alive,PG 连接池按副本配额 | | 压测门禁 | 上线前通过 1 万并发播放 + 1,000 QPS 接口压测,错误率 < 0.1% | ## 9. 可观测性与 SLO | 指标 | 目标 | 告警阈值 | | --- | --- | --- | | 接口可用性 | 99.9% | 5 分钟错误率 > 1% | | 接口延迟 P95(客户端热点接口) | < 50ms | > 100ms 持续 5 分钟 | | 首帧 P95 | < 1.5s | > 2.5s | | 卡顿率 | < 2% | > 4% | | CDN 命中率 | >= 98% | < 95% | | 单位播放成本 | 有基线并有月度预算 | 超预算 20% | | 支付成功率 | > 97% | < 95% | 埋点与看板分四层:接口层(QPS/延迟/错误码)、播放层(起播/卡顿/完播/ERROR_CODE)、 业务层(注册/首播/解锁/支付)、成本层(CDN 流量/存储/短信条数)。 链路追踪覆盖"支付"与"播放票据签发"两条关键链路。 ## 10. 安全与合规(印尼) - **合规**:Kominfo **PSE 注册**(未注册可能被整体封锁);UU 27/2022 个人数据保护(明示同意、删除权、导出权、跨境传输依据);内容分级(R13/R17/R21)与色情、宗教、政治敏感内容零容忍。 - **应用安全**:网关 WAF;接口越权(水平 + 垂直)全量校验;密钥集中托管并支持轮换;后台敏感操作二次确认 + 审计留痕。 - **支付安全**:服务端票据二次校验;防重放(nonce + 唯一键);金额与商品以服务端配置为准。 - **内容保护**:签名 URL + 短时效 + 并发设备限制;第一阶段不上 DRM,但 URL 结构与接口要为第四阶段 DRM 预留。 - **数据分级**:手机号、邮箱、设备标识、支付标识分级存储与脱敏;日志与埋点禁止写入 PII 明文。 ## 11. 上线与扩容路径 1. **环境**:dev / test / staging / prod 四套,配置外置,密钥不入库不入 Git。 2. **压测**:阶梯加压到 1 万并发播放(走真实 CDN 链路)+ 1,000 QPS 接口,记录水位与瓶颈。 3. **灰度**:先 5% 流量,观察起播、卡顿、错误率与支付成功率,再逐步放量。 4. **回滚**:镜像与配置双版本共存,一键回滚;数据库变更必须向后兼容(先加字段、再切读写、最后清理)。 5. **扩容触发线**:API 副本 CPU > 60% 或 QPS 超过设计值 70%;转码队列积压 > 30 分钟;CDN 命中率 < 95%。 6. **灾难恢复**:数据库 PITR + 每日全量备份(跨可用区),目标 RPO <= 15 分钟、RTO <= 2 小时,季度演练一次。 ## 12. 与第一阶段工作包的对应关系 | 评估表模块 | 后端承担的部分 | 优先级 | | --- | --- | --- | | 01 基础与交付准备 | 服务骨架、OpenAPI 契约、ERD、CI/CD、环境与监控 | P0 | | 02 用户账号与登录 | 用户域、OTP 与风控、会话与令牌、注销与导出 | P0 | | 03 内容发现与详情 | 内容目录、搜索、分类榜单、可见性规则、缓存 | P0 | | 04 播放器与播放控制 | **票据与签名 URL、转码与 ABR 片源、进度与续播接口、播放事件** | P0 | | 05 记录、收藏与下载 | 进度存储与合并、收藏服务、下载授权与设备绑定 | P0 | | 06 评论、点赞与分享 | 点赞与评论服务、内容治理联动、分享落地页接口 | P1 | | 07 创作者中心 | 入驻与审核流、分片上传、转码流水线、媒资与状态服务 | P0 | | 08 平台运营后台 | RBAC 与审计、内容/用户/订单管理、大盘数据接口 | P0 | | 09 分集收费与支付 | 钱包与订单、票据校验、权益决策、退款与对账 | P0 | | 10 质量、数据与上线 | 压测与容量报告、安全测试、埋点验收、发布与 DR Runbook | P0 | 建议的开发顺序(后端视角): 基础骨架与契约 → 账号与鉴权 → 内容目录与缓存 → 媒资上传与转码 → 票据与签名播放 → 进度与收藏 → 支付与权益 → 运营后台与治理 → 压测与上线准备。 其中"票据 + 签名 URL + 转码"是第一阶段风险最高、最不该压缩的链路。