多くの Cloudflare のお客様は、複数の顧客向けに SaaS(software-as-a-service)製品を運営しています。こうした企業にとって大きな関心事は、顧客ごとのコストを把握することと、顧客の行動をより広く理解することです。
顧客が使うすべての Web リクエストのデータを保持するのはコストがかかります。ページビューを顧客に紐づけるのも同様です。Cloudflare では、この問題を社内技術で解決しており、同じ技術が Analytics Engine として利用できます。
Analytics Engine は Cloudflare Workers での利用を想定しています。すでに Cloudflare Workers でリクエストを処理している場合、数行のコードで Analytics Engine にデータを送り始められます。
[...]
// This examples assumes you give a unique ID to each of your SaaS customers, and the Worker has
// assigned it to the variable named `customer_id`
const { pathname } = new URL(request.url);
env.USAGE_INDEXED_BY_CUSTOMER_ID.writeDataPoint({
"indexes": [customer_id],
"blobs": [pathname]
});SaaS の顧客アクティビティは、指数的なパターンになることが多いです。ある顧客は毎秒 1 億リクエストを送り、別の顧客は 1 日 100 リクエストしか送らないことがあります。すべてのデータをまとめてサンプリングすると、大口顧客の利用が原因で、小規模顧客のデータがゼロまでサンプリングされることがあります。Analytics Engine ではこれを防げます。上記のサンプルコードでは、顧客の一意な ID をインデックスとして渡しているため、Analytics Engine は顧客ごとのアクティビティを個別にサンプリングします。
顧客データは、Grafana(可視化)または JSON(独自ツール向け)で確認できます。詳しい手順は Analytics Engine ドキュメントのほかのページを参照してください。
すべてのエンドポイントにおける顧客の利用状況を確認します。
SELECT
index1 AS customer_id,
sum(_sample_interval) AS count
FROM
usage_indexed_by_customer_id
GROUP BY customer_idGrafana で実行すると、このクエリは各顧客の利用状況をまとめたグラフを返します。sum(_sample_interval) はサンプリングを補正します。詳細はほかの Analytics Engine ドキュメントを参照してください。このクエリで「どの顧客が最も活発か」が分かります。
上記の writeDataPoint 呼び出しは、エンドポイント名を書き込みます。そうすると、顧客のアクティビティをエンドポイント別に分解できます。
SELECT
index1 AS customer_id,
blob1 AS request_endpoint,
sum(_sample_interval) AS count
FROM
usage_indexed_by_customer_id
GROUP BY customer_id, request_endpoint顧客ごとにどのエンドポイントを使っているかが分かります。ビジネス面(顧客ニーズの把握など)にも、エンジニアがアクティビティと振る舞いを見る可観測性にも役立ちます。
Analytics Engine は、利用量の信頼性の高い近似値をもとに顧客へ課金するのに使えます。近似をよくするには、請求を作るときに顧客ごとに 1 件のクエリを実行することを推奨します。複数の顧客を一度にクエリするより、サンプリングが少なくなることがあります。
SELECT
index1 AS customer_id,
blob1 AS request_endpoint,
sum(_sample_interval) AS usage_count
FROM
usage_indexed_by_customer_id
WHERE
customer_id = 'substitute_customer_id_here'
AND timestamp >= toDateTime('2023-03-01 00:00:00')
AND timestamp < toDateTime('2023-04-01 00:00:00')
GROUP BY customer_id, request_endpoint月末に顧客ごとにこのクエリを 1 回実行すれば、請求書を作るデータが得られます。これは一例です。実際の課金方法に合わせて調整してください。
請求書を作るときは、日ごとのコストも載せたいことが多いです。次のクエリは、利用状況を日別に分解します。
SELECT
index1 AS customer_id,
toStartOfInterval(timestamp, INTERVAL '1' DAY) AS date,
blob1 AS request_endpoint,
sum(_sample_interval) AS request_count
FROM
usage_indexed_by_customer_id
WHERE
customer_id = 'x'
AND timestamp >= toDateTime('2023-03-01 00:00:00')
AND timestamp < toDateTime('2023-04-01 00:00:00')
GROUP BY customer_id, date, request_endpoint上記の利用状況クエリを課金方法に合わせて調整し、バックエンドで実行して、返ってきたデータから顧客の請求額を計算してください。