## **概述**
[Amazon CloudWatch](https://aws.amazon.com/cn/cloudwatch/?trk=cndc-detail) 可实时监控您的亚马逊云科技资源以及您在亚马逊云科技上运行的应用程序。您可以使用 CloudWatch 收集和跟踪指标,这些指标是您可衡量的相关资源和应用程序的变量。您可以创建警报,利用这些警报监视指标,当超出阈值时,它们会发送通知或者对您所监控的资源自动进行更改。例如,您可以监控您的 [Amazon EC2 ](https://aws.amazon.com/cn/ec2/?trk=cndc-detail)实例的 CPU 使用率以及磁盘读写情况,然后使用此数据确定您是否应启动其它实例来处理增加的负载。您还可以使用此数据停止未完全利用的实例以节省开支。
但是,[Amazon CloudWatch](https://aws.amazon.com/cn/cloudwatch/?trk=cndc-detail) Alarm 仅会在警报从【正常】状态转变为【告警】状态时触发一次警报。此后,即使警报仍然处于【告警】状态,也不会有新的通知产生。
本文将介绍,如何基于 [Amazon SNS](https://aws.amazon.com/cn/sns/?trk=cndc-detail) 和 [Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail),在警报被触发后按照一定的时间频率来重复报警,实现持续报警的效果,确保您及时知晓系统中的问题。
## **流程图**
![image.png](https://dev-media.amazoncloud.cn/10e785477df242f19e2afa1e0e547001_image.png "image.png")
本方案会主要会使用到以下服务:
- [Amazon CloudWatch](https://aws.amazon.com/cn/cloudwatch/?trk=cndc-detail)
- [Amazon SNS](https://aws.amazon.com/cn/sns/?trk=cndc-detail)
- [Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail)
- Amazon Lambda
首先,创建 [Amazon CloudWatch](https://aws.amazon.com/cn/cloudwatch/?trk=cndc-detail) Alarm,当警报触发时,配置将警报信息发送至 [Amazon SNS](https://aws.amazon.com/cn/sns/?trk=cndc-detail),实际上告警操作类型除了 [Amazon SNS](https://aws.amazon.com/cn/sns/?trk=cndc-detail) 以外,还支持 [Amazon EC2 ](https://aws.amazon.com/cn/ec2/?trk=cndc-detail)操作,扩展 Auto Scaling 组以及 Amazon Systems Manager 中的一些操作,具体可以参考此链接。这里使用 [Amazon SNS](https://aws.amazon.com/cn/sns/?trk=cndc-detail),主要是为了后续串联 [Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail);
链接:
https://docs.aws.amazon.com/zh_cn/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html
接着,为 [Amazon SNS](https://aws.amazon.com/cn/sns/?trk=cndc-detail) 配置类型为 [Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail) 的订阅,这样便可将警报信息传输至 [Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail);
最后,将 [Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail) 配置为 Amazon Lambda 的触发器,这样当警报信息传输至 [Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail) 时,就会触发 Amazon Lambda;
其中核心逻辑有两个:
一、Amazon Lambda 与 [Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail) 集成使用的特性:您可以使用 Lambda 函数来处理某个 [Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail) 队列中的消息。Lambda 事件源映射支持标准队列和先进先出(FIFO)队列。在 [Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail) 中,您可以通过将来自一个应用程序组件的任务发送到一个队列中并异步处理它们来进行分载。Lambda 轮询队列并同步调用您的 Lambda 函数,其中有包含队列消息的事件。Lambda 按批次读取消息,并为每个批次调用一次函数。当您的函数成功处理一个批次后,Lambda 就会将其消息从队列中删除。
特性:
https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/with-sqs.html
二、[Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail) 可见性超时:当使用者接收并处理来自某个队列的消息时,消息将保留在该队列中。[Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail) 不会自动删除消息。因为 [Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail) 是分布式系统,所以无法保证使用者实际收到消息(例如,由于使用者应用程序问题)。因此,使用者在接收和处理消息后必须从队列中删除该消息。在收到消息后,消息将立即保留在队列中。为防止其他用户再次处理消息,[Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail) 会将可见性超时,即 [Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail) 阻止其他用户接收并处理消息的一段时间。消息的默认可见性超时为30秒。最小为0秒。最长为12小时。
可见性超时:
https://docs.aws.amazon.com/zh_cn/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html
在本解决方案中,Lambda 的代码逻辑为检查警报状态,当警报仍未修复时,会主动抛出一个异常,这样 Lambda 就会认为函数并未成功处理,也不会自动从队列中删除消息,随即使用 [Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail) 可见性超时来控制间隔时间,达到预计时间后便会重复报警,直到警报被修复。当然 [Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail) 本身也存在一些限制,消息最多能在队列中保留14天。如果您需要让警报机制保持超过14天,我们可以使用另一个方案。
限制:
https://docs.aws.amazon.com/zh_cn/AWSSimpleQueueService/latest/SQSDeveloperGuide/quotas-messages.html
另一个方案:
https://aws.amazon.com/cn/blogs/china/use-aws-step-functions-to-implement-continuous-amazon-cloudwatch-alarms/
除了解决方案中使用邮件完成警报的通知,您也可以实现短信、企业微信、钉钉、飞书等多种方式的通知。
## **步骤**
在开始之前,请先确保您具有登录 Amazon 全球区或中国区控制台的账号,并具备管理员权限,您可以先登录控制台,选择合适的区域,并保持窗口开启。
![image.png](https://dev-media.amazoncloud.cn/f5eb3d34c4ca40798fda787b1e591402_image.png "image.png")
### **创建 Amazon SQS**
请按下面的信息创建 SQS。
- Name: my-poc-alarm-queue
- Visibility timeout: 5 Minutes
- Message retention period: 14 Days
![image.png](https://dev-media.amazoncloud.cn/515db58c63854f9ea05962d219f74d7a_image.png "image.png")
### **创建 Amazon SNS**
请按下面的信息分别创建 SNS。
- Name: my-poc-alarm-sns
- Display name: my-poc-alarm-sns
![image.png](https://dev-media.amazoncloud.cn/1b8eeb273e424125b16fc361d37bf325_image.png "image.png")
- Name: my-poc-sendAlarm
- Display name: my-poc-sendAlarm
![image.png](https://dev-media.amazoncloud.cn/47e8f83585bc493086f1a1a893ee8584_image.png "image.png")
请按下面的信息分别创建 Subscriptions。
- Topic ARN: arn:aws:sns:region-code:account-id:my-poc-alarm-sns
- Protocol: [Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail)
- Endpoint: arn:aws:sqs: region-code: account-id:my-poc-alarm-queue
- Topic ARN: arn:aws:sns:region-code:account-id:my-poc-sendAlarm
- Protocol: Email
- Endpoint: your-email-address
### **创建 IAM Policy 和 IAM Role**
请按下面的信息创建用于 Amazon Lambda 的 IAM Role。
- 按照以下内容创建 trust-relationship.json 文件并创建 IAM Role
```
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
aws iam create-role \\
--role-name my-poc-lambda-role \\
--assume-role-policy-document file://trust-relationship.json
```
- 按照以下内容创建 IAM Policy
```
my-poc-sqs-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"sqs:DeleteMessage",
"sqs:ReceiveMessage",
"sqs:GetQueueAttributes"
],
"Resource": "arn:aws:sqs:region-code:account-id:my-poc-alarm-queue"
}
]
}
aws iam create-policy \\
--policy-name my-poc-sqs-policy \\
--policy-document file://my-poc-sqs-policy.json
my-poc-sns-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "sns:Publish",
"Resource": "arn:aws:sns:region-code:account-id:my-poc-sendAlarm"
}
]
}
aws iam create-policy \\
--policy-name my-poc-sns-policy \\
--policy-document file://my-poc-sns-policy.json
```
- 附加 IAM Policy 到 IAM Role
```
aws iam attach-role-policy \\
--policy-arn arn:aws:iam::account-id:policy/my-poc-sqs-policy \\
--role-name my-poc-lambda-role
aws iam attach-role-policy \\
--policy-arn arn:aws:iam::account-id:policy/my-poc-sns-policy \\
--role-name my-poc-lambda-role
aws iam attach-role-policy \\
--policy-arn arn:aws:iam::aws:policy/CloudWatchReadOnlyAccess \\
--role-name my-poc-lambda-role
aws iam attach-role-policy \\
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole \\
--role-name my-poc-lambda-role
```
**
### 创建 Amazon Lambda**
请按下面的信息创建 Lambda
- Author from scratch: selected
- Runtime: Python 3.9
- Architecture: x86_64
- Execution role: Use an existing role
- Existing role: my-poc-lambda-role
示例代码如下:
```
import json
import boto3
def lambda_handler(event, context):
cloudwatch = boto3.resource('cloudwatch')
sns = boto3.resource('sns')
topic = sns.Topic('arn:aws:sns:region-code:account-id:my-poc-sendAlarm')
tmpRecord = event['Records'][0]
tmpBody = json.loads(tmpRecord['body'])
tmpMessage = json.loads(tmpBody['Message'])
tmpAlarmName = tmpMessage['AlarmName']
alarm = cloudwatch.Alarm(tmpAlarmName)
tmpAlarmValue = alarm.state_value
tmpStateReason = alarm.state_reason
tmpjson = {}
tmpjson['AlarmName'] = tmpAlarmName
tmpjson['AlarmState'] = tmpAlarmValue
tmpjson['AlarmStateDetail'] = tmpStateReason
topic.publish(
Message=str(tmpjson)
)
if tmpAlarmValue == 'ALARM':
raise Exception("This alarm still exists!")
```
### **在 Amazon SQS 中创建 Lambda triggers**
点击 [Configure Lambda function trigger]
![image.png](https://dev-media.amazoncloud.cn/19e82ff3f9a548eaac49f19ed707f49e_image.png "image.png")
- Specify an Amazon Lambda function available for this queue: arn:aws:lambda:`region-code:account-id`:function:my-poc-alarm
在 Amazon Lambda 中修改 Triggers
![image.png](https://dev-media.amazoncloud.cn/969ef54a610c4f8ab524541c54e486dd_image.png "image.png")
将 Batch size 修改为[ 1 ],因为我们需要每一个单独的 Lambda 函数来处理单独一条 SQS 消息。
## **测试验证**
### **创建 Amazon EC2 和 Amazon CloudWatch Alarm**
创建 [Amazon EC2 ](https://aws.amazon.com/cn/ec2/?trk=cndc-detail)和 CloudWatch Alarm 的过程本章不做过多叙述,读者可以参考以下文档:
教程:[Amazon EC2 ](https://aws.amazon.com/cn/ec2/?trk=cndc-detail)Linux 实例入门
https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/EC2_GetStarted.html#ec2-launch-instance
根据静态阈值创建 CloudWatch 告警
https://docs.aws.amazon.com/zh_cn/AmazonCloudWatch/latest/monitoring/ConsoleAlarms.html
需要保证在警报触发时发送通知至arn:aws:sns:`region-code:account-id`:my-poc-alarm-sns
![image.png](https://dev-media.amazoncloud.cn/ae835cb7abb947f584467d0967747da2_image.png "image.png")
### **手动触发 Amazon CloudWatch Alarm**
笔者在这里是通过调整阈值的方式触发的。
UTC15:40 触发了名为 my-poc-alarm-bastion-cpu 的警报
![image.png](https://dev-media.amazoncloud.cn/4aedc546bfb949a299729f90bc16f282_image.png "image.png")
UTC15:44 触发了名为 my-poc-alarm-bastion-network 的警报
![image.png](https://dev-media.amazoncloud.cn/946fbfc4dfa74ca282fb6d27a94a4db9_image.png "image.png")
### **Amazon CloudWatch Alarm 重复报警**
可以观察到邮件是以我们设定的可见性超时的时间为间隔发送的。
![image.png](https://dev-media.amazoncloud.cn/66a3753a91e949418acd312e3852fb27_image.png "image.png")
## **总结**
在本博客中,您学习了如何构建自动化以集成利用所有托管服务的持续警报机制。通过这种机制,它将增强 CloudWatch 原生提供的“仅一次”警报机制。在关键工作负载或服务需要高可用性的情况下,搭建持续警报系统可以显著缩短响应时间。本方案有以下优势:
- 全部使用 Amazon 托管服务,配置简单,减轻了您的运维压力;
- 扩展性强。使用此示例架构图,我们甚至可以在同一 SQS 中为该警报机制构建多个警报;
1、[Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail) 配额;
https://docs.aws.amazon.com/zh_cn/AWSSimpleQueueService/latest/SQSDeveloperGuide/quotas-messages.html
2、Amazon Lambda 配额;
https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/gettingstarted-limits.html
- 成本低廉,大多数情况下服务的免费配额即可满足需求;
1、[Amazon SNS](https://aws.amazon.com/cn/sns/?trk=cndc-detail) 定价
https://aws.amazon.com/cn/sns/pricing/?nc1=h_ls
2、[Amazon SQS](https://aws.amazon.com/cn/sqs/?trk=cndc-detail) 定价
https://aws.amazon.com/cn/sqs/pricing/?nc1=h_ls
3、Amazon Lambda 定价
https://aws.amazon.com/cn/lambda/pricing/?nc1=h_ls
**本篇作者**
![image.png](https://dev-media.amazoncloud.cn/5af15a67acad4e6487bb3db915aee788_image.png "image.png")
**杨探**
*亚马逊云科技解决方案架构师,负责互联网行业云端架构咨询和设计。*