亚马逊AWS官方博客

Amazon CloudFront 部署小指南(十七) – 利用 AWS 服务构建用户友好的 CloudFront性能监控工具

背景简介

当用户在访问网页时,偶尔会遇到资源加载缓慢的问题。这种现象可能由多种原因引起,比如网络连接差、CDN 节点调度不合理或源站响应缓慢等。为了快速定位问题,通常需要完整的链路日志,从用户侧到源站。然而,在 AWS CloudFront 中,尽管所有请求日志都被记录在 POP 点上,但用户侧的性能指标(如 DNS 解析时间、TCP 连接时间、请求时间、响应时间等)却难以直接获取。

为了解决这一痛点,笔者开发了一个用户友好的 CDN 性能监控工具,借助 AWS 的服务实现指标收集、上报及可视化展示,帮助开发者快速定位和解决问题。

项目地址:https://github.com/zhangzhao2010/aws-cdn-client-perf

工具简介

本工具分为两部分:

  1. 指标收集及上报工具
    基于浏览器的 Performance API,通过 JavaScript 采集用户侧的性能指标,并将这些数据通过 API Gateway 上报到 AWS Lambda 进行处理,最终存储到 DynamoDB 中。
  2. 数据可视化工具
    使用 Python 和 Streamlit 开发的简单易用的可视化工具,支持快速查询用户上报的性能数据,并通过图表进行直观展示。

Performance API 简介

Performance API 是浏览器提供的用于检测网页性能的 API,它是一组 API 的组合。主要包括:

  • Resource Timing API:与网页资源(脚本、样式、图片等)加载相关的耗时信息,定义了接口 PerformanceResourceTiming。
  • Navigation Timing API:从页面导航开始一直到 load 事件结束,中间经历过程的耗时信息。定义了接口 PerformanceNavigationTiming,此接口继承自 PerformanceResourceTiming 接口。
  • Paint Timing:与网页绘制相关的耗时信息。定义了接口 PerformancePaintTiming。

架构设计

以下是系统架构图,展示了工具的主要工作流程:

  1. 用户访问性能检测页面(perf.html),页面自动采集用户侧的性能指标。
  2. 通过 API Gateway 将性能数据上报到 AWS Lambda。
  3. Lambda 将处理后的数据存储在 DynamoDB 中。
  4. 可视化工具通过查询 DynamoDB 展示用户上报的数据。
  5. (可选)在 Route53 上开启 query log,以记录 DNS Resolver 信息。

详细部署步骤

一、手动部署

1. 创建 DynamoDB 表

  • 表名:cdn-perf-reports
  • Partition key:uuid (String)
  • 容量模式:On-demand

DynamoDB 存储了每次性能数据上报的详细信息,以供后续查询和分析。

2. 创建 Lambda 函数

  1. 创建一个 Lambda 函数,使用 Python 3.12 作为运行时。
  2. 赋予 Lambda 函数写入 DynamoDB 的权限:
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "dynamodb:PutItem"
                ],
                "Resource": [
                    "arn:aws:dynamodb:<region>:<account-id>:table/cdn-perf-reports"
                ]
            }
        ]
    }
    
    Python
  3. 复制以下代码到 lambda_function.py 中:
    import json
    import boto3
    import os
    import time
    
    dynamodb = boto3.resource('dynamodb')
    table_name = 'cdn-perf-reports'
    table = dynamodb.Table(table_name)
    
    def lambda_handler(event, context):
        try:
            uuid = event['pathParameters']['uuid']
            body = event['body']
            
            table.put_item(
                Item={
                    'uuid': uuid,
                    'source_ip': event['requestContext']['http']['sourceIp'],
                    'x-forwarded-for': event['headers']['x-forwarded-for'],
                    'data': body,
                    'timestamp': int(time.time())
                }
            )
    
            return {
                'statusCode': 200,
                'headers': {
                    'Access-Control-Allow-Origin': '*',
                    'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
                    'Access-Control-Allow-Headers': 'Content-Type, Authorization',
                    'strict-origin-when-cross-origin': 'strict-origin-when-cross-origin'
                },
                'body': json.dumps({'message': 'Report saved successfully'})
            }
        except Exception as e:
            return {
                'statusCode': 500,
                'body': json.dumps({'error': str(e)})
            }
    
    Python

3. 创建API Gateway

  1. 创建一个 HTTP API。
  2. 新建路由:/report/{uuid},方法为 POST
  3. 将路由与 Lambda 函数集成,选择 Payload format version:2.0。

4. 在 Route53 上创建子域名托管域以记录

  1. 在 Amazon Route53 上单独创建一个子域名的托管域用于记录 DNS 查询日志,例如子域名为 example.com,为该托管域配置 Query logging configuration 以记录 query log;
  2. 添加一个解析记录,record name 为 *.perf.example.com,record type 可以为 A 或 CNAME,value 可以为任何可访问的资源地址;
  3. perf 页面会使用生成的 uuid 构建一个唯一域名,例如:perf.example.com,尝试向该域名发送一个 GET 请求以触发DNS解析。

5. 配置和发布性能采集页面

  • html/perf.html 的以下内容修改为实际配置:
    • reportUrl 修改为 API Gateway 的地址。
    • imageUrls 中的图片 url 修改为通过 CDN 分发的测试图片地址(需与 perf.html 同域)。
    • (可选)将 r53Url 修改为测试域名 url。
  • 部署 perf.html 到源站(例如,S3 桶)并通过 CDN 分发。
  • perf.html 示例代码会加载三次测试图片,并且利用浏览器的 Performance API 采集以下指标:
    • DNS 解析时间
    • TCP 连接时间
    • 请求时间
    • 响应时间
  • 如果配置 了r53Url 并开启了 isReportR53Log,页面会尝试向该域名发送一个异步请求。

页面会自动向用户展示采集的性能指标,并上报到后端。

二、CDK 部署

1. 将项目克隆到本地,进入 cdk-cdn-perf 目录

2. 配置 AWS CDK 本地环境(如已配置可跳过)

参考链接:https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html

3. 部署指标收集后端

export AWS_REGION=us-east-1
cdk deploy CdnPerfApp
Python

4. 在 Route53 上测试测试域名

export AWS_REGION=us-east-1
cdk deploy CdnPerfRoute53 --parameters TestDomainName=perf.example.com
Python

5. 配置和发布性能采集页面

  • html/perf.html 的以下内容修改为实际配置:
    • reportUrl 修改为 API Gateway 的地址。
    • imageUrls 中的图片 url 修改为通过 CDN 分发的测试图片地址(需与 perf.html 同域)。
    • (可选)将 r53Url 修改为测试域名 url。
  • 部署 perf.html 到源站(例如 S3 桶)并通过 CDN 分发。
  • perf.html 示例代码会加载三次测试图片,并且利用浏览器的 Performance API 采集以下指标:
    • DNS 解析时间
    • TCP 连接时间
    • 请求时间
    • 响应时间
  • 如果配置了 r53Url 并开启了 isReportR53Log,页面会尝试向该域名发送一个异步请求。

页面会自动向用户展示采集的性能指标,并上报到后端。

数据可视化工具

在本地或 AWS EC2 上运行数据可视化工具,通过简单的查询即可快速分析性能数据:

  1. 确保环境具有查询 DynamoDB 的权限。
  2. 安装所需库并启动 Streamlit 应用:
    pip install streamlit plotly pandas boto3
    streamlit run streamlit/app.py
    
    Python

在 Streamlit 界面输入 uuid,即可查看具体的性能数据的可视化展示。可视化工具检索计算后会展示以下信息:

  • 用户的 IP;
  • 测试页面和图片加载的 Timeline,可明确地看到每个阶段的耗时;
  • 请求图片时 HTTP response header,从 response header 中可以看到请求的相关信息,包括当前请求使用的 POP 点;
  • 如果开启了 Route53 query log,页面会根据 uuid 查询 CloudWatch Log 以获取测试请求的 DNS resolver 相关信息;

工具的实际应用场景

  • 问题定位: 当用户反馈资源加载慢时,将性能采集页面链接发送给用户,快速采集性能数据以便诊断问题。
  • 指标分析: 结合用户数据,分析 CDN 调度、源站性能以及网络状况的潜在瓶颈。
  • 优化方案评估: 对比不同的优化方案(例如,调整 CDN 策略、增加节点等)的实际效果。

扩展与优化建议

  1. 添加安全措施:
    使用 API Gateway 提供身份验证(如 API 密钥或 JWT),防止滥用。
  2. 集成更多分析工具:
    使用 Amazon QuickSight 或 Amazon Athena 进行深度分析,获取更详细的性能洞察。
  3. 用户侧优化:
    提供更详细的报告,例如通过网络类型、地理位置等维度进一步细化数据。
  4. 自动化告警:
    结合 Amazon CloudWatch,当性能指标异常时自动发送告警邮件。

总结

通过 AWS 的一系列服务(CloudFront、DynamoDB、Lambda、API Gateway、Route53、CloudWatch Logs),我们构建了一个高效的用户端性能监控工具,助力开发者快速定位问题并提升用户体验。希望这套方案能为您的性能优化之旅提供新的思路。

相关资料

https://developer.mozilla.org/en-US/docs/Web/API/Performance_API/Resource_timing

https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming

https://developer.mozilla.org/en-US/docs/Web/API/PerformancePaintTiming

https://github.com/zhangzhao2010/aws-cdn-client-perf

本篇作者

张召

亚马逊云科技解决方案架构师,负责基于亚马逊云科技的云计算方案的架构设计,同时致力于亚马逊云科技的云服务在移动应用与互联网行业的应用和推广。拥有多年移动互联网研发及技术团队管理经验,丰富的互联网应用架构项目经历。

王骏兴

亚马逊云科技边缘产品架构师,负责亚马逊云科技 Edge 服务领域在中国的技术推广。在 CDN 内容分发以及 WAF 领域拥有多年实战经验,专注于边缘服务设计以及体验优化。

朱珊

亚马逊云科技客户解决方案经理,目前在亚马逊云科技主要支持泛娱乐行业的客户。通过运用云相关解决方案等帮助客户在迁移到亚马逊云和云上运维期间实现自身的业务价值,帮助客户成功。