データサイエンス

GCP Dataprepで大規模データを扱うときネックになるポイント

どうも、アナリティクス&デベロップメント部のTです。

GCPのサービスの一つ、Dataprepを使えば、GUI上でインタラクティブにデータの集計~整形・加工を行うことができます。

プログラミングコードを書けない人でも手軽にBigQueryやGCS上のデータをいじることができるので、

このサービスを利用してデータ加工パイプラインを組めば、ビジネス側の人も触れる大規模データの分析基盤を構築できるのでは…!

という話になり、機能調査してみました。

・・・

結論からお話ししますと、機能的には不足はないものの、オープンデータを使って基本的な処理を行う実験から以下の難点が見つかりました。

  • 処理速度が遅い
    • 特にCOUNT DISTINCTやJOINはデータ量が増えると結果が返ってこない
  • 課金額の予測が困難
    • 処理時間×使用CPU数による課金、ただしCPU数は自動でスケールされるので制御が効かない。

そもそも数MB程度のデータでも処理に5~10分程度かかってしまうのですが、それが数億行・数十GBのデータになると、処理によってはいつまでも結果が返ってこず時間課金だけ積もっていき、つらいです。

プログラミングができない人向けの小~中規模データのアドホック分析ツールとしてはよいかもしれませんが、

ビジネスサイドの人もいじれるETL(Extract, Transform, Load)ツールとして運用に乗せるのには、無理があるように思いました。

Dataprep #とは

概要

Dataprepの使用画面をまずはお見せします。

f:id:gri-blog:20200127102512p:plain

f:id:gri-blog:20200127102526p:plain

上記では、kaggleのRecruit Restaurant Visitor Forecastingというコンペティションのデータ*1をサンプルとして、データの選択・結合・集計を行っています。

GUI上で「レシピ」と呼ばれる処理のまとまりを作成し、複数ステップつなげていくことで1枚目の画像のようなワークフローを定義していきます。

レシピの作成は2枚目の画像のようなデータ編集画面で行います。
入力データに対して行いたい処理をメニューからポチポチ選択し、処理レシピを組んでいきます。

ワークフローを組み終ったら実行命令を出しましょう。
手動実行はもちろんのこと、決まったタイミングでバッチ処理を走らせるようにスケジューリングすることもできます。

詳しい使い方の実例はQiita等Web上にいくつかあるので、探してみてください(例えばこの記事)。

できること・できないこと

一般的なSQLで可能な操作は一部を除き大抵可能な印象です。

具体的には、以下のようなことができます

  • COUNT, SUMといった基本的な集計処理
  • カラム同士の四則演算
  • UNION, JOINといった複数データフレームの結合処理
  • GROUP BYのような集約処理

GROUP BYの後に集約せず行数そのままに新たなカラムを追加もできるので、カテゴリーごとの売上げ構成比の算出など、SQLでいうWindow関数(PARTITION BY)で扱うような処理も可能です。

逆に、できない処理は以下です

  • データの並べ替え(sort)
  • 複雑な演算(三角関数あたりは怪しいかも)

sortができないのはやや不便かもしれませんが、それ以外はよほど特殊な演算をしない限り問題なく使えるかと思います。

設定可能な項目

データソース

ブラウザからのデータアップロードを除けば、
入力・出力ともに、BigQueryとGoogle Cloud Storage(GCS)しか使えません。

AWS S3から入力データを取ってきたり、処理したデータを別のAPIに食わせるといったことはできません。

別のクラウドやアプリケーションと連携するには、いったんGCSに保存する必要があります。

処理パフォーマンス

Dataprepで作成したJobは、Cloud Dataflowを用いた分散処理基盤により自動スケールしながら実行されます。

この時指定できるのは、ワーカーとして処理を行うVMインスタンスの性能だけです。

Jobを実行すると裏でDataflowが立ち上がり、処理量と内容に応じてワーカーの数を自動調整しながらプロセスが進行します。

各ワーカーに割り当てられるCPUの数はVMインスタンスの性能を通して指定できますが、

ワーカーの数や、どのタイミングで増減するかを直接指定することはできません。

料金体系

気になるお値段ですが、

利用CPU数 × 時間(hour) × $0.6

により、秒単位で課金されます。

また、データソースにBigQuery, GCSを指定した場合、そちらの使用料は別途請求されます。

実験:大量データの扱い

さて、こんな感じで、

  • 大概のデータ加工処理はできるんだ!便利!
  • 重い処理でも性能のいいVMインスタンスを指定すれば対応できるね!
  • 1時間動かしても、1CPUあたり60~70円!?安くね?

のように、普段からぼーっと生きていてN〇Kの某ちゃんに叱られっぱなしな人だったら思うかもしれません。

まあ、一番目の機能面については申し分ないのですが、データ量を増やしてみたところ

性能とコストについては見事希望的観測を打ち砕かれました

概要

数億行・数十GBの大規模データを対象としたETLツールとしてDataprepを使うことはできるか?を調べるために、
オープンデータを使って5種類の基本的な操作をを行い、パフォーマンス(実行時間)とコスト(課金額)を調査しました。

データ内容

実験には、BigQueryのサンプルの一つでもあるChicago Taxi Tripsを用いました。
こちらはタクシーの走行ログデータで、車体識別ID(taxi_id)、タクシー会社名、乗車・下車時刻や位置、走行距離といった情報が入っています。

データ量は1.9億行で70GBです。

大きめのWebサービスであれば、一日ないし一週間でこれくらいの閲覧ログが溜まってもおかしくないよね、という量だと思います。

実験内容

データ加工を行う上で必ず使う、以下の5種類の操作を試しました:

  • 集約(GROUP BY)
    • 車体ごとに走行時間の合計値を計算する
  • 抽出(SELECT)
    • 特定のtaxi_idのレコードのみを取り出す
  • カラム更新(UPDATE)
    • 走行時間が5分を超えるレコードは、走行時間を+10秒加算する
  • カウント(COUNT DISTINCT)
    • 一意なtaxi_id数を数え上げる
  • 結合(JOIN)
    • 別でタクシー会社のマスタテーブルを用意しておき、会社名をキーにログデータと結合する。

そのうえで、実行時間とかかった料金を調べました。

なお、処理インスタンス自身の性能によるパフォーマンスの違いも見るために、1ワーカー当たりのCPU数が1コア、8コアの2パターンで調べ、比較しました。

実験結果

1コア(n1-standard-1)

操作内容 実行時間 最大起動ワーカー数 合計vCPU時間 料金
集約 15分18秒 27 4.2H $2.53
抽出 15分39秒 24 4.0H $2.41
カラム更新 17分1秒 205 24.0H $14.4
カウント ERROR (168) (70H以上) ($42以上)
結合 (3時間以上) (41) (100H以上) ($60以上)

8コア(n1-standard-8)

操作内容 実行時間 最大起動ワーカー数 合計vCPU時間 料金
集約 18分54秒 5 5.3H $3.18
抽出 19分50秒 5 5.6H $3.36
カラム更新 17分20秒 41 42.3H $25.3
カウント (45分以上) (41) (40H以上) ($24以上)
結合 (45分以上) (10) (40H以上) ($24以上)

処理時間

まずは最も性能の低いコア数1のインスタンス(n1-standard-1)で見ると、全体的に15分以上かかり遅いうえ、カウントと結合に至っては答えが返ってきませんでした。

それではとインスタンスの性能を上げ、8コア(n1-standard-8)にしてみても、カウント・結合ともに完了できませんでした。

他の操作も、実行時間がほとんど変わらないどころか、逆に遅くなっています。

料金

さらに料金で見ると、集約・抽出でも一回数ドル、カラム更新・カウント・結合に至っては数十ドル課金されました。。。

簡単な抽出・集計処理を行うだけでも数百円、結合が挟まると数千円かかるうえ答えが返ってくる保証がないわけです!

総じて、遅い!高い!割に合わない!

考察:何故こんなにコスパが悪いのか?

なぜ遅い?

前述の通り、Dataprepの処理はDataflow上で行われ、処理内容と量に応じてワーカーを並列に生成して分散処理してくれます。

一応数十~100ワーカーまで並列しているにもかかわらずこれだけ遅いということは、考えられる理由は

  • Dataflowで自動生成された処理ロジックが最適化されていない
  • VMインスタンス立ち上げの際のオーバーヘッドが大きい

といったところでしょうか?

なぜ高い?

実行速度は仕方ないとして、なぜこんなに高いのか?
単位時間当たり$0.6のはずでしょ?と思うかもしれませんが、もう一度思い出しましょう。

Dataprepの料金体系は、時間×使用CPU数で決まっていました。

×使用CPU数に注意が必要です。

分散処理をして起動ワーカー数が増えると、その分起動したCPUが全て課金対象になります。

ただでさえ処理自体に時間がかかるところに、分散処理によりCPU数まで増えているので、合計CPU稼働時間で見ると…数十時間超過!これに$0.6をかければ要するにそういうことです。

まとめ

DataprepはGUIをいじるだけで手軽にデータ取得から処理の定義、実行・スケジューリングまで可能なため、確かに便利でした。

数十~数百MBくらいの量までのデータなら、プログラミングの知識がない人でもデータ加工フローを構築できるでしょう。

しかし数十GBスケールのデータになると、場合によっては結果が返ってこないばかりかその分の処理も課金され、予想外にお金が溶けてしまった…orzということが起き得てしまいます。

因みに、今回結果が返ってこなかった結合(JOIN)操作ををBigQuery上で実行してみたところ、データアップロード含めても1分半程度で終了しました。

しかも、データ処理量1TBあたり$6.00の従量課金制*2なので、今回の70GBに対してはおおよそ45円、しかも毎月1TBまでは無料、、、

…うん、BigQuery使おう。