表題の通りでembulkというツールを今更ながら初めて触ってみたので記事にしてみたいと思います。digdagと連携してスケジュール処理をしようと思ったのですが記事が膨大になりそうなのでembulk検証からアウトプットしていきます。
背景
embulkを学ぼうとした背景としてはサイトを運用・開発していると開発環境などではデータを手動でいじったり開発環境で起こった不具合などの不整合なデータが存在し、テストの際に正確なデータとしてテストができないため特に数字(ビジネス)周りの改修などはデータコピーや正確なデータを用いることができないと意図せぬ不具合や安心してリリースすることができない。かといって手動で度々のデータコピーとなるとテーブル間のリレーション関係など熟知していなければならずデータが大きくなると時間もかかるし効率が悪い。。この課題を解決したいと思ったので学びました。
embulkとは
ファイルやデータベースからデータ抽出を行い、別のストレージやデータベースにデータ転送するためのツールです。
https://qiita.com/da-sugi/items/13d4ead19c86d783ebb4
OSSのデータ転送ツールでデータのin,outを含めfilterなどの加工も行うことができる高性能なツールです。
やりたいこと
本番のDBと開発DBとでリアルタイムではなく、一週間や3日単位で本番データの差分を開発DBへコピーしたい。
実現するには
・embulk + digdag
・embulk + fargate(スケジューリング)
・バッチ(AWS Batch)
他にも実現する方法は多くありますが今回はembulk + digdagを検証材料にしました、理由はdigdag自体の学習コストはfargateよりも高くなさそうでAWS Batchほど管理が不透明にならない理由でこの構成で検証して行こうと思いました。
あとembulkは差分更新が簡単に実現可能、巨大なデータの処理を得意とするためDBへの負荷を抑えることができそう、embulkの定義ファイルはテーブルに対しファイルが1:1なのでファイルを増やすだけで容易に拡張可能、embulkにはinputとoutputのプラグインが充実していて様々なサービスと連携できるため差分同期をETL専用のDBやBigQueryなどにも展開することもできる。
検証方法
docker環境でデータコピーが正常になされるのかをmysqlコンテナを2台(mysql01, mysql02)を立てて検証してみます。
初期データ挿入のためにエリア情報(region.sql)、都道府県情報(prefectures.sql), ユーザ情報(users.sql)をmysql01コンテナ内のエントリーポイントに以下のように配置します。
version: '2'
services:
mysql01:
image: mysql:5.7
ports:
- '13306:13306'
volumes:
- ./ddl:/docker-entrypoint-initdb.d
- ./my.cnf:/etc/mysql/conf.d/my.cnf
environment:
MYSQL_DATABASE: test
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
mysql02:
image: mysql:5.7
ports:
- '23306:23306'
volumes:
- ./my.cnf:/etc/mysql/conf.d/my.cnf
environment:
MYSQL_DATABASE: test
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
embulk_digdag:
build:
context: ./embulk_digdag
volumes:
- ./src/:/workspace
links:
- mysql01
- mysql02
実際に本利用するにあたって期待する検証の挙動を確認する
※前提条件としてはmysqlコンテナに同一テーブルが存在すること(Embulkはよしなにテーブルを作ってくれるが型の違いやindexを貼ってくれないためため運用では使用しない)
※ユーザ情報の名前は個人情報なのでマスクすること
Embulk環境を作る
実際に検証するために準備をしていく。
上記のリポジトリをcloneしてdocker-compose upすればコンテナ内での作業検証になるが環境構築することはできる。(digdagコマンドもインストールしているが無視で問題ない)
embulkの設定ファイルはymlで書くことができる。
ただ、mysqlのin、outのhost情報などを重複して管理することになるためLiquidファイルを利用することでDRYな書き方を実現できるため今回もそうしている。
またif文などで環境ごとにin, out設定も変更可能なため利用しました。
簡単に設定ファイルの使い方として guess
preview
run
の使い方を紹介する。
$ embulk guess region.yml.liquid
in:
type: mysql
user: root
database: test
host: mysql01
options: {useLegacyDatetimeCode: false, serverTimezone: Asia/Tokyo}
column_options:
create_date: {value_type: string, timestamp_format: '%Y-%m-%d %H:%M:%S'}
update_date: {value_type: string, timestamp_format: '%Y-%m-%d %H:%M:%S'}
table: region
select: '*'
out: {type: mysql, user: root, database: test, host: mysql02, table: region, mode: merge}
guessを使うことで設定ファイルの記述を確認することができます。
$ embulk preview region.yml.liquid
previewを使うことでどんなデータをコピーするのかを確認することができます。また、embulkはdatetime型を許容していないことと、デフォルトUTCの時間を東京の設定に変更する必要があります。
previewではUTCとして表示されていますが出力先にて日本時間に戻して格納しています。DBサーバーとEmbulk側での設定次第で若干の調整が必要になるのが少し扱いに苦戦しました。
$ embulk run region.yml.liquid
runでpreviewで確認したデータを実際にコピー実行します
コマンドが通ればコピー先のDBの中身を確認してみてください。
基礎的な扱いが分かったので実際に検証していきます。
検証内容
⒈ mysql01のエリア情報データ(region)をmysql02にコピーする
$ embulk run region.yml.liquid
無事正常に全データコピーがされていることが確認できました。
2. mysql01,mysql02に都道府県情報データ(prefectures)があるが一部データの内容が違う、あるいは行数に差がある場合のコピーする
都道府県情報のid=13の東京の行を削除し、id=27のosakaの名前をkosakaにかえてみてから実行してみます。
※mysql02にデータがない場合は1で行った 手法で一旦全コピーしてからupdateをかけても良いかもです。
試してみたところmergeモードでどちらにも正常な更新をかけることができました。しかし、idにauto_incrementをカラムに設定していないテーブルに対してはデータが重複insertされてしまいます、embulkのincrementオプションと -c コマンドオプションを利用することで重複を防ぐことができますがymlファイル別に書き換えるとすると実運用にすると手間がかかるかなと感じました。BigQueryなどデータ操作の入らないDBに対しての差分実行は効果的ですが開発環境での実行になると懸念事項に全て対応することは難しそうです。
なので開発環境に指定するモードとしては常に本番DBと同一性を求めるとすると truncate_insert
が理にかないそうです。
3. mysql01にユーザ情報(users)があり、mysql02にコピーをするときにユーザ名をマスクする。
embulkの設定ファイルにてafter_selectのオプションで同一のtransaction内で更新をかけるため、マスク失敗などの挙動を防ぐことができる。マスク対象データをささっとマスクしながらデータコピーできるのはとても使い勝手がよく感じました。
まとめ
embulkによる検証を行っていきました。
まだ使ってみたばかりですが利用してみてプラグインなど多く開発ツールがあり組み合わせることで様々なデータソースに対してもデータを加工し保存することができるため用途も様々に扱えそうです。
今回はサーバーやDBサーバーへの負荷検証などは行えていないので実データを元に検証もできたらと思います。
digdagと連携し自動データコピーを実現できることになると運用・開発においての品質面に対しても効率的な運用にできそうなので引き続き検証していきます。