news 2026/8/27 10:41:50

微服务异步通信实战:SNS+SQS扇出模式解析与代码示例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
微服务异步通信实战:SNS+SQS扇出模式解析与代码示例

微服务架构做到一定复杂度后,服务之间最难处理的不是怎么写代码,而是怎么通信。同步 HTTP 调用简单直观,但链路一长就会出现一个典型场景:A 调用 B,B 调用 C,C 又去调 D,结果 D 慢了几百毫秒,A 的线程池很快被占满,接口超时,客户端重试,流量翻倍,雪崩就是这么来的。于是大家开始找异步方案。在 AWS 生态里,最常用也最容易上手的答案就是 SNS + SQS。

这篇文章是“AWS SNS SQS 微服务架构”系列的第一篇。我会先把 SNS 和 SQS 的核心概念、适用边界、两者组合出来的扇出模式讲明白,再带你用 AWS CLI、Python boto3、Java SDK 完整跑通一条“订单事件同时分发到多个服务”的消息链路,最后给出生产环境最容易踩的坑和工程建议。

读完这篇文章,你应该能回答三个问题:第一,某个消息场景到底该用 SNS、SQS 还是两个都用;第二,怎么让一条 SNS 消息自动投递到多个 SQS 队列;第三,消息到了消费者手里为什么还会重复,线上该怎么防御。

1. 为什么微服务架构里要用 SNS + SQS

微服务之间的通信方式,从大方向上分只有两类:同步和异步。绝大多数团队最开始使用的都是同步 HTTP:服务 A 发起调用,阻塞等待服务 B 返回结果。

这种模式不是不好,而是对链路延时长、调用关系复杂的场景不友好。典型的问题有三个。

第一个是调用链放大。A 调用 B,B 调用 C,如果 C 挂了或变慢,A 的请求线程会被一直占用。流量高峰时,线程池被打满,后续请求全部排队。更糟的是客户端超时后通常会自动重试,重试流量再涌进来,系统很容易从一个小故障演变成大面积不可用。

第二个是下游强耦合。订单服务在代码里写了“通知服务”的地址,那它就是强依赖通知服务。通知服务重启、升级、甚至只是网络抖动,都可能让订单服务接口 5xx。业务上“通知失败”并不应该导致“下单失败”,但同步调用的代码会让这两件事强相关。

第三个是处理能力错配。下单是突发的,扣库存可能只要 5 毫秒,但发短信要调第三方接口,平均要 300 毫秒。用同步阻塞的方式,一个下单线程会被慢操作拖住,整个系统的吞吐就被最慢的那个环节锁死了。

当然,不是所有调用都应该异步化。实时查询类的操作,比如查订单详情、登录校验,天然需要同步拿到结果;而事件通知、状态变更传播、任务执行这类操作,并不要求调用方立刻拿到结果,这些才是异步消息的应用场景。在 AWS 上做异步,最常遇到的两个服务就是 SNS 和 SQS。

2. SNS 与 SQS 核心概念与定位

2.1 SQS:分布式消息队列

SQS(Simple Queue Service)是全托管的分布式消息队列。你不需要自己部署任何 MQ 服务,只需要创建队列,然后生产方发消息、消费方拉消息。

用生活场景来理解,SQS 就是一个快递柜。寄件人不用当面把东西交给收件人,而是放进快递柜;收件人什么时候有空,就什么时候去取。快递柜本身并不关心寄件人和收件人是否同时在线。这种解耦,就是队列最核心的价值。

SQS 有两种队列类型,选错会影响后续架构设计:

标准队列:默认类型,吞吐高,支持近似无限并发;但只保证至少一次投递,也就是说消费方有可能重复收到同一条消息。消息顺序也不保证。

FIFO 队列:提供先入先出的严格顺序语义,支持正好一次投递,但吞吐量受限,默认配额有限;FIFO 队列的命名必须以.fifo结尾。

在微服务架构里,绝大多数业务队列场景用标准队列就够;只有对消息顺序有硬要求的场景,比如交易流水回放、订单状态机流转,才必须用 FIFO。

2.2 SNS:发布订阅广播总线

SNS(Simple Notification Service)是发布/订阅模式的消息服务。它的核心组件是 Topic(主题)。生产者把消息发布到 Topic,Topic 再把消息推送给所有订阅者。

还是用生活场景理解,SNS 像广播电台的频道。电台只管发信号,谁拿着收音机调到这个频道,谁就能收到。发信号的广播台不需要知道有多少台收音机,也不管收音机是否开机。

SNS 支持的订阅端非常多:HTTP/HTTPS 端点、Email、短信、移动推送、SQS 队列、Lambda 函数等。在微服务架构中,最常用的两个订阅端是 SQS 队列和 Lambda 函数。SNS 本身不负责存储消息,也不保证消费者一定处理成功,它更像一个“事件交换机”,发布一次,转发多路。

2.3 SNS 与 SQS 的核心区别

很多新手分不清这两个服务,我用一张表把它们放在一起对比。

维度同步 HTTPSQSSNS
通信模式一对一同步一对一异步一对多异步广播
调用结果调用方阻塞等待消费者自主拉取订阅者各自接收
削峰能力需要配合队列实现
故障隔离取决于订阅端
消息存储默认保留 4 天不存储,立即推送
时序保证自然有序标准无序,FIFO 有序无序
适用场景实时查询、强一致任务队列、削峰填谷事件通知、扇出分发

一个简单的记忆方式是:SQS 是“点对点”的消息管道,一条消息只会被一个消费者取走;SNS 是“广播”的喇叭,一条消息会复制给所有订阅者。

2.4 为什么是 SNS + SQS 组合

如果只用一个队列,解决的是“一个生产者给一个消费者解耦”的问题。但很多需求是“一个事件要同时影响多个服务”。

以订单创建为例:订单服务只需要发布一条“订单创建成功”的事件,但库存服务、通知服务、积分服务都需要这个事件,而且它们各自的处理速度不同。如果直接把事件写到某个下游队列里,其他下游就收不到;如果让订单服务挨个往三四个队列各发一遍,订单服务的代码就重复且耦合。

SNS + SQS 的组合正是解决这类“一对多”扇出需求的标准做法:SNS 主题把事件广播到多个 SQS 队列,每个队列对应一个消费者服务。生产者只需要跟 SNS 交互,消费者只需要跟自己的 SQS 队列交互,中间完全是解耦的。这个模式在 AWS 官方许多参考架构里都有出现,是微服务事件驱动设计的基础。

订单服务 → SNS(order-events) ├── SQS 队列 A → 库存服务 ├── SQS 队列 B → 通知服务 └── SQS 队列 C → 积分服务

3. 环境准备与前置条件

要跑通本文示例,需要准备以下环境。

3.1 AWS 账号与 IAM 权限

你需要一个能访问 SNS 和 SQS 的 AWS 账号。不要在生产账号直接用管理员权限做实验,更稳妥的做法是创建一个最小权限 IAM 用户,或者使用 AWS CloudShell 内置的临时凭证。

本文示例需要的权限至少包括:

  • sqs:CreateQueue
  • sqs:SendMessage
  • sqs:ReceiveMessage
  • sqs:DeleteMessage
  • sqs:GetQueueAttributes
  • sqs:SetQueueAttributes
  • sns:CreateTopic
  • sns:Subscribe
  • sns:Publish
  • sns:GetTopicAttributes

如果只是本地试验,推荐使用 AWS CloudShell,它直接内置了 AWS CLI 和临时凭证,不用在本地配置密钥,安全性也更高。如果你在本地操作,则按下方方式配置。

3.2 安装并配置 AWS CLI

安装 AWS CLI 之后,执行:

aws configure

按提示输入 Access Key、Secret Key、默认区域和输出格式。验证是否配置成功:

aws sts get-caller-identity

看到 Account 和 Arn 输出,就说明配置完成。注意本文示例按us-east-1区域编写,如果你使用其他区域,请把命令和 ARN 中的区域替换成实际值。

3.3 Java 与 Python 运行环境

本文代码示例提供 Python(boto3)和 Java(AWS SDK for Java 2.x)两个版本。

Python 版只需要安装依赖:

pip install boto3

Java 版需要 JDK 8 以上和 Maven,并在 pom.xml 中引入software.amazon.awssdk:sqssoftware.amazon.awssdk:sns两个依赖。版本号不要照抄网上写死的数字,以 Maven 中央仓库当前稳定版本为准。如果使用 Spring Boot,可以通过依赖管理统一维护版本。

3.4 本地模拟选型:LocalStack

如果你不想在开发阶段连真实 AWS,可以用 LocalStack 在本地模拟 SNS/SQS。用 Docker 启动:

docker run --name localstack -d -p 4566:4566 localstack/localstack

Python 代码里指定 endpoint 即可连接本地模拟环境:

import boto3 sqs = boto3.client( 'sqs', endpoint_url='http://localhost:4566', region_name='us-east-1', aws_access_key_id='test', aws_secret_access_key='test' )

LocalStack 适合单元测试和本地联调,但它不是真正的 AWS 服务,某些高级特性可能缺失。涉及生产问题排查时,仍然要以真实环境为准。

4. 整体架构设计:订单事件扇出

下面进入实践。我们先定义一个足够典型的业务场景。

4.1 场景描述

假设有一个电商系统,用户提交订单后,订单服务需要触发三件事:

  • 库存服务扣减库存;
  • 通知服务发送短信和 App 推送;
  • 积分服务给用户增加积分。

这三件事都不需要用户在请求里等待,消费速度也各不相同。其中发短信还要调第三方接口,最容易慢和失败。这就是典型的异步扇出场景。

4.2 事件流转

完整链路如下:

  1. 订单服务发布一条消息到 SNS 主题order-events,消息内容是一段订单 JSON。
  2. SNS 将这条消息自动复制并推送到所有订阅了该主题的 SQS 队列。
  3. 库存、通知、积分三个服务各自从自己的队列中拉取消息,消费速度互不影响。
  4. 如果某个服务消费失败,消息不会丢失,而是在队列里保留,等待重试或进入死信队列。

这里的关键点是:订单服务只感知 SNS,不感知任何下游服务的地址和状态。新增一个下游服务时,订单服务一行代码都不用改。

4.3 为什么不用 Kafka

一部分读者会想:这个场景 Kafka 也能做。确实能,但两者侧重不同。

Kafka 是一个

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/27 10:41:40

DeepSeek Harness 安装难?DSH-Work 桌面客户端零配置上手指南

最近在技术社区和各大搜索平台里,“DeepSeek Harness 怎么安装”“DeepSeek Harness 怎么使用”“DeepSeek Harness 桌面端”这些搜索词出现的频率越来越高。如果你去翻一遍相关讨论,会发现很多人的问题并不在模型本身,而是卡在环境上&#x…

作者头像 李华
网站建设 2026/8/27 10:39:45

怎么查供应商有没有经营异常

1. 政策 / 热点背景随着国资穿透式监管、供应链安全相关法规落地,供应商经营异常核查,已经成为采购入库、招投标、审计、存续期风控的硬性工作环节。供应商一旦出现经营异常、资质失效、行政处罚、治理失稳等问题,若不能及时识别,…

作者头像 李华
网站建设 2026/8/27 10:39:16

我用 Codex 写了套漫画下载站 CMS,静态化和 SEO 是它的主场

最近想做一个漫画 APP 下载站。不想要重框架,选了轻量 PHP 的路线,整站交给 Codex 辅助开发。 体验地址 woxiangxin.cn,下载地址在文末。前后台功能基本齐全,静态页、SEO、下载转化、评论审核、在线升级都有,后面还会持…

作者头像 李华
网站建设 2026/8/27 10:38:18

ISBN校验码原理与工程实现解析

1. 这道题不是考编程,是考你有没有真正读懂ISBN的校验逻辑 NOIP2008提高组第一题“ISBN号码”,表面看是一道字符串处理题,但几乎所有初学者第一次提交都会WA——不是因为代码写错了,而是因为压根没吃透ISBN-10校验码的数学本质。我…

作者头像 李华
网站建设 2026/8/27 10:36:02

Amazon FreeRTOS在MCU开发中的移植实战与量产要点解析

1. 从云端到板卡:FreeRTOS是怎么变成MCU厂商“标配”的做嵌入式这些年,我见过太多所谓的“生态合作”,最后都变成了官网上一张PPT。但MCU厂商集体拥抱Amazon FreeRTOS这件事,真不是虚的。从ST、NXP、TI到瑞萨、英飞凌,…

作者头像 李华
网站建设 2026/8/27 10:35:59

告别多余点击:X-Mouse Controls 让焦点跟随鼠标

告别多余点击:X-Mouse Controls 让焦点跟随鼠标 【免费下载链接】xmouse-controls Microsoft Windows utility to manage the active window tracking/raising settings. This is known as x-mouse behavior or focus follows mouse on Unix and Linux systems. 项…

作者头像 李华