匿名ユーザーの利用量に応じて料金をテナント毎にチャージバックする方法 | How to charge back per tenant in anonymous embedding use case | Japanese

背景

近年、クラウドサービスの利用が広がるにつれ、マルチテナントアーキテクチャを採用する SaaS アプリケーションが増えています。マルチテナントでは、1つのリソースを複数のテナント(顧客組織)で共有することで、コストを抑えつつスケーラビリティを確保できます。しかし、共有リソースの利用量を正確に測定し、テナント毎に公平にコストを按分することが課題となっています。

課題

2023年に、Amazon QuickSight のコスト管理を容易にする2つのアップデートが実装されました。

2023年6月のアップデートでは、AWS Cost and Usage Report に QuickSight の各リソースIDが出力されるようになりました。このアップデートにより AWS Cost and Usage Report (CUR) 上でダッシュボードとユーザーの識別子ARNを取得できるようになりました。

2023年9月のアップデートでは、QuickSight がリソースへのタグ付けをサポートし、コスト管理が容易になりました。タグ付け可能なリソースには、データセット、データソース、ダッシュボード、テンプレート、トピック、ユーザーなどがあります。特に、ユーザーにタグを付けることで、そのタグをコスト分析タグとして利用でき、CUR に表示することができます。
しかしながら、このタグ付け機能は匿名ユーザーをサポートしていません。というのも匿名ユーザを利用している場合、匿名ユーザー故に実体がないのでタグ付けができないからです。
そのため、匿名ユーザーを多用する SaaS サービス事業者は、この新機能を活用することができません。

匿名ユーザの利用時は、セッションキャパシティ単位の課金となるため、利用したセッション数を把握する必要があります。
これまではセッション数を計測するために、自社のバックエンドサーバーから匿名ユーザー用の埋め込み URL を生成する度にログを自身で保存する必要がありました。しかし、この方法では運用の負担が増え、さらにセッション数を正確に取得することが困難でした。

ソリューション

本ソリューションでは、SaaS サービス事業者が名前空間 (Namespace) を利用して各テナントに匿名ユーザー向けのダッシュボードを提供するユースケースを想定しています。この場合、各テナントが消費したセッション数を正確に把握し可視化する必要があります。

まず、CUR をデータソースとして活用します。CUR には匿名ユーザーが利用したリソース名が記録されており、そこからNamespace 情報を抽出することができます。この情報を元に、Namespace 単位での匿名ユーザー数や、個々のユーザーが消費したセッション数を算出します。
次に、QuickSight で CUR データをグラフ化し、各テナントのセッション利用状況を一目で確認できるダッシュボードを構築します。ダッシュボードでは、テナント毎のセッション消費量の推移や、消費量の多いテナントランキングなどを視覚的に表示できます。
さらに、この過程で CUR データを加工することで、QuickSight の料金計算がより簡単になるよう整形します。
本ソリューションを活用することで、SaaS サービス事業者は匿名ユーザーによるリソース消費を正確に把握し、適切にコスト按分を行うことができます。

前提と注意点

この記事の注意点は以下の3点です。

  • Namespace 機能の利用が必要
  • Reader には匿名ユーザーを利用する
  • テナントごとのSPICEの利用料の按分計算は未対応

Reader タイプが匿名ユーザーであることを前提としています。匿名ユーザーは QuickSight へのログインなしにダッシュボードを閲覧できるユーザーであり、ダッシュボードの埋め込み時のみ利用できます。

匿名ユーザーを利用したダッシュボードの埋め込みのフローをおさらいします。

埋め込みを実施するには、まず、その URL をあらかじめ生成する必要があります。匿名ユーザの埋め込み URL を生成する場合は専用の API が提供されており、その中で埋め込み対象のダッシュボードだけでなく、匿名ユーザが仮想的に属する名前空間 (Namespace) を指定することができます。API の実行例を以下に記載します。

aws quicksight generate-embed-url-for-anonymous-user \
--aws-account-id XXXXXXXXXXXX \
--namespace prod-tenant-001 \
--session-lifetime-in-minutes 15 \
--authorized-resource-arns '["arn:aws:quicksight:us-east-1:XXXXXXXXXXX:dashboard/8cdc4fe3-5910-4ace-9d66-65c9246d1c94"]' \
--experience-configuration '{"Dashboard": {"InitialDashboardId": "8cdc4fe3-5910-4ace-9d66-65c9246d1c94"}}' \
--session-tags '[{"Key": "tenant_name", "Value": "tenant1"}]'

API の返り値として、ユーザーが一時的にアクセスできる埋め込みURLと、そのユーザーを識別するユーザー名が返却されます。

{
    "Status": 200,
    "EmbedUrl": "XXXXXXXXXXXXXX",
    "RequestId": "XXXXXXXX-7be1-4c10-917b-b4e17c8e0bf3",
    "AnonymousUserArn": "arn:aws:quicksight:us-east-1:XXXXXXXXXXXX:anonymousUser/prod-tenant-001/7c89d1f29fa74621aa1f3cf23d2809ed"
}

ユーザーは、この EmbedUrl にアクセスすることで一時的にダッシュボードを閲覧することができます。
上記で生成された埋め込み URL がアプリケーション上で読み込まれ、セッションが開始されると、AnonymousUserArn が CUR に記録されます。


SaaS で QuickSight を活用するためのポイント 〜設計から運用まで〜

匿名ユーザーの情報は、CUR 上で line_item_usage_type が QS-Reader-Capacity-xxx-UsageQS-Reader-Capacity-xxx-Extra といった名称の行に記載されています。

line_item_resource_id を見てみると、作成される匿名ユーザーのリソース ID (ARN) は次のような形式になることがわかります。
arn:aws:quicksight:[Region]:[AccountId]:anonymousUser/[Namespace]/[UserId]
消費セッション数は line_item_usage_amountに記載されています。一人の匿名ユーザーが複数セッションを利用したときは line_item_usage_amount の数が増えるのではなく、セッションの数だけ行が増えていることがわかります。

CUR をデータソースとしながらこのリソース ID に含まれる Namespace 情報を抽出することで、Namespace 毎の匿名ユーザー数や利用セッション数を計算することができます。

また、今回のソリューションでは SPICE の費用按分を実現することはできません。データセットが利用する SPICE 容量は CUR に連携されないためです。テナント毎に SPICE の利用量を把握する方法についてはこちらをご確認ください。

構築ステップ

次のステップに従ってソリューションの構築を行います。

  1. Cost and Usage Report を S3 へエクスポートする
  2. Athena 経由で Cost and Usage Report をクエリする
  3. QuickSight 上に、データを整形した Cost and Usage Report をロードする
  4. セッション利用率を可視化する

1. Cost and Usage Report を S3 へエクスポートする

CUR に備わるデータエクスポート機能を使うと、一度設定するだけで S3 へのデータ出力が自動化されます。
こちらの手順は Amazon QuickSight を使用した AWS Cost and Usage Reports の可視化(前編) | Amazon Web Services ブログAWS Cost and Usage Report | Blackbelt online seminar に詳しく解説されています。

まず、AWS マネジメントコンソールへログインし、「請求とコスト管理」ページに移動します。
左カラム中のコスト分析カテゴリ内にある「データエクスポート」をクリックします。
オレンジ色作成ボタンをクリックします。

エクスポートのタイプは「レガシー CUR エクスポート」を選択し、エクスポート名にわかりやすい名前をつけます。
今回は cur-legacy-export-for-athena としました。

エクスポートタイプは Athena 統合機能のある「レガシー CUR エクスポート」を選択します。

(補足)「標準データエクスポート」は Athena 統合機能が内蔵されていないため、自身でデータカタログの作成や Athena との連携が必要になります。もちろん、連携を行うことでこの先の分析を行うことも可能ですが、手順の簡単のため今回は利用しません。
また、「QuickSight を利用するコストと使用状況のダッシュボード」は事前定義されたダッシュボードを作成するため今回の用途には使えません。
「QuickSight を利用するコストと使用状況のダッシュボード」についてはこちらをご確認ください。

下にスクロールし、コンテンツのエクスポート設定を変更します。
その他のエクスポートコンテンツから「リソース ID を含める」にチェックを入れ、データの更新設定欄の「自動的に更新」にもチェックを入れます。
こうすることでリソース ID に含まれる匿名ユーザーの情報を取得でき、データの日次更新も自動で行われます。

下へスクロールし、データエクスポート配信オプションの設定を行います。
データの時間粒度はお好みの物を選びましょう。
レポートデータ統合から Amazon Athena を選択します。

下へスクロールし データエクスポートストレージ設定を行います。
データの配信先となる S3 バケットと、パスプレフィックスを指定します。
今回、S3 バケットを新規作成しました。バケット名は cur-legacy-export-bucket-wgmq 、S3 パスプレフィックスは athena-cur-data としました。
※) S3 バケット名は全世界でユニークである必要があるため、同じ名前を利用せずご自身で命名したものを利用してください。

下へスクロールし、レポートの作成をクリックします。

作成したレポートのステータスが 進行中 から ヘルシーになるまで待ちます。

これで CUR が S3 バケットに配信されるようになりました。

2. Athena 経由で Cost and Usage Report をクエリする

レガシー CUR エクスポート タイプによって CUR をエクスポートすると、エクスポート先の S3 に AWS CloudFormation のテンプレートファイルが出力されます。
このテンプレートを利用することで Athena や AWS Glue のセットアップを自動化することができ、手間なく Athena を使ったCUR データのクエリが行えます。
詳細な手順はこちらを参考にしてください。
AWS CloudFormation テンプレートを使用した Athena のセットアップ - AWS コストと使用状況レポート

CURの出力先に設定した S3 バケットへ移動します。先ほど設定した S3 パスプレフィックス内にレポート名のフォルダが作成されています。フォルダ内に crawler-cfn.yml が作成されています。これが CloudFormation のテンプレートファイルです。これをダウンロードします。

CloudFormation のページへ移動し、スタックの作成をクリックします。

既存のテンプレートを選択、テンプレートファイルのアップロードを選択し、先程ダウンロードした YAML ファイルをアップロードします。

「次へ」を押し、スタック名を決めた後、他のオプションはデフォルトのままで次を押していきスタックを作成します。
スタック名は CUR-Report-Analytics-Stack としました。
スタックの作成が開始したら、状態が CREATE_COMPLETEになるまで待ちます。

Athena からエクスポートした CUR データをクエリできることを確認します。
Athena のサービスページへ移動し、クエリエディタを開きます。
Athenaを初めて触る場合は、設定タブからクエリの保存バケットの設定を行います。
エディタを開き、athenacurcfn_[CUR エクスポート名] のデータベースを選択します。

レポート名と同名のテーブルをクエリし、データを読み取れることを確認します。
テーブル右側のドットをクリックし、テーブルをプレビューを選択すると、簡単な SQL クエリが発行されます。

image_17

発行されるSQLクエリ

SELECT * FROM "athenacurcfn_cur_legacy_export_for_athena"."cur_legacy_export_for_athena" limit 10;

クエリを実行し、データが出力されることを確認します。

これで Athena を使って CUR をクエリできるようになりました。
次の手順で使うため、FROM 句の内容(データベース(スキーマ名) と テーブル名) をメモしておきます。

3. QuickSight 上に、データを整形した Cost and Usage Report をロードする

QuickSight 上でデータセットを作成する前に、管理コンソール画面にて、S3 と Athena へのアクセス権限設定をします。
この操作には Admin ユーザーの権限が必要です。

QuickSight の管理ページへ移動し、セキュリティとアクセス許可から当該の S3 バケットと Athena へのアクセス許可を付与します。

権限の付与が完了したら、データセットの作成を行います。データセットページへ移動し、新しいデータセットをクリックします。

データソースは Athena を選択します。

データソース名は適宜設定し、データソースを作成をクリックします。

image_23

この画面からテーブルを指定してデータソースとすることもできますが、今回は SQL を書いてデータを加工したいため、カスタム SQL を使用をクリックします。

次の画面では何も入力せずに、データの編集/プレビューを選択します。

image_25

スキーマ編集ページに遷移します。カスタム SQL 名にわかりやすい名前をつけ、カスタム SQL 欄に次の SQL をペーストします。
FROM 句は自身の環境のテーブル名に合わせて変更してください。先ほどメモしたスキーマ名、テーブル名を利用します。

WITH cte_qs as (
SELECT
  bill_payer_account_id AS "Bill Payer Account ID",
  line_item_usage_account_id AS "Usage Account ID",
  bill_billing_period_start_date AS "Billing period",
  line_item_usage_start_date AS "Usage Date",
  line_item_resource_id AS "Resource ID",
  /* TAG NAME AS "tag", */
  CASE
    WHEN LOWER(line_item_resource_id) LIKE '%analysis%' THEN 'Analysis'
    WHEN LOWER(line_item_resource_id) LIKE '%dashboard%' THEN 'Dashboard'
    WHEN LOWER(line_item_resource_id) LIKE '%user%' THEN 'User'
    WHEN LOWER(line_item_resource_id) IS NULL THEN 'No Resource'
    ELSE 'other'
  END AS "Resource ID Category",
  line_item_usage_type AS "Line Item Usage type",
  line_item_line_item_description AS "Line Item Description",
  CASE
    WHEN LOWER(line_item_resource_id) LIKE '%:user/%'
      OR LOWER(line_item_resource_id) LIKE '%:anonymoususer/%'
    THEN SPLIT_PART(line_item_resource_id, '/', 2)
    ELSE NULL
  END AS "User namespace",
  CASE
    WHEN LOWER(line_item_resource_id) LIKE '%:user/%'
      OR LOWER(line_item_resource_id) LIKE '%:anonymoususer/%'
    THEN ELEMENT_AT(SPLIT(line_item_resource_id, '/'), -1)
    ELSE ''
  END AS "Username",
  CASE
    WHEN LOWER(line_item_resource_id) LIKE '%:user/%' THEN 'Authenticated User'
    WHEN LOWER(line_item_resource_id) LIKE '%:anonymoususer/%' THEN 'Anonymous User'
    ELSE ''
  END AS "User Type",
  CASE
    WHEN LOWER(line_item_resource_id) LIKE '%dashboard%'
      OR LOWER(line_item_resource_id) LIKE '%alert%'
    THEN ELEMENT_AT(SPLIT(line_item_resource_id, '/'), -1)
    ELSE NULL
  END AS "DashboardID",
  CASE
    WHEN LOWER(line_item_usage_type) LIKE '%spice%' THEN 'SPICE'
    WHEN LOWER(line_item_usage_type) LIKE '%alerts%' THEN 'QuickSight Alerts'
    WHEN LOWER(line_item_usage_type) LIKE '%-q%' THEN 'QuickSight Q'
    WHEN LOWER(line_item_usage_type) LIKE 'qs-user-enterprise%'
      OR LOWER(line_item_usage_type) = 'qs-user-standard' THEN 'Authors'
    WHEN LOWER(line_item_usage_type) LIKE 'qs-reader%' THEN 'Readers'
    WHEN LOWER(line_item_usage_type) LIKE '%spice' THEN 'SPICE'
    WHEN LOWER(line_item_usage_type) LIKE '%alerts%' THEN 'Alerts'
    WHEN LOWER(line_item_usage_type) LIKE '%qs-report%' THEN 'Reporting'
    ELSE line_item_usage_type
  END AS "QuickSightFeatures",
  line_item_usage_amount AS "usage amount",
  line_item_unblended_cost AS "unblended cost",
  line_item_blended_cost AS "blended cost"
FROM "AwsDataCatalog".[SchemeName].[TableName]
/* 例 FROM "AwsDataCatalog"."athenacurcfn_cur_legacy_export_for_athena"."cur_legacy_export_for_athena" */
WHERE line_item_product_code = 'AmazonQuickSight'
  AND line_item_line_item_type IN ('DiscountedUsage', 'Usage', 'BundledDiscount')
)
SELECT * FROM cte_qs
WHERE "User Type" = 'Anonymous User';

このクエリは 1) CUR に含まれる QuickSight のデータだけを整形し、2) その中でも特に匿名ユーザーに関する情報のみを抜き出す

二段構成になっています。
WITH 句で作成した cte_qs テーブルが 1) に相当し、最後の二行が 2) に相当します。
もし、QuickSight のコストに関する他の分析を行いたい場合は 2) の部分を書き換えることで必要な情報を入手できます。

「適用」を押し、データのプレビューが正しく表示されたことを確認して、画面上の「保存して視覚化」を押します。

4. セッション利用率を可視化する

作成したデータセットから分析を作成します。
セッションの利用率を表示するための計算フィールドを追加します。

image_28

項目名は セッション利用率 とし、計算式に percentOfTotal(sum({usage amount}),[{Billing period}]) と入力し保存を押します。

ピボットテーブルを追加し、行に「User namespace」、列に「Belling Period」値に「usage amount」「セッションの利用率」を配置し、値のフォーマットを整えるとテナント毎、請求月毎のセッション利用数とその割合が表示されたピボットテーブルが出来上がります。

セッション利用率の表示形式を%に変えています。
image_31

また、垂直積み上げ棒グラフを使って視覚的に割合を表示することも可能です。

まとめ

Cost and Usage Report と QuickSight を連携させることで、匿名ユーザーのリソース利用状況を把握し、公平な料金請求を実現できます。匿名ユーザーによる埋込みを利用する際の課題であった、マルチテナント環境下でのコスト按分を効率的に行えるソリューションとなっています。
ぜひお試しください!