Amazon Web Services ブログ

AWS IoT Core と Amazon CloudWatch Evidently を使用した IoT アプリケーションの A/B テストとダークローンチ

モノのインターネット (IoT) アプリケーションの開発は、顧客のニーズを満たし、価値あるビジネス成果を継続的に提供するために、より速いペースでアプリケーションを構築・保守するように加速しています。IoTデバイスにプッシュされる定期的なアップデートに加え、機能フラグにより、アプリケーションに存在するドーマントコード(注: IF文などで実際には使用されていないコード)をアクティブ化し、データドリブンなアプローチで新機能を段階的にリリースできます。たとえば、スマートサーモスタットのメーカーは、事前に導入された機械学習アルゴリズムをリモートでアクティブ化して温度を自動で調整し、あらかじめ定義した実験期間中に人間が行った手動調整の回数を観察することで、機械学習アルゴリズムの効果を測定できます。

CloudWatch の機能である Amazon CloudWatch Evidently を使用すると、開発者はアプリケーションコードに実験や機能管理を組み込むことができ、A/Bテストやダークローンチ(機能フラグ)を容易に実行できます。

この記事では、Evidently を AWS IoT CoreAWS Lambda と組み合わせて使用することで、IoT アプリケーションコードに埋め込まれた機能フラグをアクティブ化し、制御された実験を通して、各新機能のバリアントの結果を測定する方法について説明します。また、その情報をもとに様々なデバイスで最もパフォーマンスの高い機能バリアントをリリースする方法についても説明します。

ソリューションの概要

このソリューションは、AWS IoT Core、Lambda、Evidently で構成される完全なサーバーレスソリューションです。

この設計では、IoTデバイスとのフロントエンド統合に軽量MQTTプロトコルに基づく pub-sub モデルを使用しています。このアプローチは相互運用性を最大化し、Evidently が提供する機能管理の機能を抽象化します。AWS IoT Core Device Shadow サービス を使用してデバイスの状態を保存し、現在の (reported) 機能フラグと期待される (desired) 機能フラグのステータスをクラウドに保存します。

ソリューションがデプロイされたら、Evidently を使って実験やローンチを行います。

Solution architecture

図 1. ソリューションアーキテクチャ

このソリューションは以下のペルソナを対象としています。

  1. IoT アプリケーション開発者は新しい機能を開発してリリースします。その目的は、自社のコードがビジネス価値をもたらすようにすることです。IoT アプリケーションの開発者は、「新たにアクティブ化された機械学習モデルのうち、過去 24 時間にスマートサーモスタットで行った手動調整の回数を減らすことができて、それによってカスタマーエクスペリエンスの向上につながるものはどれか?」などの質問への回答を求めています。
  2. IoT フリートマネージャーは IoT デバイスの技術的特性を監視します。導入されているデバイスの現在のファームウェアバージョンや機能セットなど、オペレーション情報を収集します。IoT フリートマネージャーは、「お客様が所有しているどのスマートサーモスタットで、特定の機械学習機能がアクティブになっているか?」などの質問への回答を探しています。

ソリューションの仕組み

  1. AWS IoT Core デバイス (myDevice) は AWS IoT Core の予約済みトピック ($aws/things/myDevice/shadow/name/myFeatures/update/accepted) をサブスクライブします。これにより、デバイスの名前付きシャドウ (myFeatures) への更新が成功するとアクティブに通知されます。このメカニズムは、軽量の MQTT プロトコルを通じて IoT デバイスに目的の機能フラグステータスを指示します。
  2. デバイスは定期的に AWS IoT Core トピック (myApp/myDevice/myFeatures) にメッセージを公開します。JSON 形式のこの MQTT テレメトリペイロードは、現在の機能フラグステータス (myFeature) とカスタムメトリクス (myMetric) で構成されています。カスタムメトリクスは、機能の Key Performance Indicator (KPI) です。例えば、スマートサーモスタットでは、過去24時間に人が手動で行行った調整の回数を監視し、その減少を目指すことが有意義な KPI となります。KPI はリリースの目的に応じて、バッテリーの消耗率やユーザー満足度のスコア、毎日の平均使用量など、他の測定可能な複数の特性を追跡することができます。
  3. このトピックに公開されたすべてのメッセージは、設定された AWS IoT Core ルールと対応するアクションを通じて Lambda 関数を呼び出します。
  4. Lambda 関数は、デバイスのモノ名 (myDevice) をentityId として使用して Evidently EvaluateFeature API を呼び出します。これにより、Evidently サービスによって決定されたデバイスに必要な機能フラグが返されます。また、この関数は PutProjectEvents API を使用してカスタムメトリクスを送信し、Evidently の実験に使用します。Evidently は AWS が所有するキーを使用して、デフォルトで保存中のデータを暗号化しています。Evidently がプロジェクト、機能、リリース、実験に関するメタデータ、メトリクスイベント、評価データを保護する方法については、CloudWatch Evidently がデータを収集して保存する方法 を参照してください。
  5. また、Lambda 関数は AWS IoT Core 内のデバイスの JSON という名前付きシャドウオブジェクトを更新して、reported 機能フラグ値と desired 機能フラグ値を反映します。
  6. デバイスの名前付きシャドウが正常に更新されると、AWS IoT Core によって予約されたトピック ($aws/things/myDevice/shadow/name/myFeatures/update/accepted) に新しいメッセージが自動的に公開されます。このメッセージはサブスクリプションを通じてデバイスに受信されます。
  7. デバイスは期待される機能フラグ値を保存し、条件文を使用して機能に関連するローカルコードをアクティブ化します。

このソリューションでは、2 つの MQTT トピックを活用して AWS IoT Core デバイスと Evidently の統合を行います。

MQTT topic MQTT action by device Description
myApp/myDevice/myFeatures Publish デバイスがテレメトリ情報を公開するために使用するトピック
$aws/things/myDevice/shadow/name/myFeatures/update/accepted Subscribe デバイスが AWS IoT Core デバイスのシャドウアップデートをサブスクライブするために使用する予約済みトピック

注: MQTT トピックの命名規則は、このブログで説明している概念を簡単に説明できるように選択されています。MQTT トピックの名前付けに関するベストプラクティスは、Designing MQTT Topics for AWS IoT Core Whitepaper を参照してください。

ペルソナは次のメカニズムを使用してソリューションと対話します。

  1. IoT アプリケーションの開発者は、Evidently のプロジェクト、機能、実験を作成します。実験の開始後は、カスタムメトリクスを使用してパフォーマンスを監視し、A/B テストを利用することで、収集した有効性についての十分な情報から判断を下すことができます。満足のいく結果が得られた場合、選択した機能を制御された方法でデバイスグループ全体に起動できます。
  2. AWS IoT Core フリートインデックス は、IoT フリートマネージャーが、名前付きシャドウにインデックスを付けてクエリするように設定します。これは、IoT デバイスのreported機能フラグ値のレポートを作成するために行います。

ソリューションの導入

このソリューションでは、必要なすべての AWS リソースをデプロイするための AWS CloudFormation テンプレートが提供されています。また、このテンプレートでは Evidently とのやりとりを手動でシミュレートできるように、単一の AWS IoT Core デバイスをプロビジョニングします。

前提条件

このチュートリアルでは、次の前提条件が整っている必要があります。

  • AWS アカウント を保有している必要があります。
  • CloudFormation テンプレートを使用して AWS リソースをデプロイするための AWS IAM 権限を保有している必要があります。
  • 独自の IoT デバイスを使用してこのソリューションをテストする場合は、AWS IoT Core を使用して個別にプロビジョニングする必要があります。

AWS CloudFormation テンプレートのデプロイ

このソリューションで説明されている AWS IoT Core と Evidently 環境をデプロイするために、当社の リポジトリ からダウンロードできる CloudFormation テンプレートを用意しています。このファイルはローカルマシンにダウンロードし、CloudFormation を使用してデプロイする必要があります。

AWS コンソールで CloudFormation サービスに移動し、スタック ページから スタックの作成 > 新しいリソースを資料(標準)を選択します。スタックの作成ページが表示されると、選択した AWS リージョンがリソースをデプロイするリージョンであることを確認してください。さらに、このソリューションで利用されるすべてのサービスが、選択した AWS リージョンで利用可能であることを確認してください。サービスの利用可否は、AWS Regional Services のドキュメントで確認できます。CloudWatch Evidently 機能を AWS リージョンで利用できるかどうかは、Amazon CloudWatch User Guide CloudWatch Evidently での起動と A/B 実験を実行する セクションに記載されています。

前提条件 – テンプレートの準備テンプレートの準備完了 のままにしてください。テンプレートの指定 セクションでは テンプレートファイルのアップロード ラジオボタンを選択し、ファイルの選択 をクリックします。ファイルブラウザで、ダウンロードしたテンプレートを選択し、次へ を選択します。

スタックの詳細を指定 ページで、一意のスタック名 (myIoTApp など) を入力し、必要に応じてパラメータのデフォルト値を更新します。

  • thingName (default: myDevice) – AWS IoT Core デバイスの名前のプレフィックス
  • variantModelBaseline (default: ModelBaseline) – Evidently で使用されているベースラインモデルの名前
  • variantModelVariantA (default: ModelVariantA) – Evidently で使用される最初のモデルバリアントの名前
  • variantModelVariantB (default: ModelVariantB) – Evidently で使用される2つ目のモデルバリアントの名前
Specifying CloudFormation stack details

図 2. CloudFormation スタックの詳細の指定

パラメータ フィールドに入力したら、次へ を選択します。

スタックオプションの設定 ページで、デフォルト値のままにして 次へ を選択します。

レビュー ページで、表示された情報を確認し、ページ下部の AWS CloudFormation によって IAM リソースが作成される場合があることを承認します チェックボックスを選択して、送信 を選択します。

CloudFormation スタックのステータスが CREATE_COMPLETE になると、デプロイが完了したことになります。出力 タブには、テストに必要な次の値が含まれます。スタックの作成には約 3 分かかります。

  • outputPublishToThisTopic ([Stack name]/[Stack name]-EvidentlyIoT-[thingName]/myFeatures) – このテストデバイスがサブスクライブする MQTT トピック。
  • outputSubscribeToThisTopic ($aws/things/[Stack name]-EvidentlyIoT-[thingName]/shadow/name/myFeatures/update/accepted) – デバイスがサブスクライブする、テストデバイスの名前付きシャドウ用に予約された MQTT トピック。AWS IoT Core は、デバイスの名前付きシャドウへの変更を受け入れると、このトピックに JSON レスポンス状態ドキュメントを公開します。
  • outputThingName ([Stack name]-EvidentlyIoT-[thingName]) – デバイスに使用されるモノ名のプレフィックス。これはテストデバイスの名前でもあります。

CloudFormation スタックの 出力 セクションに表示される他の値は、オプションのロードジェネレータ環境で使用されます。ロードジェネレータスタックをデプロイする手順については、この記事の後半で説明します。

Reviewing the CloudFormation stack output

図 3. CloudFormation スタックの出力の確認

1 台のテストデバイスを使用してソリューションとやりとりする

AWS IoT Core の MQTT テストクライアントを使用して、単一の IoT デバイスとソリューションとのやりとりをシミュレートします。

AWS コンソールの AWS IoT Core ホームページ に移動し、左側のメニューから テスト > MQTT テストクライアント を選択します。トピックをサブスクライブする タブの トピックのフィルター テキストボックスに、outputSubscribeToThisTopic CloudFormation 出力の値を入力して、サブスクライブ を選択します。これで、サブスクリプション リストにサブスクリプションが表示されます。

Subscribing to a topic

図 4. トピックの購読

トピックに公開する タブに移動し、トピック名 テキストボックスに outputPublishToThisTopic CloudFormation 出力の値を入力します。

テレメトリトピックへのペイロードの公開をシミュレートするには、メッセージに myFeaturemyMetric の両方のkey-value ペアが含まれている必要があります。ペイロードの例を以下に示します。

{
    "myFeature": "ModelBaseline",
    "myMetric": 5
}

この JSON ペイロードを メッセージペイロード テキストボックスに入力し、発行 を選択します。

Simulating publishing of a payload to the telemetry topic

図 5. テレメトリトピックへのペイロードの公開のシミュレーション

この例では、myFeature の値は現在使用中の機能をデバイスから報告するようにシミュレートし、myMetric 値はカスタムメトリクスのレポートに使用されます。

MQTT テストクライアントは、名前付きシャドウの JSON シャドウドキュメント の内容を返します。

Named shadow contents

図6. 名前付きシャドウのコンテンツ

レスポンス内の desired の値は、Evidently がこの AWS IoT Core デバイス に割り当てた機能フラグです。Evidently の実験が始まるまでは、これは常にデフォルトのバリアントです。reported 値は、テスト中に メッセージペイロード を介して以前に公開された値と一致します。

デバイス側での機能情報の処理

デバイス上で実行される実際の IoT アプリケーションでは、受信した ["desired"] ["MyFeature"] Key-Value を処理して、機能をアクティブ化するのに必要なロジックをコードで実行する必要があります。

デバイス側のコードの例を以下に示します。

if state["desired"]["myFeature"] == "ModelBaseline":
    print("This is my Baseline code!")
    # TODO: Baseline Model routine
elif state["desired"]["myFeature"] == "ModelVariantA":
    print("This is my Model Variant A code!")
    # TODO: Model Variant A routine
elif state["desired"]["myFeature"] == "ModelVariantB":
    print("This is my Model Variant B code!")
    # TODO: Model Variant B routine
    # TODO: Code to publish the myFeature value back as telemetry with the reported value

Amazon CloudWatch Evidently の実験を実行

CloudFormation テンプレートを利用すると、機能と実験が設定されている Evidently プロジェクトがすでに作成されています。実験の初期状態は 作成済み です。Evidently が 機能バリアントの割り当てを開始するには、実験を開始する必要があります。

実験を開始するには、まず AWS コンソールで CloudWatch > アプリケーションのモニタリング > Evidently に移動します。プロジェクト一覧に [Stack name]-myEvidentlyProject という名前で自動的に作成されたプロジェクトが表示されます。プロジェクトページに移動するため、プロジェクト名を選択します。

実験 タブを選択すると、[Stack name]-myEvidentlyExperiment という名前で作成された実験が表示されます。実験ページに移動する実験名を選択します。次に、アクション メニューの 実験を開始 オプションを選択して、実験を開始します。

Starting the Evidently experiment

図 7. Evidently の実験を開始

ここでは、実験の終了日を定義できます。この例では、後で最高のパフォーマンスを発揮する機能を公開するために、4 日間にわたって実験を実行することにしました。

Setting the Evidently experiment schedule end date

図 8. Evidently の実験スケジュールの終了日を設定

ロードジェネレータのデプロイ

シミュレートされた実験から有意義な結果が得られるように、50 個の AWS IoT Core をプロビジョニングするロードジェネレータソリューションを別途提供しています。

ロードジェネレータのテンプレートは リポジトリ からダウンロードできます。デプロイの準備ができているファイルをアップロードするには、以前のスタックのデプロイと同じ手順を実行する必要があります。

スタックの詳細を指定 ページで、スタックに固有の名前 (myIoTAppLoadGen など) を指定します。テンプレートは、CloudFormationスタックの作成とリソースの設定に使用される2つのパラメータを要求します。

  • deviceCount (default: 50) – ロードジェネレータの Lambda 関数が期待するデバイスの数。提供されている CloudFormation テンプレートは常に 50 の AWS IoT デバイスオブジェクトを作成しますが、Lambda コードではこのパラメータで指定された数のデバイスに対してのみ負荷が生成されることに注意してください。
  • loadInterval (default: 1) – ロードジェネレータの Lambda 関数が呼び出される頻度 (分単位)。実際の IoT ユースケースでは、デバイスの機能フラグに関する情報交換の頻度が少ないことを反映して、この値が高くなる場合があります。
  • stackName – AWS IoT Core と Evidently ソリューションを収容する、先にデプロイされた CloudFormation スタックの名前(myIoTApp など)。これは、前のスタックによって作成されたリソースを見つけるために使用されます。
Inputting CloudFormation stack load generator parameters

図 9. CloudFormation スタック ロード ジェネレータ パラメーターの入力

前回のスタックデプロイ時と同じ手順に従って、スタックのデプロイを開始します。デプロイのステータスが CREATE_COMPLETE になるまで約 3 分かかります。

ロードジェネレータの使用

デプロイされた CloudFormation スタックには、loadInterval パラメータに入力された頻度 (デフォルトでは 1 分ごと) で Lambda 関数をトリガーする Amazon EventBridge ルールのスケジュールがあります。Lambda 関数はステートレスで実行時間が短いため、このコードは MQTT を使用せずに HTTPS 経由で AWS SDK を使用して、 AWS IoT Core サービスと直接やり取りすることでデバイスの動作をシミュレートします。また、この関数は、5 (ベースラインモデル)、8 (モデルA)、3 (モデルB) のベースラインを中心とした範囲から任意のメトリクスを出力し、2 つの機械学習モデルバリアントのアクティブ化に対してデバイスがどのように反応するかを再現しています。これらの値は、実験中にパフォーマンスの高いバリアントと低いバリアントを意図的に示すために選択されました。

実験の結果を表示するには、Evidently 内の実験に戻り 結果 タブを選択します。このページは、EventBridge ルールがトリガーされるのを待つため、loadInterval パラメーターで指定された分数だけデータが入力されるまでかかる場合があります。それでも結果が表示されない場合は、ページの右上隅にある時間枠が実験の範囲に設定されていることを確認してください。

最初は、表またはグラフのすべての列にデータが完全に入力されているわけではないことに気付くでしょう。これらの統計計算が表示されるには、すべてのバリエーションについて少なくとも100 イベントが Evidentry に記録されている必要があります。統計値が入力されるには、ロードジェネレータの Lambda 関数を約 7 回実行する必要があります。これは、loadInterval パラメータのデフォルトでは約 8 分になります。

以下は、これら50台のデバイスを4日間にわたってソリューションと対話するように構成した場合の実験結果の例です。

Evidentlyでは、ModelVariantB の方がよりパフォーマンスが高いため、幅広い運用に適していると結論付けています。

Reviewing Evidently experiment results

図 10. Evidentlyの実験結果のレビュー

これで、ModelVariantB を使用してプロジェクトをローンチする準備ができました。

機能のローンチ

IoT アプリケーション開発者は、実験に満足したら、最も成功したバリアントをリリースして永続的に稼働させることができます。

機能をローンチする前に、実験が完了したか、実行中の実験がキャンセルされたかを確認してください。これは、実験とローンチが互いに干渉しないようにするために必要です。

機能をローンチするには、まず Evidently に移動し、プロジェクトのリストからプロジェクト ([Stack name]-myEvidentlyProject) を選択します。プロジェクト ページを開いたら、起動 タブを選択し、起動を作成 ボタンを選択します。機能の起動を作成ページが表示されます。

起動名 テキストボックスに、名前 (myIoTApp-myEvidentlyLaunch など) を付け、オプションで説明を入力します。既存の機能から選択 オプションが選択されていること、および機能名のドロップダウンから必要な機能 ([Stack name]-myEvidentlyFeature) が選択されていることを確認します。

この例では、この機能を 5段階に分けて起動し、すべてのデバイスを4時間ごとに最もパフォーマンスの高い機能に段階的に移行したいと考えています。起動の結果をより早く確認したい場合は、以下で説明するステップ間の間隔を 4 時間からテストに適した期間に減らしてください。

起動設定 セクションで、起動をスケジュール オプションを選択します。ステップ 1 をスケジュールステップ日付ステップ時間 (JST) を入力し、トラフィックの割合 でトラフィックの 100% を ModelBaseline 値に割り当てます。ModelVariantA 値の 除外 セレクタ を無効にしてから、トラフィックの 0% を ModelVariantB 値に割り当てます。

Setting up first Evidently launch step

図 11. 1 つ目の Evidently 起動ステップの設定

別のステップを追加 ボタンを選択し、ステップ日付ステップ時間 (JST) を 4時間毎に段階的に追加します。ModelBaseline トラフィックのパーセンテージを 25% 減らし、ModelVariantB トラフィックのパーセンテージを 25% 増やすように上記のステップを繰り返します。想定されるすべてのトラフィックが ModelVariantB に割り当てられるまで、これらの手順をさらに 4 回繰り返します。

起動を作成 ボタンを選択します。

Configuring steps for the Evidently launch

図 12. Evidently の起動手順の設定

起動 タブから、作成したばかりの起動名を選択します。このページには、リリース履歴と、今後実行される予定のステップが表示されます。

Reviewing the Evidently launch configuration steps

図 13. Evidently 起動の設定手順の確認

リリースが進むにつれて、デバイスが 16 時間かけて正常に移行され、すべてのデバイスで機能フラグが有効になります。

Monitoring an Evidently launch

図14. Evidently によるローンチのモニタリング

AWS IoT Core フリートインデックスによるデバイスの機能フラグの識別

AWS IoT Core fleet inIoT フリートマネージャーとして、AWS IoT Core フリートインデックスを使用して、myFeatures という名前付きシャドウに見つかる属性をクエリできます。

AWS IoT Core フリートインデックスは、Device Shadow を含む複数のソースからのデバイスデータのインデックス、検索、集約に使用される機能です。AWS IoT Core フリートインデックスを使用してモノの動的グループを作成することもできます。これにより、特定の機能フラグのみを有効にした状態で、ジョブやレポートなどの特定の AWS IoT Core 機能をターゲットデバイスに提供できます。たとえば、特定の機能フラグが設定されているデバイスのみをファームウェアアップデートの対象にしたい場合があります。

AWS IoT Core でこの機能を使用するには、 名前付きシャドウのためのモノのインデックスの有効化 の必要があります。これを行うには、まず AWS IoT Core コンソール に移動し、左側のメニューで 設定 を選択します。フリートのインデックス作成 セクションまでスクロールして、インデックス作成の管理 を選択します。

ページ右上のスイッチを選択し、ラベルに 有効化済み と表示されるようにして、フリートインデックスを有効にします。次に、名前付きシャドウの追加 チェックボックスを選択してから、 シャドウ名を追加 を選択します。

シャドウ名 テキストボックスに myFeatures と入力し、追加 を選択します。最後に、ページの下部にある 更新 を選択します。

Turning on AWS IoT Core fleet indexing

図 15. AWS IoT Core フリートインデックスを有効にする

myFeatures という名前付きシャドウのフリートインデックス作成を有効にすると、高度な検索を実行して、機能フラグ reported.myFeature 属性に基づいてカスタムレポートを作成できます。

高度な検索をシミュレートするには、AWS IoT コンソール から 管理 > すべてのデバイス に移動し、左側のメニューから モノ に移動します。モノ ページの 高度な検索 ボタンを選択します。クエリ ボックスに、次のように入力します。

shadow.name.myFeatures.reported.myFeature: "ModelVariantB"

次に 検索 を選択します。このクエリは、クエリを保存 ボタンを使用して後で使用できるように保存できます。

Performing an AWS IoT Core advanced thing search

図 16. AWS IoT Core の高度なモノ検索の実行

上のスクリーンショットは、実験の実行中に行われた高度な検索を示しています。このクエリでは、機能フラグが ModelVariantB に設定された 16 台のデバイスが返されます。これは、デバイスの総数の約 3 分の 1 に相当します。起動完了後に 高度な検索を実行すると、このクエリによってすべてのデバイスが返されます。

クリーンアップ

今後料金が発生しないように、プロビジョニングされた CloudFormation スタックを削除してください。Evidently の実験または起動を実行している場合は、これらを手動で停止する必要があります。そうしないと、スタックの削除が失敗します。

まとめ

この記事では、Evidently を AWS IoT Core と Lambda を組み合わせて使用して、IoT アプリケーションに埋め込まれた機能フラグをアクティブ化しました。また、制御された実験を使用して新機能の影響を測定し、この情報を使用してさまざまなデバイスで機能をより広くリリースする方法を説明しました。

著者について

Alan Peaty

Alan Peaty

Alan は、Global Systems Integrators (GSIs) とその顧客が AWS サービスを採用するのを支援する Partner Solutions Architect です。AWS に入社する前は、さまざまなシステムインテグレーターでアーキテクトとして働き、ビジネス要件を技術的ソリューションに変換していました。仕事以外では、Alan は熱心なランナーで、イギリスの田舎の泥だらけのトレイルを走るのが大好きです。また、モノのインターネット(IoT)の愛好家でもあります。

Pete Davis

Pete Davis

Pete は Partner Solutions Architect で、EMEA全域の Public Sector の Global System Integrator として働いています。前職では、出版業界、カスタマーコミュニケーション業界、マーケティング業界で、公共部門と民間部門の両方で働いてきました。Alan は F1 と MotoGP の熱心なファンです。また、休みは家族である4匹の犬との散歩で忙しくしています。

翻訳はテクニカルアカウントマネージャーの日平が担当しました。原文は こちら です。