教程:使用 Evidently 示例应用程序进行 A/B 测试 - Amazon CloudWatch
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

教程:使用 Evidently 示例应用程序进行 A/B 测试

本节介绍如何使用 Amazon CloudWatch Evidently 进行 A/B 测试的教程。本教程涉及 Evidently 示例应用程序,其是一个简单的响应应用程序。示例应用程序将被配置为显示/不显示 showDiscount 功能。当向用户显示该功能时,购物网站上以 20% 的折扣显示价格。

除了向一些用户而非向其他用户显示折扣之外,在本教程中,您还设置 Evidently 以从两个变体收集页面加载时间指标。

警告

此场景需要 IAM 用户具有编程访问权限和长期凭证,这会带来安全风险。为帮助减轻这种风险,我们建议仅向这些用户提供执行任务所需的权限,并在不再需要这些用户时将其移除。必要时可以更新访问密钥。有关更多信息,请参阅《IAM 用户指南》中的 更新访问密钥

步骤 1:下载示例应用程序

首先下载 Evidently 示例应用程序。

下载示例应用程序
  1. 从以下 Simple Storage Service (Amazon S3) 存储桶下载示例应用程序:

    https://evidently-sample-application.s3.us-west-2.amazonaws.com/evidently-sample-shopping-app.zip
  2. 解压缩程序包。

步骤 2:添加 Evidently 端点并设置凭证

接下来,将 Evidently 的区域和端点添加到示例应用程序包中 src 目录下的 config.js 文件,如以下示例所示:

evidently: { REGION: "us-west-2", ENDPOINT: "https://evidently.us-west-2.amazonaws.com (https://evidently.us-west-2.amazonaws.com/)", },

您还必须确保应用程序有调用 CloudWatch Evidently 的权限。

授予示例应用程序调用 Evidently 的权限
  1. 联合到您的 Amazon 账户。

  2. 创建 IAM 用户并将 AmazonCloudWatchEvidentlyFullAccess 策略附加到该用户。

  3. 记录 IAM 用户的访问密钥 ID 和秘密访问密钥,因为您在下一步中需要使用它们。

  4. 在您本节早些时候修改的同一 config.js 文件中,输入访问密钥 ID 和秘密访问密钥的值,如以下示例所示:

    credential: { accessKeyId: "Access key ID", secretAccessKey: "Secret key" }
    重要

    我们使用此步骤使示例应用程序尽可能简单,以便您尝试。我们不建议您将 IAM 用户凭证放到实际的生产应用程序中。我们建议您使用 Amazon Cognito 进行身份验证。有关更多信息,请参阅将 Amazon Cognito 与 Web 和移动应用程序集成

步骤 3:为功能评估设置代码

当您使用 CloudWatch Evidently 评估功能时,必须使用 EvaluateFeature 操作为每个用户会话随机选择功能变体。此操作根据您在实验中指定的百分比,将用户会话分配给功能的每个变体。

为书店演示应用程序设置功能评估代码
  1. 将客户端生成器添加到 src/App.jsx 文件,以便示例应用程序可以调用 Evidently。

    import Evidently from 'aws-sdk/clients/evidently'; import config from './config'; const defaultClientBuilder = ( endpoint, region, ) => { const credentials = { accessKeyId: config.credential.accessKeyId, secretAccessKey: config.credential.secretAccessKey } return new Evidently({ endpoint, region, credentials, }); };
  2. 将以下内容添加到 const App 代码部分以启动客户端。

    if (client == null) { client = defaultClientBuilder( config.evidently.ENDPOINT, config.evidently.REGION, );
  3. 通过添加以下代码构建 evaluateFeatureRequest。此代码会预填充我们在本教程后面推荐的项目名称和功能名称。您可以替换自己的项目名称和功能名称,只要您也可以在 Evidently 控制台中指定这些项目名称和功能名称。

    const evaluateFeatureRequest = { entityId: id, // Input Your feature name feature: 'showDiscount', // Input Your project name' project: 'EvidentlySampleApp', };
  4. 添加代码以调用 Evidently 进行功能评估。发送请求时,Evidently 会随机分配查看或不查看 showDiscount 功能的用户会话。

    client.evaluateFeature(evaluateFeatureRequest).promise().then(res => { if(res.value?.boolValue !== undefined) { setShowDiscount(res.value.boolValue); } getPageLoadTime() })

步骤 4:为实验指标设置代码

对于自定义指标,请使用 Evidently 的 PutProjectEvents API 向 Evidently 发送指标结果。以下示例说明了如何设置自定义指标并向 Evidently 发送实验数据。

添加以下函数来计算页面加载时间,并使用 PutProjectEvents 向 Evidently 发送指标值。将以下函数添加到 Home.tsx 中并在 EvaluateFeature API 中调用此函数:

const getPageLoadTime = () => { const timeSpent = (new Date().getTime() - startTime.getTime()) * 1.000001; const pageLoadTimeData = `{ "details": { "pageLoadTime": ${timeSpent} }, "UserDetails": { "userId": "${id}", "sessionId": "${id}"} }`; const putProjectEventsRequest = { project: 'EvidentlySampleApp', events: [ { timestamp: new Date(), type: 'aws.evidently.custom', data: JSON.parse(pageLoadTimeData) }, ], }; client.putProjectEvents(putProjectEventsRequest).promise(); }

自您下载 App.js 文件并对其进行所有编辑之后,该文件应该如此处所示。

import React, { useEffect, useState } from "react"; import { BrowserRouter as Router, Switch } from "react-router-dom"; import AuthProvider from "contexts/auth"; import CommonProvider from "contexts/common"; import ProductsProvider from "contexts/products"; import CartProvider from "contexts/cart"; import CheckoutProvider from "contexts/checkout"; import RouteWrapper from "layouts/RouteWrapper"; import AuthLayout from "layouts/AuthLayout"; import CommonLayout from "layouts/CommonLayout"; import AuthPage from "pages/auth"; import HomePage from "pages/home"; import CheckoutPage from "pages/checkout"; import "assets/scss/style.scss"; import { Spinner } from 'react-bootstrap'; import Evidently from 'aws-sdk/clients/evidently'; import config from './config'; const defaultClientBuilder = ( endpoint, region, ) => { const credentials = { accessKeyId: config.credential.accessKeyId, secretAccessKey: config.credential.secretAccessKey } return new Evidently({ endpoint, region, credentials, }); }; const App = () => { const [isLoading, setIsLoading] = useState(true); const [startTime, setStartTime] = useState(new Date()); const [showDiscount, setShowDiscount] = useState(false); let client = null; let id = null; useEffect(() => { id = new Date().getTime().toString(); setStartTime(new Date()); if (client == null) { client = defaultClientBuilder( config.evidently.ENDPOINT, config.evidently.REGION, ); } const evaluateFeatureRequest = { entityId: id, // Input Your feature name feature: 'showDiscount', // Input Your project name' project: 'EvidentlySampleApp', }; // Launch client.evaluateFeature(evaluateFeatureRequest).promise().then(res => { if(res.value?.boolValue !== undefined) { setShowDiscount(res.value.boolValue); } }); // Experiment client.evaluateFeature(evaluateFeatureRequest).promise().then(res => { if(res.value?.boolValue !== undefined) { setShowDiscount(res.value.boolValue); } getPageLoadTime() }) setIsLoading(false); },[]); const getPageLoadTime = () => { const timeSpent = (new Date().getTime() - startTime.getTime()) * 1.000001; const pageLoadTimeData = `{ "details": { "pageLoadTime": ${timeSpent} }, "UserDetails": { "userId": "${id}", "sessionId": "${id}"} }`; const putProjectEventsRequest = { project: 'EvidentlySampleApp', events: [ { timestamp: new Date(), type: 'aws.evidently.custom', data: JSON.parse(pageLoadTimeData) }, ], }; client.putProjectEvents(putProjectEventsRequest).promise(); } return ( !isLoading? ( <AuthProvider> <CommonProvider> <ProductsProvider> <CartProvider> <CheckoutProvider> <Router> <Switch> <RouteWrapper path="/" exact component={() => <HomePage showDiscount={showDiscount}/>} layout={CommonLayout} /> <RouteWrapper path="/checkout" component={CheckoutPage} layout={CommonLayout} /> <RouteWrapper path="/auth" component={AuthPage} layout={AuthLayout} /> </Switch> </Router> </CheckoutProvider> </CartProvider> </ProductsProvider> </CommonProvider> </AuthProvider> ) : ( <Spinner animation="border" /> ) ); }; export default App;

每次用户访问示例应用程序时,都会向 Evidently 发送自定义指标进行分析。Evidently 会分析每个指标并在 Evidently 控制面板上实时显示结果。以下示例显示了指标有效负载:

[ {"timestamp": 1637368646.468, "type": "aws.evidently.custom", "data": "{\"details\":{\"pageLoadTime\":2058.002058},\"userDetails\":{\"userId\":\"1637368644430\",\"sessionId\":\"1637368644430\"}}" } ]

步骤 5:创建项目、功能和实验

然后,您可以在 CloudWatch Evidently 控制台中创建项目、功能和实验。

为本教程创建项目、功能和实验
  1. 通过 https://console.aws.amazon.com/cloudwatch/ 打开 CloudWatch 控制台。

  2. 在导航窗格中,选择 Application SignalsEvidently

  3. 请选择 Create project(创建项目)并填写字段。您必须使用 EvidentlySampleApp 作为项目名,以便示例正常工作。对于 Evaluation event storage(评估事件存储),选择 Don't store Evaluation events(不要存储评估事件)。

    填写字段后,选择 Create Project(创建项目)。

    有关更多详细信息,请参阅创建新 项目

  4. 创建项目后,在该项目中创建功能。将功能命名为 showDiscount。在此功能中,创建 Boolean 类型的两个变体。使用值 disable 将第一个变体命名为 False,然后使用值 enable 将第二个变体命名为 True

    有关创建功能的更多信息,请参阅 向项目添加功能

  5. 完成功能创建后,请在项目中创建实验。将实验命名为 pageLoadTime

    本实验将使用名为 pageLoadTime 的自定义指标,用以衡量被测试页面的页面加载时间。用于实验的自定义指标使用 Amazon EventBridge 创建而成。有关 EventBridge 的更多信息,请参阅什么是 Amazon EventBridge?

    要创建该自定义指标,请在创建实验时执行以下操作:

    • 对于 Metric source(指标来源),请在 Metrics(指标)下选择 Custom metrics(自定义指标)。

    • 对于 Metric name(指标名称),请输入 pageLoadTime

    • 对于 Goal(目标),请选择 Decrease(减少)。这表示我们希望该指标的值较低,以指明该功能变体最佳。

    • 对于 Metric rule(指标规则),请输入以下内容:

      • 对于 Entity ID (实体 ID),请输入 UserDetails.userId

      • 对于 Value key(值键),请输入 details.pageLoadTime

      • 对于 Units(单位)中,请输入 ms

    • 请选择 Add metric(添加指标)。

    对于 Audiences(受众),请选择 100% 以便所有用户都能进入实验。将变体之间的流量拆分设置为每个变体 50%。

    然后,请选择 Create experiment(创建实验)来创建实验。创建它后,只有您告知 Evidently 将其启动,它才会启动。

步骤 6:开始实验并测试 CloudWatch Evidently

最后的步骤是开始实验并开启示例应用程序。

开始教程实验
  1. 通过 https://console.aws.amazon.com/cloudwatch/ 打开 CloudWatch 控制台。

  2. 在导航窗格中,选择 Application SignalsEvidently

  3. 选择 EvidentlySampleApp 项目。

  4. 请选择 Experiments(实验)选项卡。

  5. 请选择 pageLoadTime 旁边的按钮,然后依次选择 Actions(操作)、Start experiment(开始实验)。

  6. 请选择实验结束的时间。

  7. 请选择 Start experiment(开始实验)。

    实验会立即开始。

然后,使用以下命令开启 Evidently 示例应用程序:

npm install -f && npm start

开启应用程序后,您将被分配到正在测试的两个功能变体之一。一个变体会显示“20% 折扣”,另一个变体不会显示。继续刷新页面以查看不同的变体。

注意

Evidently 包含粘性评估。功能评估是确定性的,这意味着对于相同的 entityId 和功能,用户将始终收到相同的变体分配。变体分配仅在实体被添加到覆盖或实验流量增加时更改。

但是,为了让您轻松使用示例应用程序教程,Evidently 会在您每次刷新页面时重新分配示例应用程序功能评估,以便您在无需添加覆盖的情况下即可体验两种变体。

故障排除

我们建议您使用 npm 版本 6.14.14。如果你看到有关构建或开启示例应用程序的任何错误,并且您正在使用不同版本的 npm,请执行以下操作。

安装 npm 版本 6.14.14
  1. 使用浏览器连接到 https://nodejs.org/download/release/v14.17.5/

  2. 下载 node-v14.17.5.pkg 并运行此 pkg 安装 npm。

    如果您看到 webpack not found 错误,导航至 evidently-sample-shopping-app 文件夹并尝试以下操作:

    1. 删除package-lock.json

    2. 删除yarn-lock.json

    3. 删除node_modules

    4. package.json 中删除 webpack 依赖项

    5. 运行以下命令:

      npm install -f && npm