数据库设计
数据库使用 PostgreSQL + GORM,迁移由 migrate 角色(migrations.AutoMigrate)统一执行。所有表按业务域组织,实体定义在 internal/model/entity/。
ER 总览(按业务域)
text
┌── 用户与权限域 ──┐ ┌── 视频域 ──┐ ┌── 社交互动域 ──┐
│ users │ │ videos │ │ video_comments │
│ user_profiles │ │ video_sources│ │ video_likes │
│ roles │ │ video_transcodes│ video_favorites │
│ authorities │ │ video_manifest│ │ video_play_logs│
│ role_authority │ │ tags │ │ comment_likes │
│ user_authority │ │ video_tags │ └────────────────┘
└──────────────────┘ └────────────┘
┌── 文件域 ──┐ ┌── 弹幕域 ──┐ ┌── 其他 ──┐
│ files │ │ danmaku │ │ audit_logs│
│ │ │ sensitive_words │ └──────────┘
└────────────┘ └────────────┘用户与权限
| 表 | 说明 | 关键列 |
|---|---|---|
users | 用户主表 | id、username、password(bcrypt)、email、status、role |
user_profiles | 用户扩展资料 | user_id、nickname、avatar |
roles | 角色表 | code(如 admin/user)、name |
authorities | 权限点 | resource(资源方法)、uri(资源路径) |
role_authority | 角色-权限关联 | role_id、authority_id(联合主键) |
user_authority | 用户-权限直接关联 | user_id、authority_id |
文件管理
| 表 | 说明 | 关键列 |
|---|---|---|
files | 通用文件表 | bucket、object_key、ref_type(视频原片/封面/manifest/评论附件)、size、mime_type、ref_count(引用计数)、status |
files 是统一的对象引用表:原片、封面、DASH manifest、评论附件全部登记于此,支持引用计数(秒传去重依据)。
视频域
| 表 | 说明 | 关键列 |
|---|---|---|
videos | 视频主表 | title、description、cover_file_id、duration、status(uploading/processing/published/failed)、visibility、like_count / favorite_count / play_count(冗余计数) |
video_sources | 原始视频上传记录 | video_id、file_id、uploaded_at |
video_transcodes | 转码任务与状态 | video_id、status(pending/processing/completed/failed)、resolution、codec、manifest_file_id;索引 (status, updated_at, video_id) 供 watchdog 扫描 |
video_manifest | 播放清单 | video_id、protocol(dash)、file_id、profiles(档位 JSON) |
tags / video_tags | 标签及视频-标签多对多 | - |
为什么 videos 冗余计数列? 列表页高频展示三计数,直接读 videos 列避免 join 明细表;明细表(video_likes 等)只做持久化审计与去重。
社交互动域
| 表 | 说明 | 关键列 |
|---|---|---|
video_comments | 评论 | video_id、user_id、parent_id(父子结构)、content、status |
video_likes | 点赞明细 | video_id、user_id(复合主键) |
video_favorites | 收藏明细 | video_id、user_id(复合主键) |
video_play_logs | 播放日志 | video_id、user_id、ip、user_agent、played_at |
comment_likes | 评论点赞 | comment_id、user_id |
明细表与 Redis 的关系:
| 计数 | Redis 实时 | DB 持久化 |
|---|---|---|
| 点赞 | interaction:like:{videoID}(Set 去重) | video_likes + videos.like_count |
| 收藏 | interaction:fav:{videoID}(Set 去重) | video_favorites + videos.favorite_count |
| 播放 | interaction:play:{videoID}(INCR) | video_play_logs + videos.play_count |
弹幕域
| 表 | 说明 | 关键列 |
|---|---|---|
danmaku | 弹幕 | video_id、user_id、content、time_offset(时间轴位置)、color、mode |
sensitive_words | 敏感词库 | word(AC 自动机加载) |
审计
| 表 | 说明 |
|---|---|
audit_logs | 操作审计日志(预留) |
设计要点
- 复合主键做幂等:
video_likes/video_favorites用(video_id, user_id)复合主键,Flusher 幂等落库天然去重; - 状态机驱动:
videos.status与video_transcodes.status构成转码流水线的状态机,配合 Redis 租约实现分布式幂等; - 冗余计数列:展示读
videos冗余列,明细表只增不改,避免热点行更新; - 索引支撑 Watchdog:
(status, updated_at, video_id)索引让超时扫描走索引; - 单库共享:当前所有服务共享 PostgreSQL,按「服务只读写自己归属的表集合」划分,跨服务用 ID 引用 + 事件/API(详见架构演进文档)。
迁移管理
bash
# 手动执行迁移
go run ./cmd/vistack migrate多副本部署时,建议将迁移作为独立一次性任务执行(K8s Job / compose run once),避免多实例同时 AutoMigrate 竞争。
