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分で、若干速くなった。
アップロード©の回数は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 |