视频平台架构重构:从微服务到可插拔基础设施

一、现状与问题

典型的视频平台后端通常采用微服务架构,但普遍存在一个问题:业务代码与基础设施深度耦合。

组件 常见实现 问题
消息队列 RocketMQ / RabbitMQ(直接注入客户端) 换 MQ 必须改业务代码
服务调用 OpenFeign / Dubbo 语言锁定,只能 Java 调 Java
服务发现 Nacos / Eureka 弱设备无法运行
缓存 Redis(直接注入客户端) 换缓存要改业务代码

业务代码和基础设施强耦合,导致无法在弱设备部署、无法跨语言、无法切换实现。

1.1 代码质量问题

  • Service 类臃肿(部分超过 800 行),Controller 包含事务逻辑

  • DTO 与 Entity 混用

  • 异常处理不统一

  • 硬编码较多(Redis key、超时时间)

  • 测试覆盖不足

1.2 已有亮点:存储层已抽象

部分项目中存储层已经做了抽象:

text

复制代码
StorageService(接口)
 ├── MinioStorageService(MinIO 实现)
 ├── LocalStorageService(本地实现)

这说明抽象层思路已被验证可行,可以推广到其他基础设施组件。

二、重构思路:可插拔基础设施

2.1 设计目标

  1. 业务代码只依赖接口:不依赖具体实现

  2. 配置驱动:改配置就能切换实现

  3. 多实现:每个接口有轻量/企业级/测试多种实现

  4. 渐进迁移:一个模块一个模块切,可回滚

2.2 核心接口定义

ServiceDiscovery(服务发现)

go

复制代码
type ServiceDiscovery interface {
    Register(ctx context.Context, instance ServiceInstance) error
    Deregister(ctx context.Context) error
    Discover(ctx context.Context, serviceName string) ([]ServiceInstance, error)
    Watch(ctx context.Context, serviceName string) (<-chan []ServiceInstance, error)
}

实现:FileDiscovery(嵌入式单机)、EtcdDiscovery(K8s 标准)、NacosDiscovery(兼容现有)、MemoryDiscovery(单元测试)

MessageQueue(消息队列)

go

复制代码
type MessageQueue interface {
    Publish(ctx context.Context, topic string, msg Message) error
    Subscribe(ctx context.Context, topic string, group string) (<-chan Message, error)
    Ack(ctx context.Context, topic string, msg Message) error
}

实现:MemoryQueue(测试)、RedisStreamQueue(轻量)、RocketMQQueue(企业级)、NATSQueue(高性能)

CacheStore(缓存)

go

复制代码
type CacheStore interface {
    Get(ctx context.Context, key string) ([]byte, error)
    Set(ctx context.Context, key string, value []byte, ttl time.Duration) error
    Lock(ctx context.Context, key string, ttl time.Duration) (bool, error)
    Incr(ctx context.Context, key string, ttl time.Duration) (int64, error)
}

实现:MemoryCache(测试)、SQLiteCache(嵌入式持久化)、RedisCache(分布式)、BoltDBCache(嵌入式 KV)

ServiceCaller(服务间调用)

go

复制代码
type ServiceCaller interface {
    Call(ctx context.Context, target string, method string, req []byte) ([]byte, error)
    CallStream(ctx context.Context, target string, method string, req []byte) (<-chan []byte, error)
}

实现:MemoryCaller(测试)、HTTPClient(简单服务)、GRPCClient(跨语言标准)

2.3 配置驱动

yaml

复制代码
infrastructure:
  servicediscovery:
    type: etcd          # etcd / nacos / file / memory
    endpoints: ["http://localhost:2379"]
  messagequeue:
    type: redis-stream  # redis-stream / rocketmq / nats / memory
    redisAddr: localhost:6379
  cachestore:
    type: redis         # redis / sqlite / boltdb / memory
    addr: localhost:6379
  servicecaller:
    type: grpc          # grpc / http / memory
    timeout: 3s

切换环境只需改配置:

场景 配置组合
嵌入式设备 sqlite + memory + redis-stream
老旧服务器 sqlite + redis + file
云上生产环境 mysql + redis + etcd + rocketmq
单元测试 memory + memory + memory

三、无状态与高并发

3.1 无状态原则

服务不保存任何与请求绑定的状态,全部外置:

状态类型 存储位置
用户会话 Redis(JWT + 会话)
WebSocket 连接 Redis Pub/Sub(跨实例广播)
任务进度 Redis Stream
计数器 Redis
缓存 Redis
数据库 MySQL

3.2 WebSocket 跨实例广播

text

复制代码
客户端A ──WS──▶ realtime-1 ──┐
                              ├── Redis Pub/Sub ──▶ realtime-2 ──WS──▶ 客户端B
                              └──(弹幕/通知广播)

每个 realtime 实例订阅 Redis 主题,发消息只往 Redis Publish,所有实例收到后推给本地连接。实例增减不影响广播。

3.3 Redis Stream 作为消息队列

使用 Redis Stream 替代传统消息中间件,适合弱设备场景:

指标 Redis Stream RocketMQ
内存 复用 Redis 独立几百 MB
部署 已在跑 Redis 额外服务器
弱设备 可跑 不现实

核心用法:

  • XADD:入队

  • XREADGROUP:消费

  • XACK:确认

  • XCLAIM:认领超时任务

  • XTRIM:清理已 ACK 消息

四、API 规范

4.1 统一响应结构

json

复制代码
{
  "code": 0,
  "message": "ok",
  "data": {},
  "requestId": "req-xxxx"
}

4.2 错误码体系

全局错误码(0-999):

code 说明
0 成功
400 参数错误
401 未认证
403 无权限
404 资源不存在
429 限流
500 服务器错误

业务错误码(1000+):

模块 范围
用户 1000-1099
内容 1100-1199
互动 1200-1299
订单 1300-1399

4.3 分页与认证

  • 分页page(默认 1)、pageSize(默认 20,上限 100)

  • 认证Authorization: Bearer <jwt_token>

  • 幂等Idempotency-Key: <client_uuid>(写操作)

五、重构优先级

优先级 工作量 风险
P0 抽象 MessageQueue
P0 抽象 ServiceCaller
P0 抽象 ServiceDiscovery
P1 统一错误码/异常处理
P1 DTO/Entity 分层
P2 长类拆分
P2 硬编码配置化

策略: 先抽接口(改动集中在注入点),确认编译通过且功能不变后再逐个替换实现。每个服务独立迁移,先支持配置切换(保持原实现),再逐步替换。

六、总结

  1. 抽象层思路已被存储层验证可行,推广到 MessageQueue/ServiceDiscovery/CacheStore

  2. 配置驱动让同一套代码适应不同环境(嵌入式→企业级)

  3. 无状态设计让集群可水平扩展

  4. Redis 一鱼多吃:缓存 + MQ(Stream)+ 锁 + 计数器

  5. 渐进迁移保证可回滚,风险可控

相关推荐
小蒜学长10 分钟前
大学生健康饮食的智慧管理系统(代码+数据库+LW)
java·后端·springboot·大学生·健康饮食
小蒜学长19 分钟前
基于Java的论坛数据可视化分析系统的设计与实现(代码+数据库+LW)
java·spring boot·后端·数据可视化·论坛系统
许彰午34 分钟前
52-useWebSocket自动重连
java·低代码·架构
青山木36 分钟前
RocketMQ 入门到原理(一):整体架构与消息的生命周期
java·分布式·后端·中间件·架构·rocketmq
黑马程序员毕设42 分钟前
基于微信小程序的二手交易平台设计与实现报告
前端·人工智能·spring boot·后端·考研
cAuth43 分钟前
实现一个图形编辑器
前端·架构·计算机图形学
haishikeji696_1 小时前
飞控管理平台源码|无人机智慧巡查系统私有化部署 低空一网统管巡检平台选型指南
架构·无人机·低空经济·无人机巡检·无人机管理系统·一网统飞·飞控管理平台
安易算力1 小时前
昇腾生态开发深度实践:CANN算子库架构解析与MindSpore模型优化
网络·容器·架构·kubernetes·vllm
Huanzhi_Lin1 小时前
从0搭建ECS:跨品类评估
架构·游戏开发·ecs·ecs跨品类评估
揽秀亭长1 小时前
音轨分离处理方案及效果测试分析
人工智能·音视频