当两台古董电脑开始分工协作,我终于理解了面试题里那些鬼东西

从我现有的两台电脑的配置说起,一台是轻薄本小新air14 R5 5500U核显+外接rx580,一台上古老机APU AMD A10-5800K,最近在做一个项目是需要对视频进行AI字幕识别+AI字幕文本摘要总结,流程是从ffmepg转码三种码率的源视频,再转码音频wav,再用跑Whisper音频转字幕文本,如果我自己部署的话,可能还要把字幕文本做完处理以后再扔出去跑AI总结,这套流程下来,如果不分开部署,全部让CPU一个人干,那CPU肯定要冒烟了,还是串行流程,如果分开部署,就是微服务和任务调度了,优化成流水线模式,并行实现,优化任务的硬件使用(编解码用核显的编码器足以,服务器和简单的逻辑脚本用CPU,跑转字幕模型和大语言模型用GPU )自动检测任务+并行处理+状态追踪,任务队列,数据库轮询压力大以后转Redis+RabbitMQ 管理员后台可以看到实时状态进度。我的全是Java+vue技术栈 我手头上的垃圾设备也能搭建。

一、我的垃圾装备(先晒为敬)

轻薄本·小新Air 14

  • R5 5500U + 16G内存

  • 外接无头RX 580 8G(海鲜市场200块收的)

上古神机·AMD A10-5800K

  • 推土机架构(懂的都懂,两个核心用一个计算单元)

  • 12G DDR3(AMD专用条) + 飞牛OS(套皮Debian)

就这配置,说出来都是泪。但就是这套破烂,让我悟出了微服务。


二、业务场景:一个能把CPU干冒烟的流程

我要做的是:视频转码 + AI字幕 + AI总结

串行处理的噩梦(CPU冒烟)

text

[源视频]
    ↓
[转码三种码率] ── 2小时(CPU软编码)
    ↓
[提取音频WAV] ── 10分钟
    ↓
[Whisper转字幕] ── 30分钟(CPU推理,慢到怀疑人生)
    ↓
[AI总结] ── 10分钟(Ollama跑DeepSeek)
    ↓
[完成] 总计约3小时,CPU全程100%冒烟

痛点

  •  CPU累死

  • 时间太长

  • 只能一件一件做(串行)


三、觉醒时刻:硬件也能分工?

盯着风扇狂转的电脑,我突然意识到:我手头的硬件可以分工啊!

硬件分工表(谁擅长干啥)

硬件 擅长的事 原来在干啥 应该干啥
小新CPU 调度、逻辑 转码 只做调度和文本处理
小新核显 编解码 闲着 硬件加速转码
RX 580 GPU计算 闲着 跑Whisper + AI总结
A10老机 存文件 跑飞牛OS 当任务队列和存储

这不就是微服务吗?把功能服务拆分出来单独部署、每个硬件只干自己最擅长的事!

硬件加速转码(用核显)

bash

# 以前:CPU软编码(慢)
ffmpeg -i input.mp4 output.mp4  # CPU 95%,2小时

# 现在:核显硬编码(快)
ffmpeg -hwaccel vaapi -i input.mp4 -c:v h264_vaapi output.mp4  
# CPU 20%,15分钟

GPU跑Whisper(用RX 580)

python

# 以前:CPU跑(30分钟)
model = whisper.load_model("medium")

# 现在:GPU跑(5分钟)  
model = whisper.load_model("medium", device="cuda")

当然A卡跑不了cuda。A卡适合在linux环境下,优化更友好


四、新问题:多个视频一起上怎么办?

硬件分工解决了单任务的效率,但新问题来了:

text

同时来10个视频怎么办?
怎么知道每个视频处理到哪一步?
Whisper崩了能不能自动重试?

这时候我想到了消息队列任务调度

我的架构演进:从串行到并行

阶段1:串行(原来)

text

[任务1] → [转码] → [音频] → [字幕] → [总结] → 完成
[任务2] → [转码] → [音频] → [字幕] → [总结] → 完成
[任务3] → [转码] → [音频] → [字幕] → [总结] → 完成

时间 = 任务数 × 单任务时间,CPU累死

阶段2:并行(后来)

text

                  ┌─ [转码工人A] ─┐
[任务队列] → [调度器] ── [转码工人B] ── [音频工人] ── [字幕工人(RX580)] ── [总结工人(RX580)]
                  └─ [转码工人C] ─┘
                      ↑            ↑
                   用核显硬编码   用GPU加速

效果

  • 多个任务同时处理

  • 各环节流水作业

  • 硬件各司其职


五、核心组件图解(面试题里的鬼东西原来长这样)

1. 消息队列:就是个放任务的篮子

text

[生产者] → [放任务] → [消息队列] → [取任务] → [消费者]
  (上传视频)    ↓        (Redis)       ↓      (转码工人)
               [任务1]               [任务1]
               [任务2]               [任务2]
               [任务3]               [任务3]

作用

  • 解耦:生产者和消费者互不知道对方

  • 削峰:突然来100个任务,先存队列慢慢处理

  • 容错:工人挂了,任务还在队列里

2. 数据库:系统的记事本

text

tasks表
┌──────────┬──────────┬──────────┬──────────┐
│ 任务ID    │ 文件名    │ 当前步骤  │ 进度(%)  │
├──────────┼──────────┼──────────┼──────────┤
│ 001      │ a.mp4    │ transcode│ 45%      │
│ 002      │ b.mp4    │ whisper  │ 80%      │
│ 003      │ c.mp4    │ done     │ 100%     │
└──────────┴──────────┴──────────┴──────────┘

nodes表
┌──────────┬──────────┬──────────┬──────────┐
│ 节点名    │ 能力      │ 状态      │ 当前任务  │
├──────────┼──────────┼──────────┼──────────┤
│ 小新      │ transcode│ busy     │ 001      │
│ RX580机器 │ whisper  │ idle     │ null     │
│ A10老机   │ storage   │ idle     │ null     │
└──────────┴──────────┴──────────┴──────────┘

3. 调度器:包工头

text

伪代码:

while True:
    # 1. 看谁闲着
    idle_nodes = db.query("SELECT * FROM nodes WHERE status='idle'")
    
    # 2. 看有啥活
    pending_tasks = db.query("SELECT * FROM tasks WHERE status='pending'")
    
    # 3. 派活
    for task in pending_tasks:
        node = find_idle_node(task)  # 找能干这活的
        if node:
            send_to_node(node, task)  # 派活
            db.update(task, 'processing', node)
            db.update(node, 'busy')
    
    sleep(5)  # 歇会儿再干

4. 整体架构图(我手画版)

text

                      [用户上传视频]
                            ↓
                    [数据库记录任务]
                            ↓
                    [消息队列(Redis)]
                            ↓
        ┌───────────────┬────┴────┬───────────────┐
        ↓               ↓         ↓               ↓
[转码工人1]      [转码工人2]  [音频工人]    [字幕工人]
(小新核显)       (小新核显)   (小新CPU)    (RX580)
        ↓               ↓         ↓               ↓
    [转码完成]      [转码完成]  [音频完成]    [字幕完成]
        └───────────────┴────┬────┴───────────────┘
                            ↓
                    [消息队列(Redis)]
                            ↓
                    [总结工人(RX580)]
                            ↓
                    [AI总结完成]
                            ↓
                    [数据库更新状态]
                            ↓
                    [前端实时显示]

六、从数据库轮询到消息队列(优化之路)

方案1:数据库轮询(简单但压力大)

text

[调度器] --每隔5秒查一次--> [数据库]
                ↑
             压力大!

问题:每秒查数据库,CPU和DB都扛不住

方案2:Redis消息队列(优化后)

text

[上传] --发消息--> [Redis] --取消息--> [工人]
                    ↓
                [队列1] 任务1
                [队列2] 任务2
                [队列3] 任务3

好处

  • 不用轮询,有任务就取

  • 多个队列隔离不同类型任务

  • 内存操作,速度快

失败重试机制

text

[工人取任务] → [执行失败] → [放回队列] → [重试]
                ↓
            [重试3次还失败]
                ↓
          [进死信队列] → [人工介入]

七、硬件部署图(我的破烂怎么分工)

text

┌─────────────────────────────────────────────────────┐
│                   小新Air 14                         │
├─────────────────────────────────────────────────────┤
│  CPU (R5 5500U)                                      │
│  ├── 调度器 (Java进程)                               │
│  ├── 音频提取工人 (轻量级)                           │
│  └── 文本处理工人                                    │
├─────────────────────────────────────────────────────┤
│  核显 (负责转码)                                      │
│  ├── 转码工人1                                        │
│  └── 转码工人2                                        │
├─────────────────────────────────────────────────────┤
│  RX 580 8G (外接显卡)                                │
│  ├── Whisper工人 (字幕)                               │
│  └── DeepSeek工人 (AI总结)                            │
└─────────────────────────────────────────────────────┘
                            ↑
                       网络连接
                            ↓
┌─────────────────────────────────────────────────────┐
│               A10-5800K 老机 (飞牛OS)                 │
├─────────────────────────────────────────────────────┤
│  - 文件存储 (存视频)                                  │
│  - Redis消息队列 (轻量级)                             │
│  - MySQL数据库 (任务状态)                             │
│  - 备份工人 (做些杂活)                                │
└─────────────────────────────────────────────────────┘

八、前端监控(看看进度条)

text

┌─────────────────────────────────────────────┐
│          视频处理监控面板                      │
├─────────────────────────────────────────────┤
│ 节点状态:                                     │
│  🟢 小新调度器 (空闲)                          │
│  🟡 转码工人 (处理中: 视频001)                  │
│  🟢 Whisper工人 (空闲)                         │
│  🔴 A10老机 (离线)                             │
├─────────────────────────────────────────────┤
│ 任务列表:                                     │
│  ┌────┬────────┬────────┬────────┬──────┐   │
│  │ ID │ 文件名  │ 当前步骤 │ 进度   │ 状态  │   │
│  ├────┼────────┼────────┼────────┼──────┤   │
│  │ 001│a.mp4   │转码    │████░░ 45%│处理中 │   │
│  │ 002│b.mp4   │字幕    │██████ 80%│处理中 │   │
│  │ 003│c.mp4   │完成    │██████100%│成功  │   │
│  └────┴────────┴────────┴────────┴──────┘   │
├─────────────────────────────────────────────┤
│ 实时监控图:                                   │
│  任务数                                       │
│   ↑                                          │
│ 10┤    █                                      │
│  8┤    █                                      │
│  6┤    █   █                                  │
│  4┤    █   █                                  │
│  2┤    █   █   █                              │
│   └───────────────→ 时间                      │
│     转码 音频 字幕 总结                         │
└─────────────────────────────────────────────┘

九、我悟了:面试题原来长这样

面试题1:什么是微服务?

我的理解:微服务的本质是服务拆分——把一个臃肿的单体应用,按业务边界拆成多个独立的小服务,每个服务只干一件事。

拆分之后的好处:

  • 转码服务挂了,不影响字幕服务(故障隔离)

  •  字幕服务压力大,可以单独多部署几个实例(弹性伸缩)

  •  总结服务可以用Python写,转码服务用Java写,互不干扰(技术栈自由)

  • 改一行字幕代码,只重新部署字幕服务,不用动其他(敏捷开发)

面试题2:消息队列解决了什么问题?

我的理解:消息队列解决的是服务之间的解耦问题,让它们可以异步通信,不用互相等待。

没有消息队列(同步调用)

有消息队列(异步解耦)

面试题3:分布式事务怎么处理?

我的理解:就是任务失败了怎么办。我的做法是:记录状态 + 失败重试(3次)+ 死信队列(实在不行就记下来人工处理)。

面试题4:服务发现是什么?

我的理解:就是调度器要知道谁还活着、谁能干什么。我数据库里那张nodes表就是干这个的。

面试题5:削峰填谷怎么理解?

我的理解:突然来100个任务,如果直接丢给转码服务,瞬间打死。但丢进消息队列,让工人按自己的节奏慢慢处理,系统稳如老狗。


十、写在最后(给垃圾佬们的建议)

这套系统现在跑在我的两台破烂电脑上,每天处理着几十个视频。虽然配置寒酸,但靠着微服务的架构思想,跑得还挺稳。

给还在背八股的兄弟们

那些面试题里问的“微服务优缺点”“消息队列应用场景”,不用死记硬背。找个小需求,用手头的破烂电脑自己折腾一遍,你就全明白了。

真正的理解,从来不是背出来的,是动手做出来的。哪怕是垃圾佬,也能在破烂硬件上悟出架构的真谛。


如果你也是垃圾佬,也有一堆破烂电脑,欢迎留言交流!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐