首页 / 知识库 / python服务端进阶 / 消息队列入门

01 - 为什么需要消息队列

先从一个真实的痛点说起

假设你用 FastAPI 做了一个”用户注册”接口。注册成功后,你还想做几件事:

  1. 往数据库写一条用户记录
  2. 发一封欢迎邮件
  3. 发一条短信验证码
  4. 给推荐系统推一条”新用户”事件
  5. 更新一下运营后台的统计数据

最直接的写法,是在这个接口里一件一件同步做完

用户点"注册"


┌─────────────────────────────────────────────┐
│  POST /register  (FastAPI 接口函数里)        │
│                                             │
│  写数据库 (0.05s)                            │
│    → 发邮件 (2s,要连第三方邮件服务器)         │
│      → 发短信 (1.5s,要连短信网关)            │
│        → 推事件给推荐系统 (0.8s)             │
│          → 更新统计 (0.3s)                   │
│                                             │
│  全部做完 → 才返回"注册成功"                  │
└─────────────────────────────────────────────┘


用户等了 4.6 秒,才看到"注册成功"

这里有三个越想越难受的问题:

问题一:用户被迫等待(慢)

用户其实只关心”我注册成功了没有”。可为了等邮件、短信这些跟他没关系的后续动作,他要多等好几秒。接口越挂越多的后续任务,用户等得越久。

问题二:任何一环挂了,整个注册就失败(脆)

如果邮件服务器那一刻抽风连不上,你的 发邮件 这一步抛异常,会怎么样?

整个注册接口报错,用户明明该注册成功,却看到”注册失败”。

一个”发欢迎邮件”这种无关紧要的动作,居然能拖垮核心的”注册”功能。这就是强耦合带来的脆弱。

问题三:流量一大就崩(扛不住高峰)

搞个促销活动,一瞬间涌进来 1 万人注册。每个请求都要同步发邮件、发短信……第三方短信网关每秒只能处理 200 条,你这边瞬间 1 万条压过去——短信网关被打爆,你的服务也跟着卡死

换个思路:把”要做的事”先记下来,慢慢做

现实生活里我们早就这么干了。想想餐厅点餐

  • 你(顾客)把菜单交给服务员,服务员记一张小票贴到后厨的挂单栏,然后马上回来招呼下一桌。
  • 你不用站在后厨盯着厨师炒菜,服务员也不用等菜做好才敢接待下一位。
  • 厨师(们)按自己的节奏,从挂单栏一张张取小票来做
  • 高峰期挂单多,就多排一会队;但没有任何一桌会因为”厨房忙”被赶走。

这个”挂单栏”,就是消息队列。

 顾客(生产者)        挂单栏(消息队列)         厨师(消费者)
┌──────────┐       ┌───────────────┐       ┌──────────┐
│ 下单:    │──────▶│ 单1 单2 单3 …  │──────▶│ 取单、做菜 │
│ "宫保鸡丁" │  贴单  │ (先进先出排队)  │  取单  │           │
└──────────┘       └───────────────┘       └──────────┘
   下完单就走            消息在这里排队           按自己节奏消费
   不用等菜做好

用消息队列重构注册接口

回到刚才的注册例子。引入消息队列后,接口只做必须马上做完的核心动作,其余”通知类”任务,扔进队列就返回:

用户点"注册"


┌───────────────────────────────┐
│  POST /register               │
│                               │
│  ① 写数据库 (0.05s)  ← 核心,必须做│
│  ② 往队列丢一条"用户已注册"消息    │
│     (0.001s,丢完就不管了)       │
│                               │
│  立刻返回"注册成功"             │
└───────────────────────────────┘
   │                        消息队列里躺着一条 "user_registered"
   ▼                                    │
用户 0.05 秒就看到"成功"        ┌────────┴────────┐
                              ▼        ▼        ▼
                          发邮件    发短信    推推荐/统计
                        (后台的消费者慢慢处理,各干各的)

对照一开始的三个问题,现在全解决了:

原来的问题引入消息队列后
用户等 4.6 秒(慢)只等核心的 0.05 秒(异步
邮件挂了就注册失败(脆)邮件消费者自己重试,不影响注册(解耦
高峰把短信网关打爆(扛不住)消息在队列里排队,消费者按自己节奏慢慢消化(削峰

这三个关键词——异步、解耦、削峰——就是消息队列存在的全部意义,我们会在 第 03 章 展开讲。

一句话理解消息队列

消息队列(Message Queue)= 一个”中间人”,专门负责暂存和转发消息,让”发消息的人”和”处理消息的人”彼此不用直接打交道、也不用同时在线。

发消息的一方叫生产者,处理消息的一方叫消费者,中间那个存消息的服务叫 Broker(消息中间件)。这套模型,下一章我们仔细拆开看。

小结

  • 痛点:把一堆后续任务同步串在一起做,会导致慢、脆、扛不住高峰。
  • 消息队列的思路:像餐厅”挂单栏”一样,先把任务记下来排队,再由消费者按自己节奏处理
  • 它带来三大好处:异步(快)、解耦(稳)、削峰(扛得住)

下一章 → 02 - 核心概念与工作模型