For Your ISHIO Blog

データ分析や機械学習やスクラムや組織とか、色々つぶやくブログです。

Sparkでファイル形式や圧縮形式について実験した

大規模データを処理するために、Sparkを活用しています。 先日、Twitter上での投稿に対して、もみじあめさんから、下記コメントをもらいました。

最後に述べている通り、実験が悪く、圧縮率とスループットの関係があまりつかめなかったのですが、せっかくなので今回実験した結果を共有します。

分析基盤で取り扱う3つのフォーマット

分析基盤で扱うファイルフォーマットには大きく3つのフォーマットがあると思います。

  1. テキストフォーマットCSVJsonなど)
  2. 行指向フォーマット(AVROなど)
  3. 列指向(カラムナ)フォーマット(Parquet、ORCなど)

どのように使い分けるか

chieさんのブログがわかりやすかったです。

engineer.retty.me

テキストフォーマットは、人間にとっての可読性が高いことや、アプリケーション間の連携が取りやすいことがメリットだと思います。また、データベース用途では、人間の可読性よりも保存時の圧縮効率や機械による処理のしやすさが重視されます。そこで、行指向列指向のフォーマットが登場します。

行指向フォーマットは、行方向に連続してデータを格納する方式です。従来のデータベースは、この方式を取っており、OLTP(Online Transaction Processing)向きです。逆に列指向フォーマットは、列方向に連続してデータを格納する方式であり、列単位でデータを取り出し分析するOLAP(Online Analytical Processing)向けです。

検証内容

  • 約5億レコードのデータをSparkでHDFSに書き込む処理について、HDFSに書込むファイル形式や圧縮形式を変更した。スループットHDFS上でのファイルサイズがどのように違うかを確認した。

検証環境

  • CDH6(マスター1台、スレーブ4台構成)
    • マスター:4vcpu、メモリ16G、ディスク100GB
    • スレーブ:8vcpu、メモリ32G、ディスク100GB
  • パラメータ(固定)
    • Executor数:4
    • core数:3
  • ファイル形式
    • AVRO、CSV、Parquet
  • 圧縮方法
    • 非圧縮、snappy、deflate、Gzip

検証結果

HDFS書き込み速度

  • ファイル形式によって処理速度に差が出た。parquet形式が全体的に最も処理が早く、CSV、AVROという結果になった。
  • 圧縮方法別では、非圧縮の場合が最も早かった。

f:id:ishitonton:20200917225900p:plain

ここからは雑な仮説になってしまうのですが、今回はHDFSへの書き込む処理のみなので、「圧縮時間」「各ファイル形式へのデシリアライズにかかる時間」「デシリアライズ後のファイルサイズ」が処理時間い影響していそうな気がします。

ファイルの圧縮率

  • parquetが特にファイルサイズが小さくなった。非圧縮でもファイルサイズは小さいが、特にGzipやsnappyにするとかなりの圧縮率になっている。
  • CSV形式で圧縮しないのとでは、約10倍サイズが変わった。 f:id:ishitonton:20200917230514p:plain

考察

私の実験環境、実験データでは、parquetのスループットが非常に速い結果になりました。これは、chieさんのブログにもあるとおり、parquetは、構造的に分散処理に適していることが理由と言えそうです。

また、parquetは非圧縮でも非常にファイルサイズが小さくなっていることがわかりました(対CSV)。これに関しては、parque自体が圧縮に優れていることが言えそうです。ここについては、もう少し考察を述べていきたいと思います。

parquetのエンコーディング

parquetは、列の圧縮に優れているのが特徴です。これが、snappyやGzipで圧縮をしなくても、parquet形式で保存するだけで十分に小さなファイルサイズになった要因だと考えています。では、そのparquetの圧縮についてみていきます。 下の図は、列Xの値を示しています。値が頻繁に繰り返される場合、圧縮しやすい構造です。列指向フォーマットは、列単位で保存を行いますので、同じ値が入っている可能性が高いです。

データウェアハウスで効果的な圧縮の方法に、ビットマップエンコーディングがあります。列XでN個のユニークな値が存在している場合、N個の分離されたビットマップにします。Nが非常に小さい場合には、これらのビットマップは行ごろに1つのビットですみます。Nが非常に大きい場合には、ビットマップの大部分はゼロが並んでいるだけであり、ランレングスエンコーディングを加えることでコンパクトになります。

f:id:ishitonton:20200917233102p:plain

反省

今回の検証では、圧縮率とスループットの関係をあきらかにしたかったのですが、そこまで行きつきませんでした。実際に運用する中では、圧縮形式により必要なCPUリソースが結構変わってきており、OOMになったりスループットが非常に遅くなる事象がありました。次は、もう少しCPU効率を明らかにする実験をしたいと思います。