Embulkと戯れる

記事タイトルとURLをコピーする

飛行機代を省略したのをいいことに、またIYHしたカメラマンの竹永です。
次の目標は三脚です。次の次の目標は洗濯機でしょうか。

前回前々回とFluentdを扱いましたが、S3に入っていくデータは貯めるだけで何にも使っていませんでした。

今回は、色々なところにあるデータを色々なところへ一気にガガッと突っ込めるEmbulkをご紹介します。

今日のレシピ

どんどん足されていった構成図ですが、今回は下図のような構成を作っていきます。
RedshiftとEmbulkが増えました。EmbulkはどこかのEC2にインストールします。
レシピ

どこかのEC2で使うソフトウェアのバージョンは下記の通り。

  • amzn-ami-hvm-2015.09.0.x86_64-gp2 (ami-9a2fb89a)
  • Java 1.7.0_91
  • Embulk 0.7.9

Embulkってなにもの

つぶらな瞳のシャチがかわいいバルクデータローダーです。
Fluentdのバルク(バッチ)版と考えるのが一番簡単です。

Embulkは、色々なところにあるデータを一気に読み込んで、色々な格納先に一気に流し込みます。
自分でやるととてつもなく面倒くさい、エラー処理・リジューム・クレンジング・繰り返し処理を全部やってくれます

「俺は意地でもFluentdだけでデータを転送するんだ!」という方は、中の人が用意してくれたstdinプラグインを使うと幸せかもしれません。
Fluentdはもともとバルクロードするツールではないので、おすすめはしません。おすすめはしません。大切なことなので2回(ry

ロゴがかわいいソフトウェアに悪いソフトウェアなんてありません。きっとそうだ。

なんでRedshift?

Redshiftが居るだけで、一般的なBIツールでデータにアクセスしやすくなります。
というのは建前で、Redshiftって書くだけで誰かしらが釣れそうな気がしたためです。

Redshiftにデータを挿入する一番簡単でシンプルな方法としては、Fluentdプラグインを使ったデータ挿入です。

しかし、Fluentdを分散していくとRedshiftストレージ内に入っているデータのソート順がカオスになる可能性があり、VACUUM祭りを開催しなければならない可能性もでてきます。

VACUUMをサボるために、意地でも時系列順でデータを挿入したかったので、Embulkをつかって綺麗かつ一気にデータを流し込みます。

インストール

公式ドキュメントのQuick Startに載っているコマンドを黒い画面にコピペします。

実際にコピペした時の様子は下記の通り。

$ curl --create-dirs -o ~/.embulk/bin/embulk -L "http://dl.embulk.org/embulk-latest.jar"
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0
100 37.4M  100 37.4M    0     0  2157k      0  0:00:17  0:00:17 --:--:-- 4287k

$ chmod +x ~/.embulk/bin/embulk
$ echo 'export PATH="$HOME/.embulk/bin:$PATH"' >> ~/.bashrc
$ source ~/.bashrc

バージョンは下記のコマンドで確認できます。

$ embulk --version
embulk 0.7.9

次に必要なプラグインをインストールします。
S3からJSONL形式のファイルを読み込んでRedshiftへロードしたいので、下記3つのプラグインをインストールする必要があります。

インストールするコマンドは下記の通りです。

$ embulk gem install embulk-input-s3
$ embulk gem install embulk-parser-jsonl
$ embulk gem install embulk-output-redshift

あっさり終わったので設定します。

設定ファイルづくり

ここから本気を出す必要があります。

Embulkはやりたいこと毎に、YAML形式の設定ファイルを作ってそれを読み込ませます。
今回はEmbulkのドキュメントとかプラグインのドキュメントドキュメントドキュメントを使って、下記のような設定ファイルを作りました。

# s3-to-redshift.yml
in:
  type: s3
  bucket: example-bucket
  path_prefix: access-logs/
  endpoint: s3-ap-northeast-1.amazonaws.com
  access_key_id: AKIAACCESSKEYHOGEFUGA
  secret_access_key: hereissecretKey/hogefugahungaaaaaaaa

out:
  type: redshift
  host: example-redshift.abcdefghijklmn.ap-northeast-1.redshift.amazonaws.com
  user: example
  password: userpassword
  database: exampledb
  table: www_access_log
  access_key_id: AKIAACCESSKEYHOGEFUGA
  secret_access_key: hereissecretKey/hogefugahungaaaaaaaa
  mode: insert
  iam_user_name: exampleiamuser
  s3_bucket: example-bucket
  s3_key_prefix: embulk-redshift-tmp/

書くのが面倒な項目があったので色々と必須パラメーターが抜けて落ちており、このままでは使えたもんじゃありません。

しかし、Embulkは適当に書いた設定ファイルと実際に読み込んだデータを元に、適切な設定を推測してくれます。シャチえらい。

実際に推測させるときは下記のようなコマンドを実行します。 -g jsonl は推測に使うプラグインをカンマ区切りで指定します。たぶん。

$ embulk guess -g jsonl s3-to-redshift.yml
2015-11-16 09:07:58.043 +0000: Embulk v0.7.9
2015-11-16 09:07:59.315 +0000 [INFO] (guess): Loaded plugin embulk-input-s3 (0.2.3)
2015-11-16 09:08:00.519 +0000 [INFO] (guess): Loaded plugin embulk/guess/gzip from a load path
2015-11-16 09:08:00.532 +0000 [INFO] (guess): Loaded plugin embulk/guess/csv from a load path
2015-11-16 09:08:00.548 +0000 [INFO] (guess): Loaded plugin embulk-parser-jsonl (0.0.1)
in:
  type: s3
  bucket: example-bucket
  path_prefix: access-logs/
  endpoint: s3-ap-northeast-1.amazonaws.com
  access_key_id: AKIAACCESSKEYHOGEFUGA
  secret_access_key: hereissecretKey/hogefugahungaaaaaaaa
  decoders:
  - {type: gzip}
  parser:
    charset: UTF-8
    newline: CRLF
    type: jsonl
    schema:
    - {name: host, type: string}
    - {name: user, type: string}
    - {name: method, type: string}
    - {name: path, type: string}
    - {name: code, type: string}
    - {name: size, type: string}
    - {name: referer, type: string}
    - {name: agent, type: string}
    - {name: time, type: string}
out: {type: redshift, host: 'example-redshift.abcdefghijklmn.ap-northeast-1.redshift.amazonaws.com',
  user: example, password: userpassword, database: exampledb, table: www_access_log, access_key_id: AKIAACCESSKEYHOGEFUGA,
  secret_access_key: hereissecretKey/hogefugahungaaaaaaaa, mode: insert, s3_bucket: example-bucket,
  s3-key-prefix: embulk-redshift-tmp/}
Use -o PATH option to write the guessed config file to a file.

一番下の行で怒られているように、推測したらとっととファイルに書き込むのが良いようです。
が、僕は僕のスタイルで行きます。

Redshiftの設定部分が残念なことになっていますね。
ドジっ子シャチかわいい。

さて、推測結果を元に設定ファイルを書き換えます。
in をコピペして schema に適切な型を書くだけで完成です。

in:
  type: s3
  bucket: example-bucket
  path_prefix: access-logs/
  endpoint: s3-ap-northeast-1.amazonaws.com
  access_key_id: AKIAACCESSKEYHOGEFUGA
  secret_access_key: secretKeyhogefugahungaaaaaaaa
  decoders:
  - {type: gzip}
  parser:
    type: jsonl
    charset: UTF-8
    newline: CRLF
    schema:
    - {name: host, type: string}
    - {name: user, type: string}
    - {name: method, type: string}
    - {name: path, type: string}
    - {name: code, type: long}
    - {name: size, type: long}
    - {name: referer, type: string}
    - {name: agent, type: string}
    - {name: time, type: timestamp, time_format: '%Y-%m-%dT%H:%M:%S%z'}

out:
  type: redshift
  host: example-redshift.abcdefghijklmn.ap-northeast-1.redshift.amazonaws.com
  user: example
  password: userpassword
  database: exampledb
  table: www_access_log
  access_key_id: AKIAACCESSKEYHOGEFUGA
  secret_access_key: hereissecretKey/hogefugahungaaaaaaaa
  mode: insert
  iam_user_name: example-iamuser
  s3_bucket: example-bucket
  s3_key_prefix: embulk-redshift-tmp/

Redshiftのテーブルを作る

Embulkが推測してくれたおかげで、Redshiftのテーブルも作りやすくなりました。
と、いうことでRedshift上にテーブルを作成します。

今回作ったのは下記のようなテーブル。
分散キーのことは考えていなかったり、列圧縮の指定をしてなかったりとかなり適当です。

CREATE TABLE www_access_log(
  host    VARCHAR(255),
  "user"  VARCHAR(30),
  method  VARCHAR(10),
  path    VARCHAR(MAX),
  code    SMALLINT,
  size    BIGINT,
  referer VARCHAR(MAX),
  agent   VARCHAR(MAX),
  time    TIMESTAMP
) SORTKEY(date);

なお、設定ファイルに書かれた列名とテーブルの列名が一致していないと、その列は空白になります。

試しに動かす

指定した設定ファイルが正しく動くかどうかを試すことができます。
出力テストは行わないので注意。

$ embulk preview s3-to-redshift.yml
2015-11-16 09:32:58.238 +0000: Embulk v0.7.9
2015-11-16 09:32:59.474 +0000 [INFO] (preview): Loaded plugin embulk-input-s3 (0.2.3)
2015-11-16 09:32:59.514 +0000 [INFO] (preview): Loaded plugin embulk-parser-jsonl (0.0.1)
+-----------------+-------------+---------------+--------
|     host:string | user:string | method:string | (ry
+-----------------+-------------+---------------+--------
| 123.456.789.012 |           - |           GET | …
| 123.456.789.012 |           - |           GET | …
| 123.456.789.012 |           - |           GET | …
| 123.456.789.012 |           - |           GET | …
| 123.456.789.012 |           - |           GET | …
| 123.456.789.012 |           - |           GET | …
以下省略。

10秒以上応答が返ってこない時や、Error: No input records to preview と怒られるときは、何か間違えている可能性が大です。
回線がよほど遅くなければ、数秒でプレビューが表示されます。

よくやる間違いとしては、日付のフォーマットを間違えていたり、指定を忘れていたり、キャスト出来ない型を指定していたりなどがあります。
プラグインがデバッグログを出力しない場合、 -l debug を指定してもEmbulkが真面目に仕事をしている姿しか見えてこないので、気長に問題調査しましょう。

Redshiftにいれる

Previewができればほぼ完成です。
設定ファイルのバックアップを取って、Redshiftにガガッといれましょう。

$ cp s3-to-redshift.yml s3-to-redshift.yml.orig
$ embulk run s3-to-redshift.yml -o s3-to-redshift.yml

-o で設定ファイルを書き出しているのは、最終読み込み位置を設定ファイルに記録する必要があるためです。
今回の設定だと、Redshiftへの書き込みが成功した時点で設定ファイルが更新されるので、同じファイルを2回書き込んだりすることが無くなります。

定期的に実行したい場合は上記の embulk run コマンドをcronに仕込めば勝手に動くはずです。

おわり

Redshiftに入れさえすれば、あとは煮るなり焼くなり好きにできます。 data image

…最初の目的がデータ分析だったのを今思い出しました。やばい。