SQS 与 SNS 消息服务

Amazon SQS / SNS

给系统之间传话的中间人:忙的时候先排队,闲下来慢慢处理,谁都不用干等谁。

存储与数据出现时间 · 2006 / 2010按请求次数与消息传输量计费,每月有较大免费额度,超出后按百万次请求计价。消息队列削峰填谷解耦发布订阅
看官方文档

01 它是干嘛的

SQS 与 SNS 解决的是「系统之间怎么可靠地互相通知」这件事。SQS 是一个排队信箱:生产者把消息放进去,消费者按自己的节奏取走处理;SNS 是一个广播喇叭:一条消息可以同时推送给很多个订阅者。它们共同实现了四个目标:解耦、削峰、异步、重试。

02 为什么会有它

两个程序直接对话,为什么一拥堵就会连环雪崩

系统之间的合作,最早都是「直接调用」:订单服务下的单,立刻去通知库存、通知支付、通知发货。看起来干脆,其实非常脆弱——只要其中一个慢了一点,前面的服务就得一直等着;等的人越多,积压越多,最终整条链路一起卡死。这就像你打电话给客服,对方没接你就得一直握着电话,什么也干不了。

大促时这个问题会放大成灾难。下单量瞬间暴涨,但下游处理能力有限,一瞬间涌来的请求把下游压垮,连带把上游也拖死。为了那几小时的峰值,把每一环都扩到能扛峰值,成本高得离谱,而且平时全在浪费。

消息服务的思路是把「直接对话」改成「留个条子」。发送方把要做的事写进队列就可以走了,不关心谁处理、什么时候处理;接收方按自己的速度慢慢取、慢慢做。这样发送方不会因为接收方慢而被拖累,接收方也不会被瞬间的洪流冲垮。这条「先存下来、慢慢处理」的思路,正是现代分布式系统稳定运行的基石之一。

03 它怎么工作

消息服务的核心是一条流水线:生产者只管把消息放进队列,消息会被可靠保存,消费者按自己的节奏取走处理,处理成功后才删除,失败则被重新投递。

消息队列:解耦、削峰、异步、重试① 突发流量先排进去② 空闲才取走处理失败人工介入生产者下单服务队列先把请求堆起来(削峰)消费者 1按自己节奏处理消费者 2忙就加人一起消费死信队列重试多次仍失败的自动重试失败不是立刻丢掉生产者只管把消息丢进去,不用管谁处理、处理多慢。两边从此互不拖累。正常重试需要人看
沿着箭头看「生产者 → 队列 → 消费者」三段:队列像水库一样把上游的洪峰存下来,下游再按自己的能力匀速放水,这就是削峰填谷。右侧的死信队列则专门收留反复失败的消息。

一条消息的旅程:从生产者投递到消费者确认

  1. 1
    ① 生产者把消息放进队列

    业务程序发一条消息就可以立刻返回,不必等待任何人处理,这正是「解耦」与「异步」的开始。

  2. 2
    ② 消息被可靠保存

    消息会在队列中留存一段时间,期间即使消费者宕机或重启,消息也不会丢。

  3. 3
    ③ 消费者按自己的节奏取走

    SQS 是「谁空谁来取」的点对点模式,多个消费者同时工作会自动分摊消息,处理能力可以随时增加。

  4. 4
    ④ 成功后删除,失败则重新投递

    处理完成必须显式删除消息;如果处理到一半程序崩了,消息会在超时后重新出现,被再次处理,保证「至少做一次」。

  5. 5
    ⑤ 多次失败送进死信队列

    反复处理不成功的「坏消息」被单独收进死信队列,避免它一直循环,也方便人工事后排查。

04 谁在用它

大促削峰

下单请求先进入队列,订单系统按自己能承受的速度慢慢处理,躲过一瞬间的流量洪峰。

系统解耦

下单之后要发短信、发邮件、更新积分,全部改成发消息,任何一环出问题都不影响下单主流程。

异步耗时任务

生成报表、压缩图片、处理视频等耗时操作交给队列后台慢慢做,用户不必在页面上干等。

多个系统同时收到通知

用 SNS 广播一条事件,数据分析、监控、通知等多个下游各自订阅、互不影响。

可靠的失败重试

第三方接口临时出错时,消息自动回队列重试,配合死信队列兜底,避免任务凭空丢失。

05 怎么用

概念不难,难点在于「想清楚哪些环节对重复处理是安全的」,否则重试会带来数据错乱。

  1. 01在控制台创建一个队列,先选标准队列(追求吞吐)还是先进先出队列(追求严格顺序)。
  2. 02给队列配一个死信队列,并设置「最多重试几次后转入死信」,避免坏消息无限循环。
  3. 03让业务程序作为生产者把消息发进队列,发送成功后即可继续执行,不等下游。
  4. 04编写消费者程序循环拉取消息、处理业务、成功后删除消息。
  5. 05需要一对多广播时改用 SNS 主题,让多个队列或系统同时订阅同一条消息。
  6. 06上线后监控队列积压量,积压持续增长说明消费者处理太慢,需要增加消费者数量。
发一条消息到队列,并拉取出来处理ts
import { SQSClient, SendMessageCommand, ReceiveMessageCommand } from '@aws-sdk/client-sqs'

const sqs = new SQSClient({ region: 'us-east-1' })
const QueueUrl = 'https://sqs.us-east-1.amazonaws.com/123456789012/orders'

// 生产者:把订单消息放进队列后立即返回,不必等谁处理
await sqs.send(new SendMessageCommand({
  QueueUrl,
  MessageBody: JSON.stringify({ orderId: 'A-1001', action: 'create' })
}))

// 消费者:拉取消息,处理成功后必须显式删除,否则超时后会被重投
const { Messages = [] } = await sqs.send(new ReceiveMessageCommand({
  QueueUrl, MaxNumberOfMessages: 1
}))
console.log(Messages[0]?.Body)

避坑提示

  • !SQS 保证「至少处理一次」,同一消息可能被处理两次,业务逻辑要做到重复执行也不会出错。
  • !SQS 是点对点拉取,一条消息只会被一个消费者拿走;SNS 是发布订阅推送,一条消息会送到所有订阅者,二者常搭配使用。
  • !一定要设置死信队列,否则一条永远处理失败的消息会把队列卡住甚至无限重试,悄悄消耗成本。

06 关键概念

生产者与消费者
前者负责把消息放进队列,后者负责取出来处理,两者互不等待。
削峰填谷
把瞬间的流量高峰先存进队列,让下游按稳定速度处理,避免被冲垮。
死信队列
反复处理失败的消息被单独存放的地方,便于排查且不会卡住正常消息。
可见性超时
消息被取出后暂时对其他人隐藏的一段时间,处理超时未确认就会重新出现。
发布订阅
一条消息同时推送给所有订阅者,像广播一样,而点对点队列则是一条消息只给一个人。

07 容易混淆的对比

Kafka吞吐极高、支持消息回放与多消费者独立进度,适合数据管道与流处理。
RabbitMQ路由规则灵活、功能丰富的经典消息中间件,部署与运维需自己承担。
图软件图鉴

纯静态站点,无后端、无追踪。内容为中文原创撰写,用于帮助非技术读者理解主流软件产品。

关于本站

全部内容在构建时生成
产品名称与商标归各自公司所有

© 2026 软件图鉴Nuxt 4 · Vue 3 · Tailwind 4 · 纯静态