短视频播放量(Views)计数系统实现方案:高并发、不丢数的工业级实践

〇、前言

在短视频平台后端架构中,视频播放量(Views)计数是最基础也最核心的需求之一。看似简单的"每播放一次计数+1",在头部爆款视频的瞬时高并发场景下,很容易出现数据库崩溃、数据丢失、计数错乱等问题。

本文将围绕"如何实现一个高可用、高性能、数据安全的视频播放量计数系统"展开,从业务痛点出发,拆解完整链路设计、技术选型、数据库更新方式、异常处理及热点优化,给出可直接落地的工业级方案,帮你避开落地过程中的所有坑。

核心目标:支撑每秒万级甚至十万级并发写入,保证数据实时性(秒级延迟)、持久化(不丢数),解决爆款视频带来的系统瓶颈。

一、核心业务背景与痛点拆解

在动手设计系统前,先明确核心业务场景和痛点,这是所有设计的出发点:

业务背景:负责短视频平台后端架构,需实现视频播放量(Views)计数系统,用户点击播放视频后,播放量需实时更新(允许秒级延迟),且数据必须最终落库,不能因系统重启、故障丢失。

核心痛点:头部爆款视频瞬时流量极高,若每次播放都直接执行MySQL的UPDATE操作,会导致数据库行锁竞争严重,IOPS瞬间打满,进而引发数据库卡顿、接口超时,甚至整个服务雪崩。

基于这个痛点,我们确定核心设计原则:不直接让高并发请求穿透到MySQL,通过多级缓存、异步处理、批量落库等方式,分流减压,同时保证数据一致性和实时性。

二、完整链路设计:从用户播放到数据落库

整个计数系统的核心链路,核心是"分流减压、异步持久化",避免高并发直接冲击数据库,完整链路如下(从用户点击播放到数据最终落库):

复制代码
用户播放请求 
→ API服务(校验合法性) 
→ 本地内存缓存(1s窗口合并计数) 
→ Redis集群(原子自增计数) 
→ 异步任务(定时/定量刷库) 
→ MySQL(最终持久化)

各环节核心作用拆解,帮你理解每一步的价值:

  • API服务:校验视频合法性(避免无效播放计数),接收用户播放请求,不直接处理计数逻辑,快速响应前端;

  • 本地内存缓存(Caffeine/Guava):做1秒窗口的计数合并,比如1秒内1000次播放,只合并成1次写Redis,大幅降低Redis的QPS压力;

  • Redis集群:核心计数组件,通过INCR/INCRBY原子命令实现高性能计数,单实例可支撑10万+ QPS,扛住高并发写入;

  • 异步任务(XXL-Job/Quartz):定时(推荐3秒)或定量(累计增量达一定阈值)从Redis读取增量数据,批量刷写到MySQL,实现异步削峰;

  • MySQL:最终持久化存储播放量,只接收批量增量更新,避免高频单条更新带来的行锁竞争。

关键亮点:不直接写数据库,通过"本地缓存+Redis"双重抗流量,异步批量落库解放MySQL,既保证高性能,又满足实时性和持久化需求。

三、核心技术选型:各组件作用与选型建议

技术选型的核心是"适配高并发、易落地、可扩展",根据平台规模,分为最简必选方案和高可用增强方案,各组件作用清晰可落地:

1. 必选组件(中小平台,支撑10万+ QPS)

组件 核心作用 选型建议
Redis(主从/集群) 实时计数核心,通过INCR原子命令实现高性能写入,存储实时播放量 Redis 6.0+,开启主从复制,避免单点故障
本地内存缓存 1秒窗口合并计数,削峰减压,降低Redis请求量 Caffeine(性能优于Guava,推荐)
定时任务 定时从Redis读取增量,批量刷写到MySQL,保证数据持久化 XXL-Job(易部署、可监控,适配分布式场景)
MySQL 最终持久化存储播放量,支撑后续数据统计、查询 MySQL 8.0+,合理建索引(视频ID主键)

2. 高可用增强组件(大厂/头部平台,支撑百万级 QPS)

若平台经常出千万级爆款、瞬时流量脉冲极强,可新增以下组件,进一步提升系统稳定性:

  • 消息队列(Kafka/RocketMQ):做流量削峰填谷,用户播放请求先写入MQ,再由消费端批量处理写入Redis,避免瞬时洪峰冲击Redis;同时留存播放行为流水,用于对账、防刷、数据分析;

  • 分布式锁(Redisson):防止多服务实例重复刷库,保证刷库任务幂等性,避免数据重复累加;

  • Redis集群分片:拆分热点Key,分散单节点压力,支撑更高并发。

四、核心细节:数据库更新方式选型(增量 vs 覆盖)

在异步刷库环节,数据库更新方式的选择,直接决定数据是否会丢失、错乱,这也是很多开发者踩坑的重点------必须用增量更新,绝对不能用覆盖更新,具体拆解如下:

1. 两种更新方式定义(以MySQL为例)

(1)增量更新(推荐,工业级标准)

核心逻辑:不直接写总播放量,只计算"这段时间内新增的播放量差值",累加到数据库原有值上。

标准SQL示例:

sql 复制代码
-- @incr 是这段时间的新增播放量差值,@vid 是视频ID
UPDATE video SET views = views + @incr WHERE id = @vid;

(2)覆盖更新(禁止使用,踩坑重灾区)

核心逻辑:从Redis中读取当前的"总播放量",直接覆盖数据库中该视频的原有播放量,完全替代旧值。

错误SQL示例:

sql 复制代码
-- @total 是从Redis读取的当前总播放量
UPDATE video SET views = @total WHERE id = @vid;

2. 为什么禁止覆盖更新?(4个致命问题)

  • 多实例并发刷库,数据覆盖丢失:多个服务实例同时读取Redis总播放量,先后执行覆盖更新,后执行的会抹掉前执行后新增的播放量;

  • 异步延迟导致数据丢失:Redis与MySQL存在秒级延迟,读取的Redis总播放量是旧值,覆盖后会抹掉延迟期间的新增播放量;

  • 故障重试导致数据错乱:刷库失败重试时,再次读取Redis总播放量(已新增),重复覆盖会导致计数错乱;

  • 放大行锁竞争:覆盖更新需"读Redis→写MySQL",多实例并发争抢行锁,回到"直接写MySQL"的原始痛点。

3. 增量更新的核心优势(完美适配场景)

  • 天然支持多实例并发:加法可交换,无论多少实例同时刷库,累加结果永远正确,不丢数;

  • 适配故障重试:即使刷库重试,重复累加增量也可通过对账修正,绝不会少数据;

  • 降低数据库压力:行内累加,SQL执行更快,行锁持有时间短,避免锁竞争;

  • 适配异步延迟:无需强一致,只需累加新增差值,秒级延迟完全不影响数据准确性。

4. 增量更新标准实现(避免重复累加)

工业级标准做法,确保增量计算准确,不重复、不遗漏:

  1. 记录上一次同步时的Redis播放量基数(可存在Redis或MySQL中);

  2. 本次同步时,计算增量 = 当前Redis总播放量 - 上一次基数;

  3. 执行增量更新SQL,将增量累加到MySQL原有值;

  4. 更新基数记录,作为下一次同步的基准。

五、异常处理设计:保证数据不丢、最终一致

高并发系统中,故障不可避免,需针对核心异常场景做兜底,确保数据不丢、最终一致(允许秒级延迟):

1. 场景1:Redis宕机/重启

解决方案:本地内存日志 + Redis持久化兜底

  • 写入Redis前,同时写一份本地日志文件(类似AOF思想),记录播放量增量;

  • Redis开启RDB+AOF混合持久化,重启后自动恢复数据;

  • 若Redis彻底宕机,直接将本地日志中的增量写入MySQL,避免数据丢失。

2. 场景2:异步刷库失败(网络/MySQL宕机)

解决方案:重试机制 + 失败队列兜底

  • 刷库失败时,不删除Redis中的增量数据,下一轮定时任务继续重试(最多重试5次);

  • 若多次重试失败,将增量数据写入失败队列,触发告警,人工兜底处理,确保数据最终落库。

3. 场景3:服务全部重启

解决方案:Redis持久化 + 刷库任务兜底

Redis的RDB+AOF持久化确保重启后数据不丢失,服务启动后,定时刷库任务自动将Redis中未同步的增量数据写入MySQL,无需人工干预。

六、热点处理:解决爆款视频单Key高并发瓶颈

爆款视频会导致Redis单Key热点,10万+ QPS打满单个Redis节点,需在缓存层做优化,彻底解决单点瓶颈,推荐4层优化方案:

1. 本地内存一级缓存(最有效、最廉价)

API服务本地内存做1秒窗口合并计数,同一视频1秒内多次播放,只合并成1次写Redis,将Redis QPS从10万+压到1次/秒。

2. Redis热点Key分片(集群级优化)

将单个视频的Key拆分成多个分片,例如:video:views:10086:0 ~ video:views:10086:9,写入时随机选择一个分片执行INCR,读取时求和所有分片的值,将单节点压力分散到多个Redis节点。

3. Redis主从读写分离

写入操作走Redis主节点,读取操作走从节点,爆款视频的高频读取压力不会影响写入性能,进一步提升并发支撑能力。

4. 热点自动识别 + 动态降级

系统自动识别QPS超阈值的视频(热点视频),自动开启分片+本地缓存合并策略,无需人工干预,适配流量动态变化。

七、方案总结与落地建议

本文给出的播放量计数系统方案,是抖音、快手等主流短视频平台的工业级实践,核心优势的是"高性能、高可用、易落地、可扩展",总结如下:

  • 核心链路:用户播放 → 本地缓存合并 → Redis计数 → 异步批量刷库 → MySQL持久化;

  • 核心组件:Redis(计数核心)+ 本地缓存(削峰)+ 定时任务(刷库)+ MySQL(持久化);

  • 关键细节:数据库必须用增量更新,禁止覆盖更新;热点Key用分片+本地缓存优化;

  • 异常兜底:本地日志 + Redis持久化 + 重试机制,确保数据不丢、最终一致。

落地建议

  1. 中小平台:优先采用最简方案(Redis+本地缓存+定时任务+MySQL),足够支撑10万+ QPS,开发成本低、易维护;

  2. 头部平台:新增Kafka做流量削峰、分布式锁保证幂等性,Redis集群分片支撑百万级QPS;

  3. 上线后:新增对账脚本,每日对比Redis和MySQL的播放量差值,自动修复数据,确保一致性。

相关推荐
苍何2 小时前
我用 Tabbit 浏览器搭了一套内容创作全自动流水线,太香了!
后端
苍何3 小时前
全网首测,TRAE SOLO 的 AI 麦克风!
后端
IT_陈寒3 小时前
Redis这个内存杀手,差点让我们运维半夜追杀我
前端·人工智能·后端
苍何3 小时前
用 Agent 团队来做知识管理,非常顶!
后端
苍何3 小时前
WPS多维表格,给开发者铺了条新路!
后端
修己xj3 小时前
IDEA 报错 “Command line is too long” 的解决方法
后端
子兮曰3 小时前
DeepSeek TUI:原生 Rust 打造的终端 AI 编码 Agent
前端·javascript·后端
子兮曰3 小时前
深入 Superpowers:180k Stars 的开源 AI 编程方法论是如何工作的
前端·javascript·后端
苍何4 小时前
我逆向了 329 条 GPT-Image2 提示词模板,全部开源!
后端