Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

Athenaでデータの格納形式ごとのクエリ実行性能を比較してみた

こんにちは、唄うエンジニア、miyajima です。

仕事の中でAmazon Athenaを利用する機会があったため、今回はそのAmazon Athenaを使った性能比較を試してみました。


Amazon Athena とは - Amazon Athena

Amazon Athena はS3に保存されているファイルのデータをSQL形式のクエリで直接検索することができるサービスです。
大量のデータを高速に分析、検索することができ、また一度テーブル定義すれば、あとはS3にファイルを置くだけで検索できるようになるのでデータの追加変更も容易です。またサーバレスですから費用は検索に使用した分だけとなり、運用コストも抑えられます。

Athenaサポートしているデータ形式は、以下のように多数用意されています。

  • 一般的なデータファイル形式: CSV, TSV, JSON
  • Hadoopの分散処理に適用した形式: Apache Avro, Apache Parquet, ORC
  • その他、 Apache WebServer、CloudTrail、Logstashのログ形式など

サポートされる SerDes とデータ形式 - Amazon Athena

またGZIPなどでの圧縮したデータも扱えます。

そのため、それぞれのデータ形式によって性能差がどのくらいあるのかは把握しておきたいところです。
また、AthenaはS3上の指定したパス上の全ファイルを1つのテーブルとして扱うため、ファイル数やファイルサイズがどのようにパフォーマンスに影響するのかも気になりますね。
ということで、いくつかの観点に沿って実行時間を調べてみました。

比較内容

今回は以下の観点にそって性能比較を行いました。

観点 内容
ファイルサイズ/ファイル数 データファイルの分割数を 1 / 10 / 100 / 1,000 / 10,000 にした5パターンのデータセットを用意し、それぞれの検索速度を比較
ファイル形式 同一の情報量のデータをCSVJSON、Parquet形式で用意し、検索速度を比較する。
圧縮/非圧縮 同一のデータをgzip圧縮した場合としない場合で比較。この時ファイルサイズによる影響も比較する。
検索方法 各ファイル形式に対して全検索、LIKE検索、列指定検索を比較する。

また、今回はデータ形式を主眼に比較を行っており、パーティションは指定していません。できれば別の機会に、パーティション指定の有無による性能比較も試したいと思います。

今回の調査にあたり使わせていただいたデータは、以下のページで公開されているWebサーバのログファイルです。

AIT Log Data Set V1.1 | Zenodo

この中から、Webサーバのアクセスログ(14万行)を複数のフォーマットに変換してS3に登録し、検索してみました。
mail.cup.com-access.log(抜粋)

192.168.10.190 - - [29/Feb/2020:00:00:02 +0000] "GET /login.php HTTP/1.1" 200 2532 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0"
192.168.10.4 - - [29/Feb/2020:00:00:09 +0000] "POST /services/ajax.php/kronolith/listTopTags HTTP/1.1" 200 402 "http://mail.cup.com/kronolith/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/77.0.3865.90 HeadlessChrome/77.0.3865.90 Safari/537.36"
192.168.10.190 - - [29/Feb/2020:00:00:12 +0000] "POST /login.php HTTP/1.1" 302 601 "http://mail.cup.com/login.php" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0"
192.168.10.190 - - [29/Feb/2020:00:00:13 +0000] "GET /services/portal/ HTTP/1.1" 200 7696 "http://mail.cup.com/login.php" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0"
192.168.10.190 - - [29/Feb/2020:00:00:14 +0000] "GET /themes/default/graphics/head-bg.png HTTP/1.1" 200 380 "http://mail.cup.com/themes/default/screen.css" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0"
192.168.10.190 - - [29/Feb/2020:00:00:14 +0000] "GET /themes/default/graphics/logo.png HTTP/1.1" 200 2607 "http://mail.cup.com/themes/default/screen.css" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0"
::1 - - [29/Feb/2020:00:00:18 +0000] "OPTIONS * HTTP/1.0" 200 110 "-" "Apache/2.4.25 (Debian) OpenSSL/1.0.2u (internal dummy connection)"
192.168.10.190 - - [29/Feb/2020:00:00:19 +0000] "GET /mnemo/ HTTP/1.1" 200 5681 "http://mail.cup.com/services/portal/" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0"
192.168.10.190 - - [29/Feb/2020:00:00:22 +0000] "GET /services/portal/ HTTP/1.1" 200 7053 "http://mail.cup.com/nag/list.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/77.0.3865.90 HeadlessChrome/77.0.3865.90 Safari/537.36"
192.168.10.190 - - [29/Feb/2020:00:00:26 +0000] "GET /mnemo/ HTTP/1.1" 200 5179 "http://mail.cup.com/services/portal/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/77.0.3865.90 HeadlessChrome/77.0.3865.90 Safari/537.36"
...

なお今回の性能比較の中で、全く同じ条件(データ形式、ファイルサイズ、ファイル数)でクエリ実行した場合でも、実行時間が平均値に対して20~40%程度のバラつきがありました。それもコールドスタートで発生するような「初回のみ遅い」という訳ではなく、連続で実行した時も途中の実行回だけ他よりも時間がかかる、というようなこともありました。
これは、AWS内部リソース割り当ての調整などで実行時間に差が発生しているのかもしれません。

これらのばらつきの影響を軽減するため、今回の測定では、5回測定した処理時間のうち最大値・最小値を除いた中央3値の平均を測定値とすることとしました(オリンピックでの芸術点の付け方と同じです)。

また、今回使用したデータは生の状態でも数百MB程度のものですが、GB、TB単位の大量のデータを扱う場合は、今回の誤差の影響は相対的に小さくなるのではないか、と思います。

比較結果

ファイルサイズ/ファイル数による比較

まず検証方法ですが、情報としては全く同じデータをJSONCSV、Parquetの形式で用意し、更にそのデータを1 / 10 / 100 / 1,000 / 10,000 のファイル数で分割したデータセットを作成します。
つまり、ここまでで以下の15パターンのデータセットが用意されました。

形式 ファイル数 1ファイルのデータ件数 1ファイルのサイズ(平均)
JSON
1
148,534
49,019.3 kB
JSON
10
14,854
4,901.9 kB
JSON
100
1,486
490.2 kB
JSON
1,000
149
49.0 kB
JSON
10,000
15
4.9 kB
CSV
1
148,534
37,124.2 kB
CSV
10
14,854
3,712.4 kB
CSV
100
1,486
371.2 kB
CSV
1,000
149
37.1 kB
CSV
10,000
15
3.7 kB
Parquet
1
148,534
-
Parquet
10
14,854
-
Parquet
100
1,486
-
Parquet
1,000
149
-
Parquet
10,000
15
-

※Parquetのデータはファイルを直接読み込んで得る形式ではなく、CSVデータをを元に変換しています。

そしてこれらのパターンそれぞれをAthenaの別々のテーブルに格納し、クエリを実行しました。

クエリ実行時間は、以下のようになりました。

ファイル分割数 1ファイルのデータ数 JSON CSV Parquet
1 148,534 2.17秒 2.19秒 1.90秒
10 14,854 2.15秒 2.10秒 1.83秒
100 1,486 2.11秒 2.34秒 1.89秒
1,000 149 2.03秒 2.65秒 2.26秒
10,000 15 3.09秒 3.04秒 2.49秒

ファイルサイズ・ファイル数での比較

今回は、そこまで影響は大きくはなかったですが、どの形式もサイズが小さいファイルが多くなると、処理時間が長くなる傾向が見えました。

圧縮/非圧縮の比較

今回はgzip圧縮した場合と非圧縮の場合、またファイル形式ははJSONCSVで試しました。
さらに、圧縮したデータの操作はファイルサイズや分割数にも影響する可能性があるため、ファイル分割数を上と同様にいくつかのパターンで実施しました。

ファイル分割数 1ファイル 100ファイル 10000ファイル
JSON:非圧縮 2.17秒 2.11秒 3.09秒
JSON:gzip 3.03秒 2.62秒 3.77秒
CSV:非圧縮 2.19秒 2.34秒 3.04秒
CSV:gzip 2.59秒 2.47秒 3.06秒

圧縮・非圧縮での比較

今回のデータではJSONCSVともに、検索にかかる時間はGZIP圧縮した方がわずかに長かったです。圧縮したデータを扱う方が効率は良くなるように感じますが、検証に用意出来たデータのサイズがそれほど大きくないため、あまりその効果が反映されなかったのかもしれません。

またデータ保存の観点では、データを圧縮した方がコスト効率がよいため、その点を踏まえて実際のデータで試した方がいでしょう。

ファイル形式と検索方法による比較

次はクエリによる比較です。 今回検証に使用したクエリは以下の3パターンです。

  • 全検索("SELECT * FROM <テーブル名>")
  • LIKE検索("SELECT * FROM <テーブル名> WHERE path LIKE '%.php%' ")
  • 列指定検索("SELECT host, path, status FROM <テーブル名>")

この3つのクエリで、JSON / CSV / Parquet の3種類の形式を、更にファイル分割数も替えて検索しました。

全検索

データ形式 1ファイル 100ファイル 10,000ファイル
JSON 2.17秒 2.11秒 3.09秒
CSV 2.19秒 2.34秒 3.04秒
Parquet 1.90秒 1.89秒 2.49秒

ファイル形式での比較(全検索)

LIKE検索

データ形式 1ファイル 100ファイル 10,000ファイル
JSON 1.82秒 1.53秒 2.69秒
CSV 1.94秒 1.64秒 2.71秒
Parquet 2.10秒 1.92秒 1.49秒

ファイル形式での比較(LIKE検索)

列指定検索

データ形式 1ファイル 100ファイル 10,000ファイル
JSON 1.80秒 1.54秒 2.60秒
CSV 1.46秒 1.35秒 2.59秒
Parquet 1.45秒 1.50秒 1.63秒

ファイル形式での比較(列指定検索)

CSVJSONは、どの検索方式でもファイル数が増えるにしたがって処理時間も増えているのが分かりますが、ParquetはLIKE検索、列検索の際、ファイル数が増えても処理時間が増えていません(というかLIKE検索は処理時間が減ってすらいます)。
Parquetは列指向データ形式といい、列単位でデータを取得、検索する際に最適化されたフォーマットです。この形式はデータの格納や検索を最適化するためのエンコーディングが複数用意されています。
エンコーディング方法の例:

エンコーディング方式 概要 効果の高いデータ列
Dictionary Encoding 出現する値を辞書に格納し、テーブルにはそのキーを格納する 出現する値の種類が限られているようなデータ
Run Length Encoding (RLE) 値と、その値を繰り返す回数のペアを格納する 同じ値が連続して出現するようなデータ
Delta Encoding 一定件数ごとに区切った中でのデータの前後の差分を抽出してその差分を保持する 一定のペースで変化する数値データ

参照: Encodings | Apache Parquet

そのため、これらの方式に適するデータを格納するようなスキーマを設計し、またそのカラムを検索、抽出の対象にできれば、よりParquetの特性を生かし、処理を高速化させる事が出来るのではないかと思います。

また今回はデータ量が数十MB程度しかありませんでしたので、それを強く実感できるほどではないのかもしれません。機会があれば、もっと多量のデータで検証してみたいと思います。

まとめ

今回の検証のまとめです。

  • 大量データを扱う場合は特に、処理時間、コストの両方の観点から、Parquet形式を積極的に使う。
  • ファイル数が細かく、多くなると、処理時間が長くなる傾向がある。
  • 今回のデータでは圧縮ファイルを使った場合の性能改善は見られなかった。更に大きなデータでの検証が必要。

それぞれで性能に差分は確認できましたが、より多くのデータ、複雑な条件になった時には、異なる傾向が見えるかもしれません。 機会があれば、別のデータセットで試してみたいと思います。

また、Athenaの性能改善を行う上で、AWS公式のパフォーマンスチューニングの情報は把握しておくとよいでしょう。

Amazon Athena のパフォーマンスチューニング Tips トップ 10 | Amazon Web Services ブログ

Acroquest Technologyでは、キャリア採用を行っています。
  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長
  少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。 www.wantedly.com