PRJ-02 LIVE
Vistack Vistack 视频平台
distributed live-streaming & vod platform
直播 + 点播一体化的分布式云原生视频平台
- Go
- 分布式
- 音视频
- 云原生
4
个可独立扩容的服务角色(api / worker / transcoder / auth)
240p–4K
FFmpeg 按源分辨率智能选择的 DASH 码率档位
3 件套
缓存穿透 / 击穿 / 雪崩防护全部落地(布隆 + singleflight + 随机 TTL)
1 条命令
docker compose up 起全栈(Traefik + PG + Redis + MinIO + Kafka + etcd)
// 01
问题背景
做这个项目的目标是把「视频平台」这个经典高并发场景真正做成分布式形态,而不是单体能跑的玩具:上传、转码、分发、互动,每个环节都要能独立扩容、能讲清楚取舍。
点播侧的核心矛盾是转码——CPU 密集、耗时长、不能阻塞 API;直播侧需要一个轻量高并发的 WebRTC 分发节点。同时把面试高频的「缓存三件套、限流、计数与榜单」做成真实接入业务的通用组件,而非 Demo 级代码。
// 02
系统架构
接入层
统一入口与协议分发
应用服务层
单二进制 + VISTACK_ROLE 角色分发,四进程独立部署扩容
中间件与队列层
解耦、重试与服务发现
数据与存储层
元数据、缓存与对象存储
// 03
关键技术决策
每一条都包含「为什么这样选」与「代价是什么」——这是我理解这个项目的方式。
Kafka 解耦转码任务,Redis ZSet 做退避重试
转码是分钟级的重任务,绝不能在 HTTP 请求里同步执行。选择 Kafka 而非 Redis Stream,是因为转码、删除、弹幕落库共用一套队列语义,Kafka 的消费组与分区模型更贴合水平扩容。失败任务不直接丢弃,而是进 Redis ZSet 按指数退避重投,另有 Watchdog 兜底「processing 超时」的僵尸任务。代价是要自己保证重投幂等——worker 写库全部包在事务里,用启动与重试路径的确定性换运行期故障的可恢复。
FFmpeg 隔离为独立 transcoder,gRPC + etcd 服务发现
FFmpeg 转码吃 CPU 且依赖宿主环境,放在 api 进程里会拖累接口稳定性、一次崩溃就是整个服务不可用。拆成独立容器后天然无状态(输入输出都走 MinIO),可 docker compose --scale 任意副本。实例向 etcd 注册保活,worker 通过自研 etcd→gRPC resolver 动态发现并 round_robin 负载均衡;同时保留静态地址兜底配置,etcd 不可用时转码链路不至于全瘫。
单二进制多角色,而非四个仓库
api / worker / transcoder / auth 共享同一套配置、模型与基础设施封装,拆成四个仓库会造成依赖地狱。最终用 cmd/vistack 一个入口按 VISTACK_ROLE 分发角色,internal/role 做启动引导。代价是二进制体积略大、任一模块改动触发整体发版,但对独立开发者来说部署与版本一致性的收益远大于成本。
独立 Auth 服务:RS256 + JWKS,api 本地验签
认证拆成独立服务(HTTP :8081 + gRPC :50052),api 通过 JWKS 拉公钥本地验签,鉴权路径零网络跳转;用户详情这类必须查库的请求才走 gRPC 用户查询。对称密钥 HS256 更简单,但无法把验签能力安全地下发给多个服务;RS256 的代价是要管理 kid 与 JWKS 缓存。
互动计数写 Redis,事件队列异步批量落库
点赞 / 收藏 / 播放量直接打库会把热点行锁死。改为 Redis Set 去重 + INCR 计数、Lua 保证 toggle 原子性,变更事件进队列异步批量幂等落库;videos 表冗余计数列 + 明细表双写,热门榜单直接用 ZSet。代价是缓存与 DB 存在秒级不一致,用「落库间隔 / 批量大小」配置在实时性与写压力之间调平。
// 04
我的职责与产出
RESPONSIBILITIES
- 设计并实现四角色进程拆分与单二进制角色分发机制
- 实现 Kafka 转码任务队列、Redis ZSet 退避重试与 Watchdog 超时兜底
- 实现 etcd 服务注册 / 发现与 gRPC resolver 负载均衡
- 实现 DASH 自适应码率转码流水线(ffprobe 探测 → 档位选择 → 分片 → MinIO 回传)
- 实现 Redis 缓存三件套通用组件与分布式限流中间件(令牌桶 + Lua 滑动窗口)
- 设计 RBAC 权限模型与独立 Auth 服务(RS256 / JWKS / gRPC)
OUTCOMES
- 转码能力与 API 完全解耦,transcoder 可用 docker compose --scale 水平扩容
- 上传支持分片 + 秒传 + 断点续传,DASH 240p–4K 自适应播放落地
- 缓存穿透 / 击穿 / 雪崩防护封装为通用组件,接入视频详情与推荐列表
- 一键 Compose 起全栈(含 Traefik / PG / Redis / MinIO / Kafka / etcd),附 Kubernetes 清单
- 用户端与管理端产物可一键发布至 Cloudflare Pages / S3(deploy/cdn-publish.sh)
// 05
踩坑与复盘
最大的坑在分布式任务的一致性:Kafka 消费成功但写库失败、gRPC 转码超时但任务实际仍在跑,这类「中间态」逼着我把重试、幂等、超时兜底拆成三层各自负责。下一步计划接入 Prometheus / Grafana 补齐可观测性(目前只有 zap 结构化日志预留),并把 HLS 与 DASH 双协议输出补齐。
// 06
技术栈
- Go 1.26
- Gin
- gRPC
- etcd
- Kafka
- MinIO
- FFmpeg