使用生产流量编写和测试 CloudFront 函数

作者: Julian Ju Yujin Jeong | 202 3

在维护 Web 应用程序时,有时我们需要构建一个必须以低延迟运行的简单逻辑。例如,你可能想根据条件设置网站重定向,或者快速验证传入的标题。 CloudFront Fun ctions 非常适合这些用例,因为它允许您编写轻量级 JavaScript 代码,这些代码可以添加或修改响应标头、将请求重定向到较新的网址或使用自定义响应进行响应。

这种基于脚本的方法提供了很高的灵活性,但它也有责任编写有效的代码并对其进行正确测试。通过在开发代码时遵循最佳实践,您可以确保最有效地使用此边缘计算功能,并将运行时错误的风险降至最低。

在这篇文章中,我们将分享编写和测试 CloudFront Functions 代码的一些注意事项,并使用真实的 HTTP 流量模式测试该函数。

云端函数特征

CloudFront Functions 是一种安全、快速且经济实惠的边缘计算,适用于处理简单的 HTTP 请求或响应。CloudFront 函数的执行由 亚马逊 CloudFront 根据观众请求或观众响应事件触发。

CloudFront 函数代码是什么样子?以下是一个示例代码(你可以 在这个 github 存储库 中找到更多示例 ):

function handler(event) {
    var request = event.request;
    var headers = request.headers;
    var host = request.headers.host.value;
    var country = 'DE' // Choose a country code
    var newurl = `https://${host}/de/index.html` // Change the redirect URL to your choice 
  
    if (headers['cloudfront-viewer-country']) {
        var countryCode = headers['cloudfront-viewer-country'].value;
        if (countryCode === country) {
            var response = {
                statusCode: 302,
                statusDescription: 'Found',
                headers:
                    { "location": { "value": newurl } }
                }

            return response;
        }
    }
    return request;
}

如你所见,它是 JavaScript 代码,其中包含一个强制的函数 处理程序(事件) 。将该函数与 CloudFront 关联后,CloudFront 将运行 处理 函数作为入口点。 事件 对象包含 HTTP 请求元数据或响应元数据,具体取决于事件触发器。处理函数必须返回 HTTP 请求或响应对象(如果出现查看器响应事件,则只允许 HTTP 响应),这样 CloudFront 才能继续处理返回的对象。请注意,您只能使用 CloudFront 函数呈现响应对象的标头,而 Lambda @Edge 可以呈现响应正文。

CloudFront Functions returns request event object to continue the flow, or returns response to change the flow and respond to viewers.

图 1 CloudFront 函数必须返回 HTTP 请求或响应对象。

CloudFront Functions 还设计为在有限的 CPU 时间内运行,以最大限度地减少延迟并以最大规模运行。每个函数执行都有有限的计算资源,以百分比表示为计算利用率指标。如果 CloudFront 函数使用的计算资源超过允许量,则该函数可能会失败。这将导致 CloudFront 向查看者提供错误响应。CloudFront 控制台和 TestFunction API 将计算利用率作为测试结果的一部分,显示在测试执行期间使用了最大允许计算资源的百分比。您的代码不应使用 100% 的计算量。我们建议您留出安全余地,例如利用率低于 80%,因为计算利用率可能会有所不同。

CloudFront console shows compute utilization of a function.

图 2 CloudFront 控制台显示了函数的计算利用率。

CloudFront 将已部署函数的计算利用率作为指标发布在 Amazon Cloud Watch 中。 您可以监控此 CloudWatch 指标,以了解您的函数的近乎实时的计算利用率。

Example of CloudWatch metric showing the compute utilization of CloudFront Functions.

图 3 显示 CloudFront 函数计算利用率的 CloudWatch 指标示例。

测试 CloudFront 函数代码

编写完代码后,应使用几个测试用例测试代码,以确保该函数按预期运行。这种测试通常被称为单元测试。至少有一个测试用例将验证该函数在预期输入下是否可以正常工作,而其他测试用例将验证该函数在极端情况下是否会中断。对于 CloudFront 函数,您还必须确认该函数是否在允许的计算利用率范围内。

使用控制台或 API 测试您的代码,然后准备 HTTP 请求的上下文数据(如果该函数用于查看器响应事件,则还要准备 HTTP 响应)。CloudFront 控制台为输入数据提供了框架,因此您可以使用模拟上下文数据快速测试您的功能。

Testing a function with CloudFront console

图 4 使用 CloudFront 控制台测试函数。

使用 API 调用时,必须将上下文数据作为 JSON 对象提供,如下所示:

{
    "version": "1.0",
    "context": {
        "eventType": "viewer-request"
    },
    "viewer": {
        "ip": "198.51.1.1"
    },
    "request": {
        "method": "GET",
        "uri": "/example.png",
        "headers": {
            "host": {"value": "example.org"}
        }
    }
}

如您所见,测试归结为使用一组标题、cookie、查询字符串和监控结果来精心设计正确的输入以满足您的测试目标。有几种方法可以使测试有效。

如果可能,测试每个代码路径并自动进行测试

CloudFront Functions 代码是轻量级的,因此在许多情况下,您应该能够为每个代码执行路径编写测试用例。由于会有多个测试输入,因此您可能需要自动化测试过程以加载每个测试输入并调用 API 调用。例如,您可以运行以下命令来测试具有多个测试对象的函数:

for f in *.json; do aws cloudfront test-function \
 --name ExampleFunction \
 --if-match ETVABCEXAMPLE \
 --event-object fileb://$f \
 --stage DEVELOPMENT; \
done

使用真实流量数据进行测试并监控计算利用率

当您为现有 CloudFront 发行版编写新的 CloudFront 函数时,在决定将其部署到生产环境之前,使用真实流量数据进行测试是有益的。它可能会揭示你在进行单元测试时没想到的极端情况。例如,您可能会发现某些客户端的 Us er-Agent 标 头值非常不同,或者标头缺失。它还可以测试函数的计算利用率。实际上,在编写代码之前,您应该查看真实的流量数据,以提高代码的有效性。即使您正在为尚未部署的新 CloudFront 发行版编写函数,也建议您从类似的现有发行版中获取可测试的数据。

根据生产流量进行测试

那么,如何根据生产流量创建测试数据呢?您必须收集 访问日志 并将其处理为测试输入。有许多方法可以处理访问日志,在本文中,我们将使用 Amazon Athena 作为示例。假设我们正在根据查看者请求编写一个 CloudFront 函数,该函数将读取传入的引用标头和 uri 路径。通过使用以下查询,您可以提取它们中最常见的组合。

SELECT
count(*) cnt, uri, referrer
-- please change the table name to yours
FROM combined
-- filtering 24 hours(1d) data
WHERE concat(year, month, day, hour) >= DATE_FORMAT
GROUP BY uri, referrer 
ORDER BY cnt desc
-- top 10 requests
limit 10

您也可以更进一步,让它们成为您的 CloudFront 函数代码的自动测试,如下所示。有关详细信息,请参阅 示例代码

python3 testingCFF.py --function CORS-Preflight
input(url, referer) --> output(status(Err or OK), ComputeUtilization%)
input(/images/sample.jpg, https://example.com/) --> output(OK, 11%)
input(/images/sample2.jpg, https://example.com/) --> output(OK, 15%)
input(/images/sample2.jpg, -) --> output(OK, 14%)
……………

考虑

使用这种方法时,可能需要考虑成本。Athena 根据扫描的数据记录查询费用。因此,不建议对所有现有日志运行查询。相反,您可以 将日志 加载到分区中 , 并将查询限制为仅扫描部分日志。此外,当您的 CloudFront 分配提供大量 HTTP 请求和响应时,您可以使用采样率较低的 CloudFront 实时日志。

此外,CloudFront 标准访问日志的标头数量有限。因此,您可能需要实时访问日志才能使用标准访问日志中没有的标头。

如果您要管理代码中的 CloudFront 分布以及其他资源,则可能需要将 CloudFront 函数测试集成到代码管道中。

结论

在这篇博客中,您了解了为什么需要测试 CloudFront Functions 的计算利用率,以及如何通过使用真实流量数据进行测试来避免过度使用计算利用率。

要了解更多信息,请访问 CloudFront 函数 文档 ,或查看 github 上的 示例代码

您可以开始在 亚马逊云科技 管理控制台 中编写代码 。

Julian Ju

朱利安

Julian 是东盟地区 亚马逊云科技 的边缘服务专家解决方案架构师。他在IT行业工作了超过25年,担任开发人员、技术项目经理、顾问和架构师。在 亚马逊云科技,他帮助客户采用 亚马逊云科技 Edge 服务,以获得更安全、更快的互联网体验。

Yujin Jeong

郑裕真

Yujin Jeong 是韩国的 亚马逊云科技 解决方案架构师。她热衷于帮助企业客户驾驭云之旅,寻找合适的解决方案来满足他们独特的业务需求。凭借自己的技术专长和经验,她通过创新和可扩展的云解决方案帮助客户实现云目标并推动业务成果。


*前述特定亚马逊云科技生成式人工智能相关的服务仅在亚马逊云科技海外区域可用,亚马逊云科技中国仅为帮助您发展海外业务和/或了解行业前沿技术选择推荐该服务。