为什么: 1) 产品已定名 FruitShorts,但后端仍是 reelshort 系列标识 —— Java 包 com.reelshort、 模块名与 jar 名 reelshort-*、spring.application.name、配置前缀 reelshort.*, 这些会出现在启动日志、命令行和 IDE 里,与产品名不一致。本次整体替换为 fruitshorts, 数据库连接名上一轮已改名,保持不变。 2) 第一阶段下一批第 1 步(05 离线下载)要求把下载授权(设备绑定/有效期/吊销)、 下载任务与断点续传、配额与过期清理、仅 Wi-Fi 规则做成完整接口,本提交一并落地。 3) 顺带修复:schema-phase1.sql 里 playback_ticket / order_event 仍按普通表定义唯一索引, 表分区化之后重跑脚本必定报错(分区表的唯一索引必须包含分区键)。改为在本脚本里就 按分区表定义,并验证脚本可重复执行。
17 KiB
后端服务设计(第一阶段 · 印尼市场 · 1 万并发观看)
版本 v1.0 · 配套 第一阶段 PRD · 现有实现见 架构设计 目标口径:10,000 路并发播放不劣化(对应 DAU 约 25–35 万),首发印尼。
1. 目标与约束
业务目标:日活规模下 1 万路并发观看流畅(首帧 P95 < 1.5s、卡顿率 < 2%),分集收费闭环准确无误,创作者上传到可播放全自动。
工程约束:
- 首发印尼,用户全部在东南亚,服务端与内容必须就近部署,不能用国内机房直连。
- 团队是 14–16 人的 MVP 团队,运维只有 1 人,所以不做微服务拆分,保持模块化单体。
- 数字商品必须走 Apple IAP / Google Play Billing,服务端只做校验与权益发放。
- 成本敏感:视频流量是最大成本项,码率与缓存策略从一开始就要按成本设计。
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%
推论:
- 金币解锁模式下视频成本可忽略;真正的压力来自第二阶段的广告模式(ARPU 低一个数量级时 CDN 会变成主要成本)。
- 因此第一阶段就要把平均码率、缓存命中率、CDN 单价做成看板与告警(单位播放成本 $/千次播放)。
- 把平均码率从 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 播放与地址签发(第一阶段最重要的改造)
- 客户端请求
/app/episodes/{id}/play,服务端判定权益(已购 > 活动免费 > 免费集 > 试看 > 金币可扣 > 需充值)。 - 可播放时签发短时效签名 URL(建议 15 分钟),签名绑定
episodeId + userId + 清晰度 + 过期时间。 - 返回 HLS master playlist 地址(CDN 域名),CDN 校验签名后才回源。
- 签名校验失败、过期或用户被吊销,直接 403,客户端提示重新获取。
- 防盗链:Referer/UA 白名单 + 单账号同时在播设备数限制(建议 1–2 台)。
关键点:客户端拿不到可长期复用的裸地址,也不会出现"服务端扛视频"的情况。
7.2 上传与转码流水线
创作者分片直传 OSS(STS 临时凭证)
-> 合并校验(MD5 / 时长 / 编码探测)
-> 写 transcode_task(排队)
-> worker 拉起 FFmpeg 或云转码:4 档 HLS + 封面 + 字幕封装
-> 回调写 media_rendition
-> CDN 预热
-> 状态回写创作者中心(可发布)
失败重试 3 次并记录原因;转码队列与在线服务隔离(独立节点池或命名空间),避免抢占资源。
7.3 支付与权益
- 客户端拿到商店票据后提交
/app/orders/verify。 - 服务端必须再调 Apple / Google 校验接口二次验证,不信任客户端上报。
- 订单状态机幂等:以
(platform, transactionId)唯一键去重,重复回调只返回既有结果。 - 权益发放与订单在同一事务;发放失败进补偿队列,T+1 内自动修复并留痕。
- 退款与撤销事件(App Store Server Notifications / Google RTDN)触发权益回收或欠款标记,写
coin_ledger。 - 每日对账:拉取商店账单与本地订单比对,差异进入人工处理队列并告警。
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. 上线与扩容路径
- 环境:dev / test / staging / prod 四套,配置外置,密钥不入库不入 Git。
- 压测:阶梯加压到 1 万并发播放(走真实 CDN 链路)+ 1,000 QPS 接口,记录水位与瓶颈。
- 灰度:先 5% 流量,观察起播、卡顿、错误率与支付成功率,再逐步放量。
- 回滚:镜像与配置双版本共存,一键回滚;数据库变更必须向后兼容(先加字段、再切读写、最后清理)。
- 扩容触发线:API 副本 CPU > 60% 或 QPS 超过设计值 70%;转码队列积压 > 30 分钟;CDN 命中率 < 95%。
- 灾难恢复:数据库 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 + 转码"是第一阶段风险最高、最不该压缩的链路。