この記事は、 ニフティグループ Advent Calendar 2024 23日目の記事です。 はじめに こんにちは、新卒1年目の後藤です。 今回は、S3内にあるALBのアクセスログをAthenaで確認する方法について、記載していこうと思います。 Amazon Athenaとは クラウドインフラの運用において、ログ分析は不可欠です。 AWSでは、多くのサービスがログをAmazon CloudWatchとAmazon S3で保存しています。 しかし、蓄積された大量のログデータを効率的に分析することは、いずれも困難です。 ここで登場するのがAmazon Athenaです。 Amazon Athenaは、標準SQLを使用してS3のデータを直接クエリできるサーバーレスの対話型クエリサービスです。 Athenaを使用することで、複雑なインフラ設定なしに、S3の大規模なログデータを効率的に分析できます。 環境設定 Athenaを使用するには、以下のAWSサービスへのアクセス権限が必要です: Amazon S3 S3バケットへの読み取り権限 Amazon Athena Athenaクエリの実行権限 S3バケットの設定 1. ログを保存するS3バケットを作成または確認します。 2. バケットポリシーを適切に設定します。 Athenaからの読み取り権限を許可する { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "athena.amazonaws.com" }, "Action": [ "s3:GetBucketLocation", "s3:GetObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::your-bucket-name", "arn:aws:s3:::your-bucket-name/*" ] } ] } 必要に応じて、特定のIAMロールやユーザーからのアクセスのみを許可する { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::123456789012:role/YourRoleName" }, "Action": [ "s3:GetObject", "s3:PutObject" ], "Resource": [ "arn:aws:s3:::your-bucket-name/*" ] } ] } 注意: 上記のポリシーは一例なので、実際の環境に合わせて適切に調整してください。 3. 必要な権限を付与します。 s3:GetBucketLocation – バケットの場所を取得する権限 s3:GetObject – オブジェクトを読み取る権限 s3:ListBucket – バケット内のオブジェクトを一覧表示する権限 s3:PutObject – クエリ結果を保存する権限(結果を S3 に保存する場合) 設定 ログを保存するS3バケットを指定 Location of query result でログを保存するS3バケットを指定します。 Browse S3で選択することも可能です。 データベースの作成 以下コマンドをクエリで実行します。 CREATE DATABASE your_database; [Run] (実行) をクリックするか、 Ctrl+ENTER キーを押します。 左側の [Database] (データベース) リストから、現在のデータベースとして your_database を選択します。 テーブルの作成 今回はALBのアクセスログ用のテーブルを作成します。 使用したいログやデータに合わせて変更してください。 作成したデータベース( your_database )を選択 クエリで以下コマンドを実行 CREATE EXTERNAL TABLE IF NOT EXISTS alb_access_logs ( type string, time string, elb string, client_ip string, client_port int, target_ip string, target_port int, request_processing_time double, target_processing_time double, response_processing_time double, elb_status_code int, target_status_code string, received_bytes bigint, sent_bytes bigint, request_verb string, request_url string, request_proto string, user_agent string, ssl_cipher string, ssl_protocol string, target_group_arn string, trace_id string, domain_name string, chosen_cert_arn string, matched_rule_priority string, request_creation_time string, actions_executed string, redirect_url string, lambda_error_reason string, target_port_list string, target_status_code_list string, classification string, classification_reason string, conn_trace_id string ) PARTITIONED BY ( year string, month string, day string ) ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe' WITH SERDEPROPERTIES ( 'serialization.format' = '1', 'input.regex' = '([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*):([0-9]*) ([^ ]*)[:-]([0-9]*) ([-.0-9]*) ([-.0-9]*) ([-.0-9]*) (|[-0-9]*) (-|[-0-9]*) ([-0-9]*) ([-0-9]*) \\"([^ ]*) (.*) (- |[^ ]*)\\" \\"([^\\"]*)\\" ([A-Z0-9-_]+) ([A-Za-z0-9.-]*) ([^ ]*) \\"([^\\"]*)\\" \\"([^\\"]*)\\" \\"([^\\"]*)\\" ([-.0-9]*) ([^ ]*) \\"([^\\"]*)\\" \\"([^\\"]*)\\" \\"([^ ]*)\\" \\"([^\\\\s]+?)\\" \\"([^\\\\s]+)\\" \\"([^ ]*)\\" \\"([^ ]*)\\" ?([^ ]*)?' ) LOCATION 's3://your-bucket-name/access-log-folder-path/' TBLPROPERTIES ( 'projection.enabled'='true', 'projection.year.type' = 'integer', 'projection.year.range' = '2024,2050', 'projection.year.interval' = '1', 'projection.month.type' = 'integer', 'projection.month.digits'='2', 'projection.month.range' = '1,12', 'projection.day.type' = 'integer', 'projection.day.digits'='2', 'projection.day.range' = '1,31', 'storage.location.template' = 's3://your-bucket-name/access-log-folder-path/year=${year}/month=${month}/day=${day}' ); [Run] (実行) を選択。 テーブル alb_access_logs が作成され、 your_database データベースの [ Tables ] (テーブル) リストに表示されます。 公式から追加した箇所の説明 PARTITIONED BYの説明 PARTITIONED BY テーブルをパーテーション化することを宣言しています。 パーテーション化は、大規模なデータセットを小さな、管理しやすい部分に分割することです。 year string , month string , day string パーテーションキーとして使用され、それぞれがstring型で定義されています。年、月、日の順で階層的にパーティションが作成されます。 TBLPROPERTIESの説明 'projection.enabled'='true' Partition Projectionを有効にします。クエリ時にPartitionを動的に生成できます。 'projection.year.type' = 'integer' , 'projection.month.type' = 'integer' , 'projection.day.type' = 'integer' 年、月、日のPartitionがそれぞれ整数型であることを指定します。 'projection.year.range' = '2024,2050' 年の範囲を2024年から2050年までと指定します。 'projection.year.interval' = '1' 年のPartitionが1年ごとに増加することを指定します。 'projection.month.digits'='2' , 'projection.day.digits'='2' 月と日のPartitionが2桁の数字で表されることを指定します。 'projection.month.range' = '1,12' 月のPartitionが1から12までの範囲であることを指定します。 'projection.day.range' = '1,31' 日のパーティションが1から31までの範囲であることを指定します。 'storage.location.template' S3内のデータの実際の格納場所のテンプレートを指定します。 ${year} , ${month} , ${day} はそれぞれ年、月、日の値に置き換えられます。 データの取得 テーブルを作成したら、実際にデータを取得してみます。 基本的なクエリ 最新のログエントリを10件取得する: SELECT * FROM alb_access_logs WHERE year = 2024 AND month = 12 AND day = 12 LIMIT 10; コンソールの下に結果が表示されるので確認します。 パフォーマンスとコスト最適化 Athenaにデータを設定する際の最適化 1. パーテーションの活用 適切なパーティションにより、スキャンするデータ量を減らし、クエリ速度を向上させ、コストを削減することが可能です。 今回はs3://~/YYYY/MM/DDのようにデータが保存されているので、以下のように PARTITIONED BY でパーテーションを設定することが可能です。 PARTITIONED BY ( year string, month string, day string ) 2. 圧縮の使用 ログファイルをgzipなどで圧縮することで、ストレージコストとクエリ時間を削減できます。 gzipに圧縮した際は、テーブル定義の TBLPROPERTIES 内に 'compression.type'='gzip' を追加することを忘れないようにしましょう。 実際に検索する際の最適化 必要な列のみを選択 SELECT * の使用は避け、必要な列のみを指定します。 例: SELECT time, elb_status_code, request_url FROM alb_access_logs WHERE ... LIMIT句の使用 大量のデータを扱う場合、LIMIT句を使用して結果セットを制限します。 例: SELECT * FROM alb_access_logs LIMIT 100; これらの最適化技術を適用することで、Athenaの使用をより効率的にし、コストを抑えることができます。定期的にクエリのパフォーマンスとコストを監視し、必要に応じて調整を行うことが重要です。 まとめ Amazon Athenaを使用してS3のログを分析することで、大規模なデータセットに対して効率的かつ柔軟なクエリが可能になります。 主要なポイントは以下の通りです: Athenaの基本設定 クエリ結果の保存場所の指定 データベースとテーブルの作成 テーブル設計の重要性 適切なカラム定義 パーティショニングの活用 効率的なクエリ実行 基本的なSQLクエリの構造 パーティションを利用したデータフィルタリング パフォーマンスとコスト最適化 必要な列のみの選択 LIMIT句の使用 データの圧縮 Athenaを活用することで、複雑なインフラストラクチャを管理することなく、S3に保存されたログデータから迅速に得ることができます。 パフォーマンスとコストの最適化テクニックを適用することで、より効率的にデータ分析を行うことが可能です。 最後に、常にAWSの ベストプラクティス と セキュリティガイドライン に従い、コストとパフォーマンスのバランスを取りながら、Athenaを活用しましょう。 参考文献 https://docs.aws.amazon.com/ja_jp/athena/latest/ug/what-is.html https://docs.aws.amazon.com/athena/latest/ug/create-alb-access-logs-table.html 次の記事もお楽しみに!