要約
- PythonでDataflowを実行すると、実行完了後に GCSの
temp_location
のファイルが消えない不具合がある- Python実装のみの不具合(Javaで実行したときは勝手に消えるらしい)
- 毎日数十GBのBigQueryデータ投入タスクを行なっていると、すごい勢いでGCSの使用量が増え、多額の請求が発生する
- 今のところ、GCS bucket lifecycleでデータを自動削除するくらいしか回避方法がない
発生した問題
GCPのDataflow(Python)を使って、毎日数十GBのデータをBigQueryに投入するジョブを走らせていたところ、GCSの請求金額が一日あたり$7/日ずつ増えている事に気が付きました。
GCS bucketを調査すると、Dataflowで使っているbucketの使用量が爆速で増えてました。
- 220GB/日のペース
原因
原因は、Dataflow実行時に --temp_location
で指定するフォルダ内に、生成された一時ファイルが永遠に残り続けていたためでした。
$ gsutil du -s -h gs://******-bucket/dataflow/tmp/**
40.24 TiB gs://******-bucket/dataflow/tmp/**
オプション名から、 temp_location
フォルダに置かれる一時ファイルは、Dataflowジョブが終わった段階で勝手に消えるものと期待していましたが、実際には消えずに残っていました。
- ドキュメントでは「ジョブが失敗すると、Dataflow は一時ファイルやステージング ファイルを自動的にクリーンアップしないことがあります。」などと書かれている箇所があり、ジョブ成功時には勝手に消えそうな感じがする。
temp_location
フォルダのファイルが消えない件についてサポートに問い合わせたところ、「 Javaでは消えるがPythonではなぜか消えない。バグっぽい 」との回答を得たので、しばらくの間は temp_location
のファイルを手動で消して、bucket使用量が肥大化しないようにしないといけなそうです。
- 当該の実装部分(サポート問い合わせで教えてもらったもの)
bucketの肥大化を防ぐには、GCSのオブジェクトライフサイクルを使うと良いです。
Dataflowを使用しているチームの方は、一度 temp_location
が肥大化していないか確認していただけると良いかと思います。
備考
Q: どうして数十GBのBigQueryへのデータ投入で220GB/日も一時ファイルが作られていたんですか?
A: Apache Beamの WriteToBigqueryの仕様のためです。
WriteToBigqueryは、BigQueryに書き込むデータを一旦無圧縮JSONとしてファイルに書き出すため、もとのCSVデータの10倍くらいのファイルを一時ファイルとして吐くようでした。
例:
元のデータが
c1,c2,c3,c4
1,"a","あ",true
2,"b","い",false
のようなテーブル(BeamのPCollection)のとき、WriteToBigqueryは
{"c1": 1, "c2": "a", "c3": "あ", "c4": true}
{"c1": 2, "c2": "b", "c3": "い", "c4": false}
のようなファイルを一時ファイルとして吐いており、カラム名が毎行付与されていく&無圧縮なのでファイルサイズがめっちゃでかくなってしまう。
- しかも、扱っているテーブルはカラム数が100個くらいあるテーブルが多く、値はカラ(null)であることが多いため、その分Beam→jsonでデータサイズが増えていました。
- 中間ファイルの形式は無圧縮JjsonかAvroかを選べるらしいのですが、どうせ一時ファイルだし何でもいいやと無指定でジョブを実行していたら、無圧縮jsonが永続的に保存され続ける状態になってしまっていました。