こんにちは、香田です。
今回はAthena Partition Projectionを使用しNginx アクセスログをクエリする方法について紹介していきます。
AthenaよりクエリするNginx アクセスログは、ローカル環境でDockerを利用しデータを準備していく流れとなります。
Athena Partition Projectionについて
Athena Partition Projectionについて簡単に解説すると、
Partition Projectionが提供される前は、Athenaでパーティション分割されたデータを管理する場合、MSCK REPAIR TABLE
やALTER TABLE ADD PARTITION
を使用し、分割したいデータ毎にパーティションを追加する必要がありました。
Partition Projection
を使用することで、パーティションを手動で追加する必要がなく、パーティション管理を自動化することが可能となります。
パーティション分割については詳しくは下記を参考にしてみてください。
S3バケットの作成
はじめにAthenaで参照するNginx アクセスログ転送先のS3バケットを用意していきます。
aws s3 mb s3://<バケット名> --region ap-northeast-1
ローカル環境の作成
Nginx アクセスログを転送するためにFluentdを利用していきます。
FluentdにてS3へログ転送する為に独自のコンテナイメージを作成していきます。
作業ディレクトリを作成します。
mkdir athena-fluentd-nginx
cd athena-fluentd-nginx
Fluentd 用のディレクトリを作成します。
mkdir -p fluentd/etc
Dockerfileをfluend
配下へ作成します。
FROM fluent/fluentd:v1.12.0-debian-1.0
USER root
RUN ["gem", "install", "fluent-plugin-s3", "--no-document"]
RUN ["gem", "install", "fluent-plugin-rewrite-tag-filter", "--no-document"]
ARG AWS_ACCESS_KEY_ID
ARG AWS_SECRET_ACCESS_KEY
ARG AWS_DEFAULT_REGION
ARG S3_BUCKET_NAME
ARG S3_PREFIX
ENV AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
ENV AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
ENV AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}
ENV S3_BUCKET_NAME=${S3_BUCKET_NAME}
ENV S3_PREFIX=${S3_PREFIX}
USER fluent
Fluentdの設定ファイルをfluentd/etc/fluent.conf
へ作成します。
<source>
@type forward
port 24224
bind 0.0.0.0
</source>
<match nginx>
@type rewrite_tag_filter
<rule>
key source
pattern /^stdout$/
tag nginx.access_log
</rule>
<rule>
key source
pattern /^stderr$/
tag nginx.error_log
</rule>
</match>
<match nginx.access_log>
@type copy
# S3
<store>
@type s3
s3_region "#{ENV['AWS_DEFAULT_REGION']}"
s3_bucket "#{ENV['S3_BUCKET_NAME']}"
path "#{ENV['S3_PREFIX']}/nginx/access_log/dt=%Y%m%d/"
<format>
@type single_value
message_key log
</format>
<buffer tag,time>
@type file
flush_interval 60s
path /tmp/s3/access_log
timekey 1m
timekey_wait 1m
timekey_zone Asia/Tokyo
</buffer>
</store>
# Debug
<store>
@type stdout
<format>
@type single_value
message_key log
</format>
</store>
</match>
<match nginx.error_log>
@type copy
# S3
<store>
@type s3
s3_region "#{ENV['AWS_DEFAULT_REGION']}"
s3_bucket "#{ENV['S3_BUCKET_NAME']}"
path "#{ENV['S3_PREFIX']}/nginx/error_log/dt=%Y%m%d/"
<format>
@type single_value
message_key log
</format>
<buffer tag,time>
@type file
flush_interval 60s
path /tmp/s3/error_log
timekey 1m
timekey_wait 1m
timekey_zone Asia/Tokyo
</buffer>
</store>
# Debug
<store>
@type stdout
<format>
@type single_value
message_key log
</format>
</store>
</match>
下記のdocker-compose.ymlを作成します。
version: "3"
services:
fluentd:
build: ./fluentd
image: fluentd-custom:v1.12.0
container_name: fluentd
environment:
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
- AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}
- S3_PREFIX=${S3_PREFIX}
- S3_BUCKET_NAME=${S3_BUCKET_NAME}
volumes:
- ./fluentd/etc:/fluentd/etc
ports:
- "24224:24224"
- "24224:24224/udp"
nginx:
image: nginx:latest
container_name: nginx
ports:
- '8080:80'
logging:
driver: fluentd
options:
fluentd-address: "localhost:24224"
tag: nginx
depends_on:
- fluentd
各ファイル作成後、下記のような構成になっているはずです。
.
├── docker-compose.yml
└── fluentd
├── Dockerfile
└── etc
└── fluent.conf
Nginx アクセスログの転送確認
Compose ファイルで環境変数を参照させる為に、.env
ファイルを用意します。
AWS_ACCESS_KEY_ID=<AWS アクセスキー>
AWS_SECRET_ACCESS_KEY=<AWS シークレットキー>
AWS_DEFAULT_REGION=ap-northeast-1
S3_BUCKET_NAME=<S3 バケット名>
S3_PREFIX=logs
コンテナを起動します。
docker-compose up -d
Nginxへアクセスします。
for i in `seq 1 10`;
do
curl -s http://localhost:8080/index.html -o /dev/null -w '%{http_code}\n'
sleep 1
done
作成したS3バケットへログが転送されていることを確認します。
aws s3 ls s3://<S3 バケット名>/logs/nginx/access_log/ --recursive
下記のようにdt=yyyymmdd
形式でパーティション分割されていることが確認できるはずです。
2021-09-05 23:37:02 114 logs/nginx/access_log/dt=20210905/202109052335_0.gz
2021-09-05 23:38:02 125 logs/nginx/access_log/dt=20210905/202109052336_0.gz
2021-09-05 23:40:03 176 logs/nginx/access_log/dt=20210905/202109052338_0.gz
Partition Projectionを利用したテーブル作成
Athena コンソールへアクセスし、クエリエディタを使用しデータベースを作成します。
クエリエディタに下記を入力し、[Run Query]をクリックします。
CREATE DATABASE IF NOT EXISTS nginx;
次にPartition Projectionを利用したテーブルを作成していきます。
Partition Projectionの設定はTBLPROPERTIES
句に設定していきます。
クエリエディタに下記を入力し、[Run Query]をクリックします。
LOCATION
句で指定するS3バケット名は適宜指定してください。
CREATE EXTERNAL TABLE IF NOT EXISTS nginx.access_log (
`clientip` string COMMENT 'from deserializer',
`ident` string COMMENT 'from deserializer',
`auth` string COMMENT 'from deserializer',
`timestamp` string COMMENT 'from deserializer',
`verb` string COMMENT 'from deserializer',
`request` string COMMENT 'from deserializer',
`httpversion` string COMMENT 'from deserializer',
`response` string COMMENT 'from deserializer',
`bytes` string COMMENT 'from deserializer',
`referrer` string COMMENT 'from deserializer',
`agent` string COMMENT 'from deserializer',
`rawrequest` string COMMENT 'from deserializer')
PARTITIONED BY (
`dt` string)
ROW FORMAT SERDE
'com.amazonaws.glue.serde.GrokSerDe'
WITH SERDEPROPERTIES (
'input.format'='%{COMBINEDAPACHELOG}')
STORED AS INPUTFORMAT
'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
's3://<S3 バケット名>/logs/nginx/access_log'
TBLPROPERTIES (
'compressionType'='gzip',
'projection.dt.format'='yyyyMMdd',
'projection.dt.range'='NOW-5YEARS,NOW',
'projection.dt.type'='date',
'projection.enabled'='true')
下記のようなテーブルが作成されていれば成功です。
テーブル作成後、パーティション追加する必要なくテーブルに対してクエリ実行できるはずです。
SELECT * FROM nginx.access_log
WHERE dt > '20210901'
さいごに
Athena Partition Projectionを使用しNginx アクセスログをクエリする方法いかがでしたでしょうか?
Partition Projectionを利用することで、Athenaに対するクエリ実行時パーティション追加等を意識する必要がなくなるのは大きなメリットではないでしょうか。
Athena Partition Projectionを利用する際、本記事が参考になれば幸いでございます。
最後までご覧いただきありがとうございます。