概述
Amazon Simple Notification Service(SNS)是 AWS 的消息通知服务,采用发布/订阅(pub/sub)模型:向 Topic 发布一条消息,所有 Subscription 都会收到。
常见用途:
- CloudWatch Alarm 触发后发邮件、短信
- 应用解耦广播(一个事件通知多个下游)
- 推送到 Lambda、SQS、HTTP 端点
SNS 不负责监控、不负责排队存消息;它只负责「把通知送出去」。
核心概念
| 概念 | 说明 |
|---|---|
| Topic | 主题,消息发布的目标(如 enx-api-backup-alerts) |
| Publisher | 发布方,调用 Publish 把消息发到 Topic |
| Subscription | 订阅,声明 Topic 上的消息要发到哪(邮箱、Lambda 等) |
| Protocol | 订阅协议:email、sms、lambda、sqs、https 等 |
| Endpoint | 订阅目标地址(邮箱地址、Lambda ARN、队列 ARN 等) |
Publisher(CloudWatch Alarm / 应用 / 其它 AWS 服务)
→ Publish → Topic
├─ Subscription: email → 你的邮箱
├─ Subscription: lambda → 触发函数
└─ Subscription: sqs → 写入队列
与 CloudWatch、SQS 的区别
| 服务 | 角色 |
|---|---|
| SQS | 消息队列,消费者拉取;适合异步削峰、DLQ 存档 |
| CloudWatch | 监控与告警;Alarm 触发时不直接发邮件 |
| SNS | 通知;把一条消息推给多个订阅者 |
备份失败通知链路:
SQS DLQ(存失败详情)
→ CloudWatch Alarm(发现 DLQ 有消息)
→ SNS Topic(发通知)
→ Email 订阅(人收到邮件)
邮件订阅注意点
用 email 协议时,创建订阅后 AWS 会发一封 Confirm subscription,必须点链接确认,否则 Topic 有消息也收不到邮件。
订阅未确认前,控制台里状态为 PendingConfirmation。
同一 Topic 同时发邮件和 Telegram
SNS 没有原生 telegram 协议。可在同一 Topic 上再挂一个 lambda 订阅,由 Lambda 调用 Telegram Bot API 发消息:
CloudWatch Alarm → SNS Topic
├─ email
└─ lambda → Telegram
Bot Token 放在 terraform.tfvars(已 gitignore)或 SSM,不要写进仓库。
计费与免费额度
按通知次数计费,不同协议价格不同。详见 SNS Pricing。
Homelab 常见情况:
| 协议 | 免费档(参考) |
|---|---|
| Email / Email-JSON | 每月前 1,000 封 通常免费 |
| HTTP/S | 每月前 100,000 次 |
| SMS | 无长期免费档,按条收费 |
每周备份失败才告警几次,基本不产生费用。
OpenTofu 示例
来自 w10n-config/aws/opentofu/ec2-tokyo/lambda.tf(CloudWatch Alarm → SNS 邮件):
resource "aws_sns_topic" "enx_backup_alerts" {
name = "enx-api-backup-alerts"
}
resource "aws_sns_topic_subscription" "enx_backup_alerts_email" {
topic_arn = aws_sns_topic.enx_backup_alerts.arn
protocol = "email"
endpoint = "you@example.com"
}
# Alarm 的 alarm_actions 指向 Topic ARN
resource "aws_cloudwatch_metric_alarm" "example" {
# ...
alarm_actions = [aws_sns_topic.enx_backup_alerts.arn]
}
CloudWatch 向 SNS 发布时,Topic 需允许 cloudwatch.amazonaws.com 调用 sns:Publish(见同文件 aws_sns_topic_policy)。
常用 CLI
# 列出 Topic
aws sns list-topics
# 创建 Topic
aws sns create-topic --name my-alerts
# 订阅邮件(之后去邮箱点确认)
aws sns subscribe \
--topic-arn arn:aws:sns:ap-northeast-1:123456789012:my-alerts \
--protocol email \
--notification-endpoint you@example.com
# 查看某 Topic 的订阅
aws sns list-subscriptions-by-topic \
--topic-arn arn:aws:sns:ap-northeast-1:123456789012:my-alerts
# 手动发一条测试(确认订阅后)
aws sns publish \
--topic-arn arn:aws:sns:ap-northeast-1:123456789012:my-alerts \
--message "test notification"