
Amazon SNS(Simple Notification Service)是 AWS 提供的全托管发布/订阅消息服务,核心模型是:发布者向一个主题(Topic)发送消息,SNS 将这条消息立即推送给所有订阅了这个主题的端点。一条消息可以同时触发多个下游系统,这是 SNS 和 SQS 最本质的设计区别。
SNS 是什么,和 SQS 的核心差别
SQS 是拉取模型:消费者主动向队列发起请求取消息,消息在队列中持久化存储,直到被取走并显式删除。SNS 是推送模型:消息发布后 SNS 立即向所有订阅者推送,消息不在 SNS 中持久化,订阅端点必须在消息到达时能够接收处理。
从架构设计的角度看,两者解决的是不同的问题。SQS 的队列是一对一的:一条消息只被一个消费者处理,适合工作队列场景。SNS 的主题是一对多的:一条消息被推送给所有订阅者,每个订阅者都收到完整的消息副本,适合事件广播场景。
SNS 支持两类通信模式。Application-to-Application(A2A)是服务之间的消息传递,将消息推送给 SQS 队列、Lambda 函数、HTTP/HTTPS 端点或 Kinesis Data Firehose。Application-to-Person(A2P)是系统向人的通知,通过 SMS 短信、Email 或手机 App 推送通知直接触达用户。
标准主题与 FIFO 主题
SNS 提供两种主题类型,和 SQS 的队列类型相对应,选型逻辑也相似。
标准主题支持近乎无限的发布吞吐量,消息投递保证”至少一次”,消息可能以与发布顺序不完全一致的顺序到达订阅者。适合绝大多数事件通知场景,吞吐量没有实际上限,是新项目的默认起点。
FIFO 主题(First-In-First-Out)提供严格的顺序保证和”精确一次”投递,发布吞吐量限制为每秒 300 条消息(开启批量模式后提升到每秒 3,000 条)。FIFO 主题的名称必须以 .fifo 结尾,只能订阅 SQS FIFO 队列,不支持 Email、SMS 等其他端点类型。适合对消息顺序有严格要求的场景,如金融交易事件的顺序广播、需要精确一次处理的业务流。
FIFO 主题的成本也高于标准主题,在选型时应确认业务真正需要顺序保证,而不是为了”更安全”而选择 FIFO。
| 对比项 | 标准主题 | FIFO 主题 |
| 吞吐量 | 近乎无限 | 300–3,000 条/秒 |
| 投递保证 | 至少一次 | 精确一次 |
| 消息顺序 | 尽最大努力 | 严格保证 |
| 支持的订阅端点 | SQS、Lambda、HTTP、Email、SMS、Mobile Push | 仅 SQS FIFO |
| 适合场景 | 事件广播、通知推送、高吞吐量 | 严格顺序的事件链 |
创建主题与配置订阅
创建 SNS 主题
用 AWS CLI 创建一个标准主题:
aws sns create-topic –name order-events
返回的主题 ARN 格式为 arn:aws:sns:ap-east-1:123456789012:order-events,后续所有发布消息和管理订阅的操作都使用这个 ARN 标识目标主题。
创建订阅
订阅是将某个端点关联到主题的操作。每种端点类型的订阅创建方式略有不同,以下是几种常见类型。
将 SQS 队列订阅到 SNS 主题:
aws sns subscribe \
–topic-arn arn:aws:sns:ap-east-1:123456789012:order-events \
–protocol sqs \
–notification-endpoint arn:aws:sqs:ap-east-1:123456789012:order-processing-queue
将 Lambda 函数订阅到 SNS 主题:
aws sns subscribe \
–topic-arn arn:aws:sns:ap-east-1:123456789012:order-events \
–protocol lambda \
–notification-endpoint arn:aws:lambda:ap-east-1:123456789012:function:order-notifier
将邮件地址订阅到主题:
aws sns subscribe \
–topic-arn arn:aws:sns:ap-east-1:123456789012:order-events \
–protocol email \
–notification-endpoint ops-team@company.com
邮件订阅创建后,SNS 会向邮件地址发送确认邮件,收件人必须点击确认链接后订阅才正式生效。SQS 和 Lambda 订阅则不需要确认步骤,创建即生效。
权限配置
SNS 向 SQS 队列投递消息时,需要 SQS 队列的访问策略允许 SNS 的 SendMessage 操作。在 SQS 控制台的「访问策略」中添加:
{
“Version”: “2012-10-17”,
“Statement”: [{
“Effect”: “Allow”,
“Principal”: {“Service”: “sns.amazonaws.com”},
“Action”: “sqs:SendMessage”,
“Resource”: “arn:aws:sqs:ap-east-1:123456789012:order-processing-queue”,
“Condition”: {
“ArnEquals”: {
“aws:SourceArn”: “arn:aws:sns:ap-east-1:123456789012:order-events”
}
}
}]
}
SNS 向 Lambda 函数投递消息时,需要 Lambda 的资源策略允许 SNS 调用函数。关于 IAM 策略和资源权限的完整配置说明,可以参考 AWS IAM 权限管理教程。
消息过滤(Message Filtering)
消息过滤是 SNS 最实用的功能之一,也是降低下游处理成本的关键手段。在没有过滤的场景下,所有订阅者都会收到主题中发布的每一条消息,下游系统需要自己判断哪些消息与自己有关。消息过滤让 SNS 在投递前就做这个判断,只将符合条件的消息推送给对应的订阅者。
基于属性的过滤
基于属性的过滤(Attribute-based filtering)完全免费,是推荐的默认过滤方式。发布消息时在消息属性中附带元数据,订阅者在订阅配置中设置过滤策略,只接收属性匹配的消息。
以订单事件为例,发布消息时附带 orderType 属性:
aws sns publish \
–topic-arn arn:aws:sns:ap-east-1:123456789012:order-events \
–message ‘{“orderId”: “order-001”, “amount”: 299.99}’ \
–message-attributes ‘{
“orderType”: {
“DataType”: “String”,
“StringValue”: “express”
},
“region”: {
“DataType”: “String”,
“StringValue”: “asia”
}
}’
为某个 SQS 订阅设置过滤策略,只接收 orderType 为 express 的消息:
aws sns set-subscription-attributes \
–subscription-arn arn:aws:sns:ap-east-1:123456789012:order-events:xxx \
–attribute-name FilterPolicy \
–attribute-value ‘{“orderType”: [“express”]}’
这样,普通订单(orderType: standard)不会投递给这个订阅对应的 SQS 队列,只有加急订单才会被接收。另一个订阅了相同主题、设置了不同过滤策略的 SQS 队列,则可以只接收普通订单。
基于消息体的过滤
基于消息体的过滤(Payload-based filtering)按扫描的数据量计费($0.09/GB),过滤条件直接匹配 JSON 消息体中的字段,适合不方便修改发布端代码去添加消息属性的场景。
过滤策略变更后需要最多 15 分钟才能在所有 SNS 节点上全量生效,这是分布式系统最终一致性的特性,在调试时应注意。
SNS + SQS 扇出架构
SNS 和 SQS 单独使用时,各自解决了特定的问题。两者配合使用才能构建出兼顾广播能力和持久化处理能力的完整架构——这就是”扇出”(Fanout)模式。
扇出架构的结构是:一个 SNS 主题作为事件入口,多个 SQS 队列分别订阅这个主题,每个队列后面挂接独立的消费者(EC2 Worker 或 Lambda 函数)。当一个事件发布到 SNS 主题时,所有订阅的 SQS 队列都会收到这条消息的副本,各自的消费者并行处理,互不依赖。
以电商订单为例:订单创建事件发布到 order-events SNS 主题,三个 SQS 队列同时订阅这个主题:
- inventory-queue:库存服务扣减库存
- shipping-queue:物流服务生成发货单
- analytics-queue:数据分析服务更新销售报表
三个队列的处理逻辑完全独立。物流服务故障期间,消息在 shipping-queue 中积压,等服务恢复后继续处理,不影响库存服务和分析服务的正常运行。这是扇出架构最核心的价值:通过解耦将故障隔离在单个消费者内部,不让一个服务的问题级联影响其他服务。
相比之下,如果没有 SNS 直接让订单服务同步调用三个下游服务,任何一个服务超时都会阻塞整个调用链;如果只用 SQS 而没有 SNS,同一条消息只能进入一个队列,无法同时触发三个并行处理流程。关于 SQS 队列的配置细节和死信队列机制,可以参考 AWS SQS 教程。
扇出架构还有一个常见的应用场景是生产/测试环境同步。将生产环境的 SQS 队列订阅到 SNS 主题处理真实订单,同时将测试环境的 SQS 队列也订阅到同一主题,实时接收生产数据进行测试,不需要在测试环境单独构造测试数据。
SNS 与 Lambda 集成
SNS 触发 Lambda 是异步调用——SNS 将消息推送给 Lambda 后立即返回,不等待 Lambda 的处理结果。Lambda 函数内部的处理成功或失败,SNS 不感知,也不会因为 Lambda 处理失败而重新投递消息。
这和 SQS 触发 Lambda 的行为有本质差别。SQS 触发 Lambda 时,消息在 Lambda 处理完成并显式确认(或超时)后才从队列中移除,处理失败的消息会重新变为可见,可以配置死信队列捕获反复失败的消息。SNS 直接触发 Lambda 时,如果 Lambda 处理失败,消息直接丢失,没有自动重试机制。
因此,对于需要保证消息不丢失的场景,推荐使用 SNS + SQS + Lambda 的组合:SNS 扇出消息到 SQS 队列,Lambda 从 SQS 队列取消息处理,利用 SQS 的持久化和重试机制保障可靠性。关于 Lambda 函数的事件源映射和错误处理配置,可以参考 AWS Lambda 完整教程。
如果处理结果不需要严格保证(如发送通知邮件、记录访问日志),SNS 直接触发 Lambda 的架构更简单,省去了 SQS 队列的中间层。
计费方式
SNS 按实际使用量计费,没有前期成本和最低消费承诺。每月首百万次 API 请求和首十万次 HTTP/HTTPS 投递免费,超出后按量计费。
标准主题计费: 每次发布操作是一次 API 请求,每 64KB 的消息数据计为一次请求。一条 256KB 的消息 = 4 次请求计费。每月前 100 万次免费,超出后 $0.50/百万次。
FIFO 主题计费: 发布操作 $0.30/百万次,订阅消息(发布次数 × 订阅数量)$0.01/百万次。FIFO 主题比标准主题的计费更复杂,同等消息量下成本约是标准主题的 4–5 倍。
投递费用: 向 SQS 和 Lambda 投递消息本身不收投递费,但传输的数据量按 AWS 数据传输费率计费(同区域内免费)。向 HTTP/HTTPS 端点投递,超出免费额度后 $0.60/百万次。向邮件地址投递,超出首 1,000 封后 $2/100,000 封。SMS 无免费额度,按目的国家单独计费,即使投递失败(如号码无效)也会计费。
消息过滤计费: 基于属性的过滤完全免费;基于消息体的过滤按扫描量收费 $0.09/GB,被过滤掉的消息和成功投递的消息都计入扫描量——如果 90% 的消息被过滤,仍然为 100% 的消息体扫描量付费。过滤量大时,基于属性的过滤在成本上更有优势。
降低成本的直接方式: 使用 PublishBatch 批量发布,单次 API 调用最多发布 10 条消息,将 API 请求次数减少到 1/10;大消息分拆为多条小消息,避免单条超过 64KB 带来的请求倍增。
配置 AWS 账单告警时,建议同时为 SNS 设置月度消费上限通知。当 SNS 消费超出预期时提前收到告警,可以帮助排查是否有异常发布行为或 SMS 投递失败积累。关于如何配置 AWS 费用告警和排查账单异常,可以参考 AWS 账单告警的判断思路。
常见使用场景
系统监控告警通知
CloudWatch 告警触发时,最常见的通知方式是发布消息到 SNS 主题,再由主题推送到运维人员的邮件或 SMS。一个 SNS 主题可以同时向多个邮件地址和手机号发送告警,不需要为每个告警单独配置通知目标,是系统告警通知的标准架构。
电商订单事件的扇出处理
用户下单后,API 将订单创建事件发布到 SNS,同时触发库存扣减、物流建单、数据分析三个并行处理流程,各自通过独立的 SQS 队列和消费者处理,任何一个流程的延迟或故障不影响其他流程,也不影响订单 API 的响应时间。
手机 App 推送通知
SNS 支持向 iOS(APNs)、Android(FCM)设备直接发送 App 推送通知,并提供设备端点管理、消息发送状态追踪和批量推送能力,适合需要向大量移动设备推送个性化通知的应用。
生产/测试环境数据同步
同一 SNS 主题同时订阅生产 SQS 队列和测试 SQS 队列,生产环境的真实事件自动流入测试环境,测试团队可以用真实数据验证新版本的处理逻辑,不需要人工构造测试用例,也不影响生产环境的正常运行。
账号开通与代理充值
使用 SNS 需要有效的 AWS 账号,SNS 本身没有资源配额申请门槛,创建主题和配置订阅不需要额外审批。对于同时使用 SNS、SQS、Lambda 构建消息架构的团队,月均 AWS 综合消耗在 $300 以上时,通过 AWS 代理商 渠道充值可以享受代理专属折扣(低至 7 折),付款支持 USDT 和对公转账,适合没有海外信用卡或需要企业对公结算的团队,账号免实名、免绑卡,1 分钟极速交付。



