## 1. 背景
在业务全球化的大背景下,全球 CDN 加速是必不可少的一项服务,亚马逊云科技的 CDN 服务-CloudFront,也是众多客户的选择对象。CloudFront 可以以低延迟和高传输速度向全球用户安全地分发静态内容和 API,缩短等待时间,提高用户体验。由于国内客户对于 CDN 的使用习惯和要求与海外客户有较大差异,所以在一些方面还是需要做一些定制化的方案来适配国内用户的需求。
在我们实际接触的客户中,客户针对 CDN 的监控 API 还是有一定的需求特点的:
* 客户要求监控的实时性,同时又要求数据准确性,往往要求监控 API 既能提供低延迟的指标查询用于监控和及时发现问题,又能依照依照标准日志的统计分析数据来用于成本对账和一些其他的数据校正。
* 需要以客户的业务域名作为 host 去查询指标,但是 CloudFront 的本身接口以都是以 Distribution ID 来查询,因此需要定制专门的接口参数。
* 客户实际业务需求中有几百个域名,因此也要求接口可以支持多域名并发请求查询。
亚马逊云科技在 [Amazon CloudFront](https://aws.amazon.com/cn/cloudfront/?trk=cndc-detail) Extensions 中推出了开箱即用的监控解决方案,支持基于实时日志和标准日志的监控,客户可以复用已有的13个监控指标,也可以基于这个架构进行二次开发,这里就分享一下我们在使用 [Amazon CloudFront](https://aws.amazon.com/cn/cloudfront/?trk=cndc-detail) Extensions 的 CloudFront 监控时学习到的一些经验。
## 2. 解决方案概览
### 2.1 非实时监控 non-real-time-monitoring
![image.png](https://dev-media.amazoncloud.cn/73606aa844474fd28eaff5d15aaaa1d0_image.png "image.png")
这个是官方给的基于标准日志监控的架构图,方案的实现流程图中也一目了然,具体的解释可以去参看官方文档的描述,这里不多赘述,详见:https://awslabs.github.io/aws-cloudfront-extensions/zh/monitoring/non-real-time-monitoring/?trk=cndc-detail 。解决方案最终以 API 或 UI 的方式对外提供监控指标查询的。
从使用者的角度看,方案还是很有特点的:
首先是 CloudFormation 一键部署,这个很方便。方案使用了 API Gateway、Lambda、DynamoDB、S3、Athena、Glue、EventBridge。我们后续改造还使用了 EC2。不得不说 Amazon 的服务组件真的够多,虽然减少了很多的开发工作量,但是如果单独去部署这么多组件,学习难度本身就很大了。CloudFormation 很好的解决了这个问题。
然后是通过对日志的二次处理提升了查询效率 。CloudFront 标准日志包含30多个字段。有些字段对于日常监控和数据统计来讲可能不太用的上,因此在方案中并没有标准日志存进 S3 之后直接用于查询分析,而是进行了一个二次处理,删除了不需要的字段再存进 S3,以减少 Athena 扫描的日志量,提升效率,减少成本。
### 2.2 实时监控 real-time-monitoring
![image.png](https://dev-media.amazoncloud.cn/0291b2e00ec0480f8690ba1e69622f47_image.png "image.png")
上图是基于实时日志的监控架构图,本身架构也很完善,性能也 OK,不过我们再实际使用中,出于成本和实际需要求的考虑,又对实时监控做了另外的改造。
### 2.3 监控改造方案
![image.png](https://dev-media.amazoncloud.cn/77f378d59ee74d24931c4a49305631b1_image.png "image.png")
标准日志监控的部分,沿用了官方 [Amazon CloudFront](https://aws.amazon.com/cn/cloudfront/?trk=cndc-detail) Extentions 的方案,不过将处理日志的 Lambda 换成了 EC2;
实时监控部分,官方给出的方案中可以基于实时日志分析出很多指标信息,有些指标如根据下载速率基于国家和运营商的分布是 CloudWatch 中没有的。由于我们的客户需求对于实时监控主要要求的指标有带宽、流量、状态码、缓存命中率、回源带宽等都可以直接从 CloudWach 获取或转换的指标,所以这里对于实时指标要求较简单的场景来讲,我们可以通过 Lambda 获取 CloudWatch 接口数据来处理,然后写入 DynamoDB 中。对于 CloudWatch 中不支持的指标,再使用此方案。
这样可以节省掉实时日志监控系统产生的资源成本,又能做到以统一的接口格式对外提供实时监控指标和标准日志的监控指标。
## 3. 方案部署
### 3.1 基于标准日志的监控
标准日志监控,在亚马逊云科技已经发布了官方的部署指南,部署也很简单,直接通过 CloudFormation 一键部署即可,这里就不在复述了。我们部署了 Non-real time monitoring,不过官方版本部署之后,我们在使用中,还是发现了一些问题,并针对性做了一些调整优化。
#### 3.1.1 调整一
就部署资源和程序而言,我们在官方的基础上替换了处理原始日志的Lambda,将其替换成了 EC2,并且给 EC2 添加 SQS 和 S3 的权限。
![image.png](https://dev-media.amazoncloud.cn/a3014f80651f49cb9481072e83968ac8_image.png "image.png")
![image.png](https://dev-media.amazoncloud.cn/cd661e1a7a6f49b5b8c046328adb38bf_image.png "image.png")
为什么这么做呢?原因有两点:
一是 Lambda 本身是有内存的限制的,而官方在这里的处理机制是把整个日志包全都读入内存之后才开始处理,日志过大就会发生内存溢出进而无法处理对应日志里的内容造成数据缺失,日志太小有会造成资源浪费。
那为什么要换成 EC2,不能改 Lambda 的处理机制呢?当然也可以的,不过这就是我要说的第二点原因。我们账号下正好有一台做日志格式定制化转换的 EC2 资源,换成 EC2 也是为了更好地复用资源,节省成本。
当然 EC2 里处理机制也做了定制开发,改成了边读取边处理,避免出现同样的内存为题。这个机制也可通过 Lambda 实现。
#### 3.1.2 调整二
Athena 查询 S3 桶中日志的 sc-bytes 字段,官方默认使用的类型是 int,这对于小流量是没有问题的,但是我们实际使用当中,比如5分钟的流量字节数超过了 int 类型的长度限制,就无法查询出正确的结果,如图:
![image.png](https://dev-media.amazoncloud.cn/f5838b0102ff4ca39c64b41ee07029b8_image.png "image.png")
所以这里我们把 int 改成了 bigint。对于大流量用户而言,这里也要注意一下。
### 3.2 实时指标监控
上文中描述了对实时指标的改造,这里需要创建一个 Lambda 函数,部署代码,以便获取 CloudWatch 接口指标并写入 [Amazon DynamoDB](https://aws.amazon.com/cn/dynamodb/?trk=cndc-detail) 中。
在 Amazon Lambda 控制台,点击创建函数,编辑好函数名和编写函数的语言(这里我们用了 Python)
关联以下角色权限:
创建后将对应的程序代码部署该 Lambda 函数中。
![image.png](https://dev-media.amazoncloud.cn/53986765cb564e57a2e279d9d9c3171e_image.png "image.png")
## 4. 方案使用说明
### 4.1 开启日志
基于标准日志的监控分析,部署之后要使用起来,需要先开启对应分配的标准日志。
打开 CloudFront 控制台,在分配标签下单击需要创建标准日志的分配(Distribution)ID。
在设置中点击编辑按钮,打开编辑设置并找到标准日志记录。
选中打开,并在 S3 存储桶列表中找到包含-cloudfrontlogbuckete 关键字的选项,将其设置为传输日志文件的 S3 存储桶。如果您没有找到对应名字的 S3 存储桶,请确认是否在部署解决方案时,参数 CloudFront Log Type为yes-Non-Realtime,详情请参阅[部署解决方案](https://awslabs.github.io/aws-cloudfront-extensions/zh/deployment/#\\_1?trk=cndc-detail)。
最后点击保存更改,使设置生效。
### 4.2 调用 API
URL:endpoint
调用方法:GET
认证:header: x-api-key
请求参数:
| 参数名 | 是否必要 | 参数值 |
| --- | --- |--- |
| Domain | 是 | 查询域名,多个域名以逗号, 分隔,也可用All 来直接拉取全部域名的值 ( www.a.com,www.b.com,www.c.com ) |
| StartTime | 是 | 开始时间,0时区。格式严格匹配“ YYYY-mm-dd HH:MM:SS ” 例如 2022-05-24 13:00:00 |
| EndTime | 是 | 结束时间,0时区。 |
| Metric | 是 | ![image.png](https://dev-media.amazoncloud.cn/4bbe436f2e3649a3b5e7faa022a70b5c_image.png "image.png") |
接口响应参数:
```js
{
"Response": {
"RequestId": "b30e37f1-4b48-44b5-89cc-d09157b087e9",//请求ID
"Interval": "5min",//粒度
"Data": [
{
"www.a.com": [//domain
{
"Metric": "stdBandwidth",//指标类型
"DetailData": [//具体指标数据
{
"Time": "2022-08-01 08:00:00",
"Value": "8062630279"
},
]
}
]
}
]
}
}
```
## 5 方案测试
### 5.1 单域名标准日志指标测试
![image.png](https://dev-media.amazoncloud.cn/21edd6a003db4170ab8366d78c55e683_image.png "image.png")
### 5.2 多域名实时指标测试
![image.png](https://dev-media.amazoncloud.cn/d6c474fefc6a42809bb187784dc8a851_image.png "image.png")
![image.png](https://dev-media.amazoncloud.cn/dcd4e3e6a21a4c5298deeb3f4095faa9_image.png "image.png")
## 6 小结
本文介绍了我们是如何基于 [Amazon CloudFront](https://aws.amazon.com/cn/cloudfront/?trk=cndc-detail) Extensions 进行二次开发,最终构建出符合特定客户需求的 CDN 监控解决方案。除了监控解决方案外, [Amazon CloudFront](https://aws.amazon.com/cn/cloudfront/?trk=cndc-detail) Extensions 还提供了 CloudFront 配置快照、SSL 证书批处理和扩展存储库等功能,详情参考:https://awslabs.github.io/aws-cloudfront-extensions/zh/?trk=cndc-detail