EmbulkでMySQLに4GB突っ込んで測ってみた
Embulkを使えば、いろいろなデータを簡単にDBに突っ込めるはず。
でも、パフォーマンスが気になるよね。
という訳で、Embulkのパフォーマンスを測ってみることにした。
環境の準備
自分のマシンでパフォーマンステストをすると他のことができなくなってしまうので、AWSを使うことにした。
インスタンスタイプはどうしようか?
マルチスレッドを試したいので4CPU欲しい。DB入れるのでメモリもある程度必要だ。ディスクはSSDだとちょっと速過ぎる気がするし、EBSだと遅い気がするし…、とかいろいろ考えて、結局旧世代のm1.xlargeにしてしまった。
OSは自分のマシンに合わせてWindows。JavaとかMySQLもインストールする。
MySQLのチューニングとかは特にしていない(あまり詳しくないので…)。
Embulkもダウンロードした。このときの最新は0.5.0。
embulk-output-jdbcとembulk-output-mysqlもインストールする。
テストデータの作成にもEmbulkを利用しよう。
以前も試した embulk-plugin-input-random(0.1.0)を使わせてもらった。
ymlはこんな感じ。
exec: {} in: type: random rows: 10000000 schema: id: primary_key number: integer value1: string value2: string value3: string value4: string value5: string value6: string value7: string value8: string value9: string value10: string out: type: file path_prefix: z:/test file_ext: .csv formatter: type: csv header_line: false charset: UTF-8 newline: CRLF
なんで10,000,000件かというと、試しに1,000,000件で400MBくらいのデータを入れてみたら、2分くらいだったから。
2分じゃちょっと短いし、200分だと大変なので、20分くらい掛かるデータ量にしようと思ったのだ。
できたファイルサイズは、約4.2GB。
テーブルの方も、こんな感じで用意しておく。
create database EMBULK default character set utf8; grant all on EMBULK.* to embulk_user@"%" identified by 'embulk_pw'; create table example ( id bigint, number bigint, 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) );
embulk-output-jdbcはまだint型には対応していないので、bigint型を使う必要がある。
embulk-output-mysqlで突っ込む
こんな感じのymlを用意して、MySQLに突っ込んでみた。
in: type: file path_prefix: Z:/test.000.00 parser: charset: UTF-8 newline: CRLF type: csv delimiter: ',' quote: '"' escape: '' null_string: 'NULL' header_line: false columns: - {name: id, type: long} - {name: number, type: long} - {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: mysql host: localhost database: embulk user: embulk_user password: embulk_pw table: example mode: insert
27分くらい掛かった。速いか遅いか、というと、他と比べてみないとよく分からん。
という訳で、LOAD DATAと比べてみることにした。
LOAD DATAで突っ込む
という訳で、こんな感じで突っ込んでみた。
select current_time(); LOAD DATA LOCAL INFILE 'Z:/test.000.00.csv' INTO TABLE example FIELDS TERMINATED BY ',' LINES TERMINATED BY '\r\n'; select current_time();
6分くらいだった。
さすがに速い。
しかし、Embulkにはマルチスレッド機能がある!
4CPUをフル活用すれば、速度4倍くらいになって、互角になるはず!
embulk-output-mysqlでマルチスレッドで突っ込む
と思ったんだが、どうやってマルチスレッドで動かすんだろ?
ドキュメントを見ても、それらしい設定項目は無いな…。
という訳で、ソースを追ってみると、org.embulk.standards.LocalFileInputPluginクラスに以下のようなコードが。
// number of processors is same with number of files int taskCount = task.getFiles().size();
つまり、複数ファイルを入力する場合はマルチスレッドになるけど、1ファイルしかない場合は1スレッドで動くようだ。
うーん、困ったな。このままだとLOAD DATAに負けたままになってしまう…。
という訳で、1ファイルを分割して読み込み、マルチスレッドで動かせるInputPluginをテスト用に作ってみた(いずれ整理して公開する予定)。
CPU数×2の8スレッドで動かして(org.embulk.exec.LocalExecutorに準じた)、結果は…、
何と、7分!!!
これなら十分LOAD DATAに対抗できるな。
まとめ
結局、それぞれ3回ずつ計測した。平均を取ったのがこれ。
方法 | 実行時間(分) | CPU利用率 |
---|---|---|
embulk-ouput-mysql | 22.2 | 27.3 |
embulk-ouput-mysql(8スレッド) | 7.0 | 86.3 |
LOAD DATA | 5.6 | 23.3 |
マルチスレッド化でさすがに4(CPU数)倍にはならなかったが、3.2倍くらいになった。でも十分速い。CPUもほぼフル活用されている。
今後は、CPU数をさらに増やしたらどうなるかとか、別のDBMS(OracleとかSQL Serverとか)ではどんなものかとか、いろいろ試してみたい。
AWSインスタンス | m1.xlarge (データディレクトリはInstance Storeを使用) |
OS | Windows 2008 R2 SP1 Datacenter edition (64bit, Japanese) |
Java | JDK 8u31 |
Embulk | 0.5.0 |
embulk-output-jdbc | 0.2.0 |
embulk-output-mysql | 0.2.0 |
MySQL | 5.6.23 (InnoDBを使用) |