Amazon Kinesis Firehoseを使ってRedshiftにデータを送ってみた #reinvent

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

Amazon Kinesis FirehoseとはリアルタイムストリーミングデータをKinesis経由でS3やRedshiftに保存できるサービスです。
以前、こちらの記事でFirehoseを使ってログをS3に送ってみました。
[新機能]Amazon Kinesis FirehoseでS3にデータを送ってみた #reinvent  

今回はRedshiftに送ってみます。

概要

ストリーミングデータは下記のフローでRedshiftに格納されます。
スクリーンショット 2015-10-19 16.50.43
図からわかる通り、データは一旦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ポートへのアクセスを許可します。
WS000016

Publicly Accessibleを有効にして、Redshiftクラスタを起動します。
WS000015

S3バケットの作成

データフローは
Firehoseデリバリストリーム -> S3バケット -> Redshiftクラスタ
なので、特別な理由がない限り全て同じリージョンに作るほうが良いでしょう。
今回はオレゴンリージョンにバケットを作ります。
WS000017

Firehoseデリバリストリームの作成

Firehoseデリバリストリームを作成します。
「Destination」でAmazon Redshiftを選択します。
WS000003
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"

次にバッファーサイズと圧縮、暗号化の有無を設定します。
今回はバッファーを小さめにして、圧縮、暗号化は無効にします。
WS000001

確認画面です。
WS000002

ログ送信部分の作成

まず、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バケットを見るとオブジェクトが作られていました。
WS000004

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秒程度でした。
WS000005

最後に

EC2上のログを簡単にRedshiftに送ることができました。
データの発生箇所とデータの保存場所を繋ぐFirehoseが出てきたことで、これまで以上にRedshiftを活用できるようになると思います。