今日もプログラミング

IT技術とかプログラミングのこととか特にJavaを中心に書いていきます

embulk-output-redshiftのパフォーマンスを計測してみた

embulk-output-redshiftを使えばテキストファイルを簡単にAmazon Redshiftにインポートできる。

だが、やはり気になるのはパフォーマンスだ。

という訳で、embulk-output-redshiftのパフォーマンスを計測してみた。

 

計測環境

AWSのリージョンはTokyoを使用した。

Redshiftのインスタンスはdc1.large。クライアントのインスタンスはm1.xlarge(4コア)だ。

インポート先のテーブルは、以下を用意した。

create table example (
    id integer,
    num decimal(12,0),
    value1 varchar(60),
    value2 varchar(60),
    value3 varchar(60),
    value4 varchar(60),
    value5 varchar(60),
    value6 varchar(60),
    value7 varchar(60),
    value8 varchar(60),
    value9 varchar(60),
    value10 varchar(60),
    primary key(id)
);

テストデータは、10,000,000件(約4.2GB)のCSVファイルを用意した。

 

手動でインポートしてみる

まずは、指標とするため、embulkを使わず手でインポートしてみる。

まずはChromeからS3 Management Consoleでアップロードしたところ、約3.3分掛かった。

そこからCOPYでインポートしたところ、約2.6分掛かった。合計約5.9分だ。

COPY
  example
FROM
  's3://xxx/temp/test1.csv'
CREDENTIALS
  'aws_access_key_id=XXXXXXXX;aws_secret_access_key=XXXXXXXXXXXXXXXX'
DELIMITER
  ','

 

embulk-output-redshiftでインポートする

以下のようなymlを用意し、embulk-output-redshiftでインポートしてみる。

in:
  type: file
  path_prefix: '/temp/test1.csv'
  parser:
    charset: UTF-8
    newline: CRLF
    type: csv
    delimiter: ','
    columns:
    - {name: id, type: long}
    - {name: num, type: string}
    - {name: value1, type: string}
    - {name: value2, type: string}
    - {name: value3, type: string}
    - {name: value4, type: string}
    - {name: value5, type: string}
    - {name: value6, type: string}
    - {name: value7, type: string}
    - {name: value8, type: string}
    - {name: value9, type: string}
    - {name: value10, type: string}
out:
    type: redshift
    host: xxxxxxxx.ap-northeast-1.redshift.amazonaws.com
    database: dev
    user: xxxxxxxx
    password: XXXXXXXX
    table: example
    mode: insert_direct
    iam_user_name: redshift
    access_key_id: XXXXXXXX
    secret_access_key: XXXXXXXXXXXXXXXX
    s3_bucket: xxxxxxxx
    s3_key_prefix: temp

約35.6分掛かった。

...結構掛かるな。。

embulk-output-redshiftでは、一定サイズ毎に、GZIP圧縮された一時ファイルを作成→S3にアップロード→COPY を繰り返す。

ログを集計したところ、この処理の回数は204回。

合計アップロード時間は12.2分、合計COPY時間は3.6分だった。

COPYはともかく、アップロードにかなり時間が掛かっているな。。

なお、CSVファイルを丸ごとGZIP圧縮したら、3.2GBくらいだった。

 

AmazonS3ClientのputObjectを計測する

アップロードが遅いのが気になったので、AWS SDKのAmazonS3ClientクラスのputObjectメソッドを使って、アップロードだけする簡単なプログラムを書いてみた。

すると、4.2GBのファイルのアップロードに17分くらい掛かった。

やはり、S3 Management Consoleに比べるとかなり時間が掛かっている。

なぜかは…、まだ分かっていない。。

 

batch_sizeを大きくしてみる

上で「一定サイズ毎に、GZIP圧縮された一時ファイルを作成→S3にアップロード→COPY を繰り返す」と書いたが、このサイズは大きくすることができる。

これを大きくすれば、アップロードやCOPYの回数が減るため、オーバーヘッドの分速くなるかもしれない。

ymlを以下のように修正した。デフォルトの10倍だ。

...
out:
    type: redshift
    batch_size: 167772160
    ...

結果は、33.7分で、若干速くなった。

アップロード&COPYの回数は21回、合計アップロード時間は11.4分、合計COPY時間は2.6分だった。

 

embulk-input-filesplitを使う

embulk-input-filesplitは、入力ファイルを分割して読み込み、マルチスレッド処理してくれる。

これを使えば高速化するかもしれない!

という訳で試してみた(batch_sizeは10倍)。

in:
  type: filesplit
  path: '/temp/test1.csv'
  parser:
    ...

結果は約8.9分で、かなり速くなった!

 

アップロードとCOPYをバックグラウンド化する

現状、アップロードとCOPYは同期処理になっている。

つまり、アップロードとCOPYが終わってから、次のレコードを読みに行くということだ。

アップロードとCOPYをバックグラウンドで行うようにすれば、速くなるかもしれない。

という訳で、実装して実行してみた(batch_sizeは10倍)。

結果は、約20.9分。

バックグラウンド化する前(33.7分)と比べると、だいぶ速くなった。

 

バックグラウンド化+embulk-input-filesplit

これに更にembulk-input-filesplitも組み合わせてみる。

embulk-input-filesplitですでにマルチスレッド化されているので、それほど効果は期待できないが…。

結果は、約7.7分。

若干速くなったようだ。

 

まとめ

現状のembulk-output-redshiftは少々遅いので、embulk-input-filesplitと組み合わせるのがお勧め。

embulk-output-redshift自体もマルチスレッド化などにより、高速化を目指したい。

 

embulk 0.6.16
embulk-output-redshift 0.4.1
embulk-input-filesplit 0.1.2