Amazon Athena で CloudFront のアクセスログを集計する

eyecatch_athena

こんにちは、菊池です。

これまでのエントリで、ELBのログをAmazon Athenaで分析する方法を紹介しました。

今回は、CloudFrontのアクセスログをAmazon Athenaで分析してみます。

CloudFront とは

Amazon CloudFrontは、AWSが提供するコンテンツ配信サービス(CDN)です。ユーザからのアクセスを、世界中にあるエッジサーバを経由するよう誘導することで、高速なアクセスを提供します。また、エッジサーバにコンテンツをキャッシュすることで、オリジンサーバの負荷を低減することもできます。

CloudFrontのアクセスログ

CloudFrontのアクセスログは、ディストリビューションごとに指定したS3のバケットに保存されます。

ウェブディストリビューションとRTMPディストリビューションでログファイルの形式は異なりますので、今回はウェブシストリビューションを対象にします。

テーブル定義

ログファイルのフィールドを、ドキュメントを参考に以下の様にテーブルのカラムにマッピングします。

フィールド 説明
request_date イベントが発生した日付。yyyy-mm-dd形式。UTC。
request_time CloudFrontがリクエストへの対応を完了した時刻(UTC)。
x_edge_location リクエストを処理したエッジロケーション。3文字コードと割り当てられた数字で識別される。
sc_bytes CloudFront がリクエストに応答してビューワーに渡したデータの総バイト数
client_ip リクエストを送信したクライアントの IP アドレス。
cs_method リクエスト時のHTTPメソッド。
cs_host CloudFront ディストリビューションのドメイン名。
cs_uri_stem パスおよびオブジェクトを識別する URI 。
sc_status CloudFrontが応答したHTTP ステータスコード。応答前にクライアントが切断した場合は"000"を記録。
cs_referer リクエスト元のドメインの名前。
user_agent リクエスト内の User-Agent ヘッダーの値。
uri_query URI のクエリ文字列の部分 (ある場合)。ない場合には"-"を記録。
cookie リクエスト内の Cookie ヘッダー。ない場合には"-"を記録。
x_edge_result_type エッジロケーションへのCloudFrontのレスポンスの分類。例えば以下のようなものがある。

  • Hit:エッジキャッシュから応答
  • RefreshHit:キャッシュの有効期限がきれていたため、オリジンに最新バージョンを問い合わせ
  • Miss:リクエストをオリジンサーバに転送し、結果を応答
x_edge_request_id 要求を一意に識別する文字列。
x_host_header ビューワーによってこのリクエストの Host ヘッダーに追加された値。
cs_protocol リクエストのプロトコル。httpまたはhttps
cs_bytes リクエストに組み込まれたデータのバイト数
time_taken CloudFrontエッジサーバがリクエストを受け取ってから、レスポンスの最終バイトをエッジサーバーの出力キューに書き込むまでの秒数。
x_forwarded_for ビューワーがリクエストを送るのに HTTPプロキシやロードバランサーを使った場合、client_ipの値は、プロキシあるいはロードバランサーの IP アドレスとなる。その場合のリクエスト元のビューワーの IP アドレス。
ssl_protocol cs_protocolがhttpsの場合のSSLプロトコル。
ssl_cipher cs_protocolがhttpsの場合のSSL 暗号。
x_edge_response_result_type CloudFront がレスポンスをビューワーに返す直前に行った分類。x_edge_result_typeも参照。
cs_protocol_version リクエストで指定した HTTP バージョン。

これらを順にカラムとして定義します。Amazon Athena は、ログが複数のファイルの場合でも、同じフォルダに配置することで同じテーブル内のデータとしてクエリーを実行できます。

CREATE EXTERNAL TABLE IF NOT EXISTS cf_log (
    request_date STRING,
    request_time STRING,
    x_edge_location STRING,
    sc_bytes INT,
    client_ip STRING,
    cs_method STRING,
    cs_host STRING,
    cs_uri_stem STRING,
    sc_status STRING,
    cs_referer STRING,
    user_agent STRING,
    uri_query STRING,
    cookie STRING,
    x_edge_result_type STRING,
    x_edge_request_id STRING,
    x_host_header STRING,
    cs_protocol STRING,
    cs_bytes INT,
    time_taken DECIMAL(8,3),
    x_forwarded_for STRING,
    ssl_protocol STRING,
    ssl_cipher STRING,
    x_edge_response_result_type STRING,
    cs_protocol_version STRING
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
WITH SERDEPROPERTIES (
    'serialization.format' = '\t',
    'input.regex' = '\t'
)
LOCATION 's3://LOG_BUCKET_NAME/cf/'
TBLPROPERTIES ('has_encrypted_data'='false');

上記のDDLをテンプレートとして利用する場合、LOCATION に指定するクエリ対象のロフファイルを保存している S3バケット/フォルダ名を変更するだけで、再利用できます。

全てのレコードの全てのカラムデータが参照できることが確認できます。

SELECT * FROM sampledb."cf_log" limit 10;

athena-cf-001

CloudFront アクセスログの集計

実際にCloudFrontのアクセスログを集計する例を、いくつか紹介します。

エッジロケーションごとのアクセス数を集計

どの地域からのアクセス数が多いか、調べてみるのに使えるかと思います。

SELECT x_edge_location, count(*) AS num
FROM cf_log
WHERE request_date = '2017-08-15'
GROUP BY 1
ORDER BY 1;

athena-cf-002

クライアントIPごとにアクセス数を集計

クライアントのIPアドレスごとのアクセス数を集計します。BotやF5アタックなど、不適切なアクセスを仕掛けてくるIPを特定し、AWS WAFで遮断するなどの対応を想定しています。

SELECT client_ip, x_edge_location, count(*) AS num
FROM cf_log
WHERE request_date = '2017-08-15'
GROUP BY 1,2
ORDER BY 1;

athena-cf-003

パスごとにキャッシュ有無によるレスポンス時間を集計

アクセス先のパスごとに、平均のレスポンス時間を集計しています。キャッシュの状態により、ユーザへどの程度のレスポンス時間でサービスできているか確認できます。

SELECT cs_uri_stem, x_edge_result_type, avg(time_taken) AS num
FROM cf_log
WHERE request_date = '2017-08-15'
GROUP BY 1,2
ORDER BY 1;

athena-cf-004

最後に

以上です。

ELB(CLB/ALB)に続き、CloudFrontのアクセスログをAthenaで集計する手順を紹介しました。AWSでは、S3にログを出力するサービスが多いですが、Athenaを使うことでカジュアルに分析することができます。