短视频这行的技术服务,最容易被外界误解的一点是:大家看到的是推荐算法多神、内容生态多繁荣,但真正决定一个平台能不能活下来、能不能赚钱的,是底下那层“流量承载”的骨架。这套骨架没做好,算法再准也会被卡顿和加载失败拖垮;骨架做得太贵,商业模式再漂亮也会被带宽账单吃干净。这里我用“某头部短视频平台”(下文统一简称“平台”)来指代研究对象,不点名、不引用具体业务数据,只讲这套海量流量承载技术架构与商业模式之间的耦合关系,以及一个从业者在真实场景里会怎么拆、怎么算、怎么避坑。适合做后端架构、CDN/边缘计算、音视频链路、增长与商业化技术支撑的同行参考,也适合产品与运营同学理解“为什么某些需求技术上就是做不了”。
1. 先把问题拆开:所谓“海量流量承载”到底在承什么
1.1 用一次量级推演把模糊的“海量”变成具体数字
“海量”这个词在汇报里很好用,在架构评审会上毫无意义。我喜欢在项目启动时先把词换算成三个数字:日播放次数、日均出网流量、峰值带宽。这里做一个纯教学性质的推演示例,不代表任何真实平台的数据:假设日均播放 200 亿次,平均单次有效观看时长 30 秒,平均传输码率 1.5 Mbps。那么一天的出网数据量约为 200亿 × 30s × 1.5Mbps ÷ 8 ≈ 1.125×10¹⁶ 字节,也就是约 11 PB/天。把它摊到 86400 秒,平均出网带宽约 130 GB/s,折算成比特约 1 Tbps 量级;再按晚高峰 2.5 倍的峰均比做容量规划,峰值就要预留 2.5~3 Tbps 的出网能力。
这个推演的价值不在于数字准不准,而在于它立刻把问题分层了:11 PB/天这种量级,绝不可能靠自建机房扛下来,必须先靠分发网络把绝大部分请求消化在离用户几十公里内;1 Tbps 的峰值也决定了你不可能按峰值长期包带宽,必须做弹性与错峰。很多人做容量规划时只算平均值,结果一到晚八点就雪崩,原因就在于忽略了短视频这种“晚间集中爆发 + 单次时长短 + 请求数极多”的流量形态。它跟长视频的点播完全不是一回事,长视频单次会话长、并发会话数少,而短视频是海量短会话、超高 QPS、极高频的调度决策。
1.2 承载的三条线:可用性、体验、成本,缺一条都不算成
我习惯把“承载能力”拆成三条互相拉扯的线。第一条是可用性线,核心指标是核心接口成功率与分发侧的可用率,这条线守的是“别挂”。第二条是体验线,核心指标是首帧时间、卡顿率、二次缓冲比例,这条线守的是“别卡”。第三条是成本线,核心是单位播放带宽成本与单位转码成本,这条线守的是“别亏”。这三条线天然冲突:想不卡,就多预加载、多铺边缘节点、码率给足,成本立刻上去;想省钱,就压码率、收缩边缘覆盖,体验马上掉;想两边都保,就得在调度策略上做极精细的取舍。
真实项目里最容易出的问题,是三条线由三个不同团队各自优化,最后互相打架。播放团队为了降卡顿把预加载拉满,CDN 成本爆炸;成本团队一刀切降码率,卡顿率上升;可用性团队为了稳把限流阈值设得很保守,高峰期大量正常用户被误伤。所以我一直主张,海量流量承载的技术架构必须由一套统一的指标体系来驱动,把成功率、首帧、卡顿率、单位成本放在同一张看板上,任何一个策略上线前都要回答:它让哪条线变好、哪条线变差、净收益是多少。
提示:容量规划别只写“支撑千万级并发”,要写成“在峰均比 X、平均码率 Y、首帧目标 Z 毫秒的条件下,需要多少边缘容量与回源带宽”。模糊的容量描述在评审会上等于没写。
2. 整体架构的设计主线:分层削峰,就近服务
2.1 五层结构以及每层为什么必须存在
平台级流量承载,我通常画成五层:接入层、调度层、服务层、存储层、计算层。接入层解决“连接怎么进来”,包括四层/七层负载、协议优化、连接复用;调度层解决“请求该去哪”,包括全局流量调度、就近接入、灰度与容灾切换;服务层解决“业务逻辑怎么跑”,包括微服务拆分、限流熔断、异步化;存储层解决“数据放哪”,包括冷热分层、多副本、对象存储与元数据分离;计算层解决“重活谁来干”,主要是转码、审核、特征计算这类离线与近线任务。
这五层不是画着好看的,每一层都对应一类必须被隔离的故障。举个最常见的例子:转码是典型的 CPU/GPU 密集型任务,如果不把它从在线服务层彻底剥离出去,一次大 V 集中发稿导致的转码排队,会直接把在线接口的 CPU 抢光,用户端表现为“刷不出来”。我见过不止一个团队在这个坑里栽过,本质就是把“在线请求”和“离线重计算”混在同一个资源池里,缺了物理或逻辑上的资源隔离。
另一个容易被忽略的是元数据与内容本身的分离。视频文件走对象存储 + 分发网络,而视频的标题、作者、状态、权限、计数这类元数据走在线数据库与缓存。这两者的访问模式天差地别:内容是一次写入、海量顺序读,元数据是高频随机读写、强一致要求高。把它们混在一套存储里,最后一定是两边都不讨好。
2.2 为什么是“边缘优先”而不是“中心堆机器”
新手常有的直觉是:流量大就加机器、扩机房。这条路在短视频场景里走不通,原因很简单——物理距离带来的时延是加机器解决不了的。光在光纤里跑,1000 公里单程就要 5 毫秒左右,往返 10 毫秒,再加上中间若干跳设备的处理时延,跨区域访问很容易到几十毫秒。而首帧时间的目标通常在几百毫秒内,其中留给网络传输的预算可能只有一两百毫秒。你不可能让所有用户都回中心机房取数据。
所以架构主线一定是边缘优先:把热门内容提前推到离用户近的节点,让绝大多数播放请求在边缘就被满足,回源只发生在缓存未命中或者内容冷门的时候。衡量这套体系好不好,核心就看两个数:边缘命中率和回源带宽占比。命中率每提升一个百分点,回源带宽和中心机房的压力都线性下降。我做过的一个项目里,把命中率从 92% 提到 96%,回源带宽直接砍掉一半,因为回源量本来就是那剩下的 8%,砍一半等于省下 4% 的总流量,而这 4% 往往是成本里最贵、最不可控的那部分。
与之配套的是“热度分级”。新发布的内容先在中心或区域中心待着,观察一小段时间的播放增速,增速够快的才逐级往更边缘的节点推。这套机制听起来简单,但阈值设不好会出大问题:阈值太宽松,冷内容占满边缘存储,热门内容反而推不进去;阈值太严格,热点内容推得慢,用户在爆发期疯狂回源,形成回源风暴。后面第 7 节会专门讲这个坑。
3. 播放链路拆解:从一次点击到第一帧画面
3.1 调度层做的其实是一道“多目标最优化题”
用户点开视频,第一个动作不是拉流,是问调度层“我该去哪个节点”。这道题的目标函数看着简单——最快拿到数据——但约束条件极多:节点剩余带宽、节点负载、用户所在网络、运营商归属、节点健康状态、内容是否在该节点有缓存、成本权重。实际实现里通常是一个加权打分模型,把候选节点的各项指标归一化后加权求和,取最高分。权重是可调的,这也是运营手段介入技术的地方——比如在某段时间把成本权重调高,让部分请求走更便宜的链路。
调度层最怕的是“决策过度集中”。如果所有客户端都向同一个中心调度服务请求节点分配,这个服务本身就成了单点。常见做法是多级调度:客户端内置一份粗粒度的调度配置,定期更新;请求先打到就近的调度接入点,接入点本地就有一份节点健康视图,能做快速决策,只有异常情况才向上追问。这样即便中心调度短暂不可用,边缘调度还能靠本地视图继续工作一段时间。
# 调度配置的动态下发与本地兜底(示意) # 客户端侧:优先用本地缓存配置,超过有效期再拉取 GET /sched/config?app_ver=xxx&isp=xxx®ion=xxx # 响应里带 ttl,客户端按 ttl 缓存 # 若拉取失败,继续使用本地旧配置,并在退避后重试这里有个非常实际的细节:配置的 TTL 设多长。设短了,配置服务压力大,且网络抖动时容易拉不到;设长了,节点故障时客户端还在往坏节点上打。我的经验是按业务分级,播放调度配置给较短的 TTL 并允许失败降级到旧配置,而一些非关键的展示配置可以给很长的 TTL。降级到旧配置这个设计必须从一开始就做进去,别等到出事才想起来加。
3.2 分片、预加载与自适应码率:三件套怎么配合
视频不是一次性下载完再播,而是切成若干秒的小分片,边下边播。分片长度是个典型的两难:分片太长,起播要等更多数据,首帧变慢;分片太短,请求数暴增,连接建立和协议开销占比上升,调度层压力更大。常见折中是 2~4 秒一片,同时在起播阶段额外做一个更小的“首片”,专门为了快速出画。
自适应码率(ABR)是体验与成本之间的调节阀。客户端根据实时下载速度、缓冲区余量、设备解码能力选择下一片的码率档位。缓冲充裕就往上探,缓冲告急就往下掉。这套逻辑的调优点很多,我最关注两个:下探的灵敏度与上探的保守度。下探太迟钝,用户已经卡了才降档;下探太激进,网络轻微抖动就掉清晰度,用户会觉得“怎么老是糊”。上探太激进,刚升上去又掉下来,来回抖动比一直低码率还难受。实践里通常给上探加一个“缓冲区必须高于某水位且稳定若干秒”的条件,宁可慢一点升。
预加载则是把双刃剑。合理的预加载是在用户还没滑到下一条时,提前拉取首片和少量元数据,让切换看起来无缝。做过头就是浪费:用户可能根本不看下一条,你预加载的流量全白花,成本上升还可能挤占当前视频的带宽。我的建议是预加载只做首片、只做弱网不友好的档位(低码率首片),并且要能被用户快速滑动时的取消信号及时打断。
3.3 CDN 成本与命中率的拉锯,以及一份实用的缓存策略
分发网络的计费通常是按流量或按带宽峰值,两者差别很大。按流量计费适合流量波动大但峰值不极端的场景,按带宽峰值计费适合流量稳定可预测的场景。多数平台的真实做法是混合:基础量走带宽包,超出部分走流量计费,用这种方式锁定成本上限又保留弹性。
缓存策略是控制成本最直接的手段。下面这份策略表是我在多个项目里反复调过的结构,仅供参考:
| 内容类型 | 缓存位置 | TTL 策略 | 说明 |
|---|---|---|---|
| 热门视频分片 | 边缘节点 | 长 TTL,配合主动刷新 | 命中率贡献最大,值得占存储 |
| 普通视频分片 | 区域中心 | 中等 TTL | 边缘放不下,退一层 |
| 冷门视频分片 | 中心源站 | 短 TTL 或不缓存 | 访问少,缓存反而浪费 |
| 封面图与静态资源 | 边缘节点 | 超长 TTL | 体积小、复用高,几乎无脑缓存 |
| 播放列表/元数据 | 边缘节点短缓存 | 秒级 TTL | 变化频繁,缓存久了会看到错误状态 |
注意:TTL 不是越长越好。视频被下架、被设为私密、被替换封面,这些状态变化必须能及时生效。所以长 TTL 必须配一套主动失效通道,否则会出现“内容已删但还在被播放”的尴尬情况,这在合规层面是很麻烦的事。
4. 上传与转码链路:把不可控的输入变成可控的资产
4.1 上传环节的稳定性设计,比播放更考验功底
播放链路是“读”,可以靠缓存和分发摊平;上传链路是“写”,每一次写入都绕不开中心。短视频创作者的网络环境千差万别,弱网、切换网络、后台被杀,这些情况在上传环节极其常见。所以上传必须具备断点续传能力:文件按固定大小切片,每片独立上传,服务端记录已完成的片序号,客户端重连后先查进度再续传。
切片大小也有讲究。切太小,请求数多、握手开销大;切太大,单片失败重传成本高。常见选择是 1~4 MB 一片,在弱网下再动态调小。另一个关键点是“上传与发布解耦”:上传完成不等于发布成功,中间要经过审核、转码、元数据落库等环节。很多产品在这里做得不好,用户点了发布就卡在“发布中”,其实是后台还在排队转码。正确做法是把状态机做清楚,让用户看到明确进度,同时允许后台继续跑,用户退出 App 也不影响。
# 上传状态机的简化示意(伪代码) states = ["INIT", "UPLOADING", "UPLOADED", "TRANSCODING", "REVIEWING", "PUBLISHED", "FAILED"] def advance(task, event): if task.state == "UPLOADING" and event == "all_chunks_done": task.state = "UPLOADED" enqueue_transcode(task) elif task.state == "TRANSCODING" and event == "transcode_ok": task.state = "REVIEWING" enqueue_review(task) elif task.state == "REVIEWING" and event == "review_pass": task.state = "PUBLISHED" else: # 任何环节失败都要能回到可重试状态,而不是直接 FAILED 死掉 task.state = "FAILED" task.retryable = True这段代码的重点不是语法,而是那个retryable标记。我见过太多实现是失败即终态,用户只能重新上传一遍,体验极差且浪费带宽。
4.2 转码流水线:算力调度才是真正的成本黑洞
转码是把各种五花八门的原始文件统一成若干标准档位的过程。档位设计要平衡覆盖面和成本:档位太多,存储和转码算力翻倍;档位太少,弱网用户被迫看高码率卡顿,或者强网用户看到模糊画面。常见做法是三到五档,从低清到高清,再配一个只在大屏或强网下使用的更高档。
编解码器的选择直接决定成本。用通用 CPU 做软件编码,质量好、灵活,但吞吐低、功耗高;用硬件编码器,吞吐高、单位成本低,但质量和参数粒度会受限。实际生产里通常是混合:主力档位走硬件编码保吞吐,对质量敏感的高档位走软件编码。这里给一个粗略的算力估算思路,帮助理解为什么转码这么吃资源:假设单路 1080p 视频的软件编码速度是实时的 2 倍(即 60 秒视频需要 30 秒 CPU 时间),一天有 500 万条投稿、平均每条 45 秒,那么一天需要的 CPU 时间约为 500万 × 45 ÷ 2 = 1.125 亿秒,约 31250 CPU 小时。按单机 32 核满打满算,至少需要 1000 台机器全天不停跑。这个量级下,硬件编码带来的成本差异是千万级的。
转码任务必须进队列,按优先级调度:头部创作者、热点内容优先,普通内容排队。队列积压是常态,关键是要有积压监控和自动扩容。我踩过最难受的一个坑是队列积压时没有降级策略,所有投稿都卡在“处理中”,创作者以为是平台故障,实际上只是排队。后来加了两条规则:一是积压超过阈值时,先只转低档位,保证能发出来,高档位延后补转;二是给用户展示预计等待时间,哪怕不准,心理感受也好很多。
# 转码参数的参考写法(ffmpeg 示意) ffmpeg -i input.mp4 \ -c:v libx264 -preset veryfast -crf 23 \ -vf "scale=-2:720" -maxrate 2000k -bufsize 4000k \ -c:a aac -b:a 96k -ac 2 \ -movflags +faststart \ output_720p.mp4-movflags +faststart这个参数特别值得说一句:它把索引信息挪到文件头部,让播放器不用下载整个文件就能开始播放。忘了加它,首帧时间会莫名其妙地变长,而且这个问题很难从日志里看出来,属于典型的“一行参数坑半天”。
5. 服务端稳定性:限流、降级、多活三件套
5.1 限流要设三道闸门,而不是一道
只设一道全局限流是很危险的,因为全局阈值一旦被触发,受影响的是所有用户,包括正常用户。我的做法是三道闸门叠加:第一道是接入层的连接数与 QPS 限制,按 IP、按设备、按接口维度做粗粒度拦截,主要防刷和防单点打爆;第二道是服务层的并发度与熔断,保护下游依赖,某个下游慢了就快速失败而不是排队堆积;第三道是业务层的用户级配额,比如单用户单位时间内的请求次数上限。
这三道闸门的作用不同:第一道保集群不被瞬间打穿,第二道保调用链不被慢依赖拖死,第三道保资源不被少数用户占满。缺了第二道,最常见的结果是线程池被打满,整个服务假死,连健康检查都超时,最终被负载均衡摘掉,形成连锁雪崩。这种故障的排查难度很高,因为日志里全是超时,看不出根因。
# 服务层限流与熔断的配置示意 rate_limit: endpoint: "/api/v1/feed" strategy: "token_bucket" qps: 80000 burst: 120000 circuit_breaker: target: "recommend_service" error_rate_threshold: 0.3 window_seconds: 10 min_requests: 200 open_duration_seconds: 5 timeout: connect_ms: 100 read_ms: 300超时设置这里有个经验:一定要设置成“下游超时 < 上游超时”,形成超时递减。否则下游还没超时,上游先超时并重试,重试流量又打到还没处理完的下游,雪崩会加速而不是缓解。我这边的习惯是每往上一层加 50~100 毫秒的余量。
5.2 降级清单要在平时就写好,出事时才不至于乱砍
降级不是出事时临时决定,而是提前列清单。清单里每一项都要写清楚:降级触发条件、降级后用户看到什么、恢复条件、谁有权操作。以下是短视频场景里一份典型的降级优先级排序,从“最先砍”到“最后砍”:
| 优先级 | 可降级项 | 降级后影响 | 触发条件参考 |
|---|---|---|---|
| 1 | 非核心动效与装饰性接口 | 页面朴素些 | 核心接口 P99 超过阈值 |
| 2 | 预加载提前量 | 切换略慢 | 带宽逼近上限 |
| 3 | 推荐结果的多样性探索位 | 内容同质化上升 | 推荐服务负载过高 |
| 4 | 高清档位可选范围 | 清晰度上限下降 | 出网带宽告急 |
| 5 | 评论、点赞的实时刷新 | 数据延迟更新 | 写入压力过大 |
| 6 | 部分区域的非核心功能 | 功能不可用 | 区域级故障 |
这张表的价值在于它把“要不要牺牲体验”变成了一道有排序的选择题。真到了那一刻,值班同学不需要请示,按表执行就行。我强烈建议每个团队都维护这么一张表,并且每季度演练一次。演练时故意把某个依赖打断,看看降级是否真的按预期生效——很多降级开关平时压根没被触发过,真开的时候才发现开关接错了服务,这种事我遇到过两次。
5.3 多活不是买两套机房那么简单
多活的常见误区是把“有备份”当成“多活”。真正多活要解决三件事:流量能不能切、数据能不能对、切过去之后能不能扛。流量切换相对容易,调度层改权重即可,但要注意 DNS 缓存和长连接的存在,切换不是瞬时的,可能几分钟内新旧流量混杂。数据一致性更难,尤其是用户发布内容、关注关系、计数这类数据,跨地域同步总有延迟,切流时要决定是牺牲一致性还是牺牲可用性。
单元化是我比较推荐的路径:按用户维度把流量和数据切成若干单元,每个单元内部闭环,单元之间尽量不跨调用。这样单个单元出问题,影响面被限制在单元内,而不是全站。代价是单元之间的社交关系、内容分发会变复杂,跨单元读要走异步或本地缓存。我的经验是先把“读”跨单元的问题解决掉,写的问题用异步补偿慢慢收敛,不要一上来就追求强一致,那样架构会重得走不动。
容灾演练必须做真实的切流,不能只看监控面板。有个细节特别容易被忽略:切流之后,缓存是冷的。原本靠边缘缓存扛住的流量,切到新机房后全部回源,新机房瞬间被打爆。所以切流预案里必须包含缓存预热步骤,或者至少把切流速度控制得足够慢,让缓存逐步建立。
6. 技术架构如何长成商业模式
6.1 流量分发本身就是商业模式的第一层
很多人把技术架构和商业模式分开看,其实在这类产品里,流量分发机制本身就是商业模式。平台每天产生海量曝光机会,这些曝光怎么分配给内容、分配给广告、分配给直播和商品,直接决定了收入结构。技术上,这层通常是一个多路召回加排序的系统:内容候选、广告候选、直播候选各自召回,然后统一排序。排序的目标函数不是单一的点击率,而是点击率乘以单次曝光的期望收益,再叠加用户体验约束。
这里的技术难点在于,商业目标和体验目标要在同一个排序框架里融合,而不是两套系统打架。如果广告单独走一个通道强行插入,用户体验会明显受损;如果完全按体验排序,商业化又上不去。常见的做法是给商业内容一个“体验成本折算”,让它参与统一排序但被扣分,扣分幅度由策略侧调节。这套机制的实现不复杂,难的是评估:你怎么知道扣分幅度调多少合适?答案是必须做长期指标观测,只看短期点击率一定会调过头。
创作者激励也是同一套逻辑的延伸。新内容需要冷启动曝光,否则永远没机会被验证;但冷启动曝光又占用了本可以变现的流量。技术上通常用流量池分级:新内容先进小流量池,根据完播、互动等信号决定是否放量。这套机制的设计要点是给足样本量与观察窗口,样本太小噪声大,容易误杀好内容;窗口太短,慢热内容起不来。
6.2 直播、电商、本地生活对技术架构提出的新增要求
从纯内容到直播,架构上加的是“实时”。推流端要稳定编码上传,服务端要低延迟转封装与分发,播放端要能在秒级内追上直播进度。直播的容量规划和点播完全是两种模型:点播靠缓存摊平,直播是“一份流、多人看”,边缘节点的扇出能力成了关键。一场大场直播,可能是几百万人在同一时刻看同一路流,这时候边缘节点的带宽和并发连接数直接决定成败。所以直播场景里,节点选择策略会更偏向“连接数承载能力”而不是“缓存命中”。
电商带来的则是交易链路:下单、支付、库存扣减、订单状态。这条链路对一致性的要求远高于内容消费。库存超卖是绝对不能接受的,所以库存扣减必须走强一致的路径,通常用数据库行锁或者预扣减加异步确认。支付回调要考虑重复通知,必须幂等。这些在电商领域是常识,但放到内容平台的技术栈里,往往需要新建一套能力,而不是改造现有服务。
本地生活又多了一层“地理位置”。用户看的内容与门店的距离强相关,这要求召回和排序都能处理地理索引,同时对地图类数据的更新频率有要求。技术上通常用地理网格编码加多级索引,配合缓存来承载高频的位置查询。
| 业务形态 | 新增技术诉求 | 关键指标 | 典型风险 |
|---|---|---|---|
| 短视频内容 | 高并发读、缓存分发 | 首帧、卡顿率、命中率 | 回源风暴、热点击穿 |
| 直播 | 低延迟扇出、连接数承载 | 延迟、卡顿、断流率 | 大场并发打爆边缘 |
| 电商 | 强一致交易、幂等 | 下单成功率、超卖率 | 库存超卖、重复扣款 |
| 本地生活 | 地理索引、门店数据时效 | 距离准确度、门店可用率 | 门店信息过期导致履约失败 |
7. 成本账、常见问题与踩坑实录
7.1 把成本算清楚,架构决策才有依据
讨论架构不谈成本就是耍流氓。以分发成本为例,假设边缘命中率 95%,总出网 11 PB/天,那么回源量约 550 TB/天。边缘流量单价通常低于回源流量单价(因为回源往往跨区域、走骨干),假设边缘单价为 A、回源单价为 1.8A,则日成本约为 11 PB × 95% × A + 0.55 PB × 1.8A。可以看到,即便回源只占 5%,由于单价更高,它在总成本中的占比可能接近 10%。这解释了一个反直觉的现象:优化回源单价的收益,有时比提升命中率更直接。
转码成本同理。前面算过,纯软件编码一天需要上千台机器。如果其中 70% 的档位能切到硬件编码,单位成本可能下降一半以上。但硬件编码不是免费的午餐,它带来的是质量评估体系的重建:因为硬件编码的参数粒度不同,原来那套基于软件编码的质量阈值全部要重测。这一步很多团队会偷懒,直接沿用旧阈值,结果上线后画质投诉上升。
7.2 常见问题速查表
下面这张表是我这些年被问得最多、也是我自己踩过的问题汇总,按“现象—可能原因—排查动作”组织,可以直接拿去当值班手册的初稿。
| 现象 | 可能原因 | 排查动作 |
|---|---|---|
| 首帧时间突增但成功率正常 | 调度指向了远节点 / 首片未预热 | 看调度决策日志与首片命中率 |
| 卡顿率上升但带宽没涨 | 码率档位切换抖动 | 看 ABR 切换频次与缓冲水位分布 |
| 回源带宽暴涨 | 热点内容未被推到边缘 / TTL 失效 | 查热点列表与边缘缓存状态 |
| 发布一直卡在处理中 | 转码队列积压 / 状态机未推进 | 查队列深度与任务状态分布 |
| 某区域整体不可用 | 区域节点故障 / 调度未摘除 | 查节点健康上报与调度权重 |
| 接口 P99 飙升但 CPU 不高 | 下游依赖慢导致线程堆积 | 查下游耗时分布与线程池状态 |
| 切流后新机房被打爆 | 缓存冷启动 + 切流过快 | 降切流速度、做缓存预热 |
| 用户看到已下架内容 | 长 TTL 未配主动失效 | 查失效通道与缓存刷新记录 |
7.3 几条用真金白银换来的经验
第一条,热点内容的推边缘要做“预判”而不是“事后”。等监控发现某个内容播放量飙升再去推,往往已经晚了几十秒,这几十秒的回源量足以把源站打出一个坑。做法是对发布初期的播放增速做实时统计,增速超过阈值就提前推,宁可多推一些冷内容浪费一点存储,也别让源站挨打。
第二条,所有限流和降级开关必须有“演练模式”。平时不演练,出事时开关大概率是失效的,因为代码路径早就被改坏了没人发现。我现在要求关键开关每季度至少触发一次,在低峰期做,看监控是否符合预期。
第三条,缓存预热要当成切流预案的强制步骤。前面提过一次,这里再强调:新机房或新节点的缓存是空的,直接接流量等于把所有请求都变成回源。预热可以简单到用历史热门列表批量回源拉一遍,成本很低,收益极大。
第四条,别迷信单一大档位。曾有一段时间流行“统一高清”,结果弱网用户体验崩了。多档位 + 智能选择才是正解,但档位设计要克制,每增加一个档位,存储和转码成本都要乘一遍,评估时把这两笔账一起算。
第五条,状态机比接口重要。上传、发布、审核、结算这些流程,接口写得再漂亮,状态机设计错了就是一堆脏数据。我的习惯是先画状态迁移图,把所有异常分支列全,再动手写代码。这个习惯帮我省下的返工时间,比任何性能优化都多。
最后分享一个我自己一直在用的判断标准:当你面对一个架构选择拿不定主意时,问自己“这个方案在出故障时,我能不能在五分钟内说清楚问题出在哪一层”。能,就选它;不能,说明抽象层没做对,先别急着上量。海量流量承载这件事,真正的门槛从来不是能不能扛住峰值,而是出问题时你能不能快速定位、快速止损、快速恢复——这套能力,是靠一次次演练和一张张清单堆出来的,没有捷径。