Amazon Kinesis Firehoseを使ってRedshiftにデータを送ってみた #reinvent
はじめに
Amazon Kinesis FirehoseとはリアルタイムストリーミングデータをKinesis経由でS3やRedshiftに保存できるサービスです。 以前、こちらの記事でFirehoseを使ってログをS3に送ってみました。 [新機能]Amazon Kinesis FirehoseでS3にデータを送ってみた #reinvent
今回はRedshiftに送ってみます。
概要
ストリーミングデータは下記のフローでRedshiftに格納されます。 図からわかる通り、データは一旦S3に保存され、そのあとRedshiftにロードされます。 S3にデータを保存するのも、Redshiftへのロードを実行するのもFirehoseサービスです。 したがって、Firehoseには下記の権限が必要です。
- S3へのデータ保存権限(IAM Role Policy)
- Redshiftへのアクセス(Redshiftのセキュリティグループ)
- Redshiftへのログイン&データロード(Redshiftユーザ)
S3バケットに保存されるオブジェクトのサイズはFirehoseのバッファーサイズやバッファー間隔で調整できます。 ストリームの流量が大きい場合はRedshiftへのロード効率を上げるためにバッファーを大きくするほうが良いでしょう。 流量がそれほどでもない場合は、バッファーを小さめにして、よりリアルタイムに近い形でロードされるようにしたほうが良いでしょう。
では、実際に構築していきます。
手順
今回はApacheのアクセスログをKinesis Agentを使ってFirehoseに送ります。 Redshiftクラスタ、S3バケット、Firehoseデリバリストリーム、Apacheが動くEC2インスタンスの順に構築していきます。 リージョンはオレゴンを利用しました。
Redshiftクラスタの作成
Firehoseがアクセスできるように、「Publicly Accessible」を有効にし、セキュリティグループでFirehoseのIPアドレスからRedshift用ポートへのアクセスを許可します。 Firehoseのアクセス元IPは下記ページに記載されています。 Amazon Redshift and Amazon VPC Access 今回はオレゴンリージョンを使うので、52.89.255.224/27からのRedshiftポートへのアクセスを許可します。
Publicly Accessibleを有効にして、Redshiftクラスタを起動します。
S3バケットの作成
データフローは Firehoseデリバリストリーム -> S3バケット -> Redshiftクラスタ なので、特別な理由がない限り全て同じリージョンに作るほうが良いでしょう。 今回はオレゴンリージョンにバケットを作ります。
Firehoseデリバリストリームの作成
Firehoseデリバリストリームを作成します。 「Destination」でAmazon Redshiftを選択します。 S3バケットは先ほど作成したバッファ用バケットを選択し、このバケットでのオブジェクト操作権限を持ったIAM Roleをデリバリストリームに付与します。 IAM Roleがない場合はその場で作成できます。
Redshiftクラスタとデータロード先のデータベース名、テーブル名も指定します。 後ほど、access_logというテーブルを作り、そこにApacheのログを送る想定です。
ユーザ名とパスワードはRedshiftクラスタへのINSERT権限のあるユーザのものを指定してください。
「Redshift COPY options」でCOPYコマンドの追加オプションを指定します。 Firehoseが発行するロードコマンドは下記のようなものです。
COPY * FROM [S3オブジェクト名] CREDENTIALS "[IAMクレデンシャル]" MANIFEST
IAMクレデンシャルはFirehoseが自動で入力してくれるのですが、データの区切り文字や圧縮方式、S3バケットのリージョンは明示的に指定してやる必要があります。 今回はタブ区切り、圧縮なし、バケットはオレゴンリージョンなので、「Redshift COPY options」で次のように指定しています。
DELIMITER "\t" REGION "us-west-2"
次にバッファーサイズと圧縮、暗号化の有無を設定します。 今回はバッファーを小さめにして、圧縮、暗号化は無効にします。
ログ送信部分の作成
まず、Kinesisへのレコード登録権限を付与したEC2インスタンスを立ち上げます。
最初にRedshiftにテーブルを作っておきましょう。
[ec2-user@demo ~]$ sudo yum -y install postgresql [ec2-user@demo ~]$ psql -U root -h demo-redshift.xxxxxxxxxx.us-west-2.redshift.amazonaws.com -p 5439 -d dev Password for user root: psql (9.2.13, server 8.0.2) WARNING: psql version 9.2, server version 8.0. Some psql features might not work. SSL connection (cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256) Type "help" for help. dev=# CREATE TABLE access_log( dev(# remote_host VARCHAR, dev(# remote_log VARCHAR, dev(# remote_user VARCHAR, dev(# request_time VARCHAR, dev(# request_first_row VARCHAR, dev(# http_status INT, dev(# response_bytes VARCHAR, dev(# referer VARCHAR, dev(# user_agent VARCHAR dev(# ); CREATE TABLE dev=# \q
続いて、Kinesis Stream AgentとApacheをインストール、設定していきます。
[ec2-user@demo ~]$ sudo yum -y install aws-kinesis-agent httpd
Kinesis Agentの設定は下記のようにしました。
[ec2-user@demo ~]$ cat /etc/aws-kinesis/agent.json { "cloudwatch.emitMetrics": true, "cloudwatch.endpoint": "https://monitoring.us-west-2.amazonaws.com", "firehose.endpoint": "https://firehose.us-west-2.amazonaws.com", "flows": [ { "filePattern": "/var/log/httpd/access_log", "deliveryStream": "StreamToRedshift", "initialPosition": "START_OF_FILE" } ] }
Apacheのアクセスログを最初から読み込むようにしています。 アクセスログをタブ区切りにするため、Apacheの設定を変更します。
[ec2-user@demo ~]$ diff -u /etc/httpd/conf/httpd.conf{.orig,} --- /etc/httpd/conf/httpd.conf.orig 2015-10-20 11:30:11.230242715 +0000 +++ /etc/httpd/conf/httpd.conf 2015-10-20 11:30:42.226513287 +0000 @@ -495,7 +495,7 @@ # The following directives define some format nicknames for use with # a CustomLog directive (see below). # -LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined +LogFormat "%h\t%l\t%u\t%t\t\"%r\"\t%>s\t%b\t\"%{Referer}i\"\t\"%{User-Agent}i\"" combined LogFormat "%h %l %u %t \"%r\" %>s %b" common LogFormat "%{Referer}i -> %U" referer LogFormat "%{User-agent}i" agent
これでログ送信側の設定は完了です。簡単ですね。 それでは動作確認してみます。
動作確認
ApacheとKinesis Agentを起動し、
[ec2-user@demo ~]$ [ec2-user@demo ~]$ sudo service aws-kinesis-agent start aws-kinesis-agent startup [ OK ] [ec2-user@demo ~]$ sudo service httpd start Starting httpd: httpd: apr_sockaddr_info_get() failed for ip-172-16-1-59 httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName [ OK ]
abで1000回ほどアクセスしてみます。
[ec2-user@demo ~]$ ab -n 1000 -c 10 localhost/
バッファー期間は60秒にしていたので、60秒ほど待ってからS3バケットを見るとオブジェクトが作られていました。
Redshiftのテーブルも確認しましょう。 1000件レコードが登録されています。
dev=# select count(*) from access_log; count ------- 1000 (1 row) dev=# select * from access_log limit 3; remote_host | remote_log | remote_user | request_time | request_first_row | http_status | response_byte s | referer | user_agent -------------+------------+-------------+------------------------------+-------------------+-------------+----------------+---------+------------------- 127.0.0.1 | - | - | [20/Oct/2015:15:29:38 +0000] | "GET / HTTP/1.0" | 403 | 3839 | "-" | "ApacheBench/2.3" 127.0.0.1 | - | - | [20/Oct/2015:15:29:38 +0000] | "GET / HTTP/1.0" | 403 | 3839 | "-" | "ApacheBench/2.3" 127.0.0.1 | - | - | [20/Oct/2015:15:29:38 +0000] | "GET / HTTP/1.0" | 403 | 3839 | "-" | "ApacheBench/2.3" (3 rows)
Redshiftのロード履歴を確認したところ、ロードにかかった時間は1秒程度でした。
最後に
EC2上のログを簡単にRedshiftに送ることができました。 データの発生箇所とデータの保存場所を繋ぐFirehoseが出てきたことで、これまで以上にRedshiftを活用できるようになると思います。