Secret Ninja Blog

Support Engineering Manager してます

PrestoのDistributed Sortのパフォーマンスを見る(見れてない)

負けられない戦いがそこにある。アドベントカレンダー3日目。

Arm Treasure Data Advent Calendar 2019 - Adventar

Prestoのバージョンアップに際して、トレジャーデータのPrestoを利用して検証するのは簡単なんですが、あくまでトレジャーデータのPrestoの検証になってしまうところが気になります。 ブログにふと書こうと思った時に、なるべくOSSとしてのPrestoでの機能による性能差を書きたいなというのがポリシーなところです。 また、再現性がないことはよくないので、PrestoのDockerイメージを利用して、ローカルでTPCHを利用して検証してみます。また、今回の検証対象として、Distributed Sortの仕組みを試してみたいので、複数Workerを持つPrestoを利用してみました。

そこで、TDのPrestoチームメンバーが公開しているPresto複数ワーカーをDockerで立ち上げるツールを使って試してみます。

GitHub - Lewuathe/docker-presto-cluster: Multiple node presto cluster on docker container

(結論としては、パフォーマンス検証がローカルでちゃんとできているわけではないです。)

検証環境

  • MacBook Pro (13-inch, 2016)
  • 2 GHz Intel Core i5
  • 8 GB 1867 MHz LPDDR3

検証項目

Treasure DataのPrestoのバージョンは、0.205となっており、2020年1月にPresto317に移行予定です。そのためここではPresto317での性能を比較します。

Distributed Sortとは何か?

分散クエリエンジンにおいて、ORDER BYという処理は鬼門です。 ORDER BYはデータの順番を単一に保証しているため、同じデータは同じ順序で結果を返す必要があります。 そのため、全てのデータを一つのサーバ(ノード)に集めて、並び替えを行うため、数千万〜数億件以上のデータがある場合に1ノードに全てのデータが集まるため、処理パフォーマンスがよくないだけなく、Prestoのようなメモリにデータを保存する処理する場合に非常に大きなメモリ消費を行う必要があります。

そのため、基本的にはORDER BYを使わないというのが鉄則です。

一方で、そうした問題を解決するための仕組みの一つがDistributed Sortです。これは1ノードでソートする前段階で複数のノードを利用してソートし、さらにソートした結果を元に1ノードでソートをするような仕組みです。 これにより、一度に全量データのソートをする必要がないことで、ピークメモリの消費量を減らすメリットがあります。

Prestoクラスタの立ち上げ

下記設定でPresto 317を3 Worker付きで立ち上げることができます。

version: '3'

services:
  coordinator:
    image: "lewuathe/presto-coordinator:317"
    ports:
      - "8080:8080"
    container_name: "coordinator"
    command: coordinator
  worker0:
    image: "lewuathe/presto-worker:317"
    container_name: "worker0"
    ports:
      - "8081:8081"
    command: worker0
  worker1:
    image: "lewuathe/presto-worker:317"
    container_name: "worker1"
    ports:
      - "8082:8081"
    command: worker1
  worker2:
    image: "lewuathe/presto-worker:317"
    container_name: "worker2"
    ports:
      - "8083:8081"
    command: worker2

そして下記を実行。

$ docker-compose up -d

Dockerが立ち上がったら、127.0.0.1:8080に接続することでPresto Web UIが参照できます。

f:id:toru-takahashi:20191202215510p:plain

Prestoクラスタへの接続

下記のjarファイルをダウンロードすることで、CLIからPrestoクラスタに接続できます。

2.2. Command Line Interface — Presto 326 Documentation

// 実行権限の設定
$ chmod +x presto-cli-326-executable.jar 
// tpchデータベースへの接続
$ ./presto-cli-326-executable.jar --server localhost:8080 --catalog tpch

接続後、下記のスキーマがあるので、今回はローカルのテストなのでtinyを利用してチェックをしていきます。

presto> SHOW SCHEMAS FROM tpch;
       Schema       
--------------------
 information_schema 
 sf1
 sf100              
 sf1000             
 sf10000            
 sf100000           
 sf300              
 sf3000             
 sf30000            
 tiny               
(10 rows)

Query 20191202_125600_00004_x4aa8, FINISHED, 4 nodes
Splits: 53 total, 53 done (100.00%)
0:08 [10 rows, 119B] [1 rows/s, 14B/s]

テスト

tinyなので、6万件ほどのデータしかない。

./presto-cli-326-executable.jar --server localhost:8080 --catalog tpch --execute "SELECT count(1) FROM tiny.lineitem"
"60175"

SELECT GROUP BYの場合

./presto-cli-326-executable.jar --server localhost:8080 --catalog tpch --execute "SELECT orderkey, count(1) FROM sf1.lineitem GROUP BY 1"
  • Execution Time 14.55s
  • Peak Total Memory 180kB

SELECT GROUP BY ORDER BYの場合

Distributed Join = True

./presto-cli-326-executable.jar --server localhost:8080 --catalog tpch --execute "SET SESSION distributed_sort=true; SELECT orderkey, count(1) FROM tiny.lineitem GROUP BY 1 ORDER BY 1"
  • Execution Time 5.06s
  • Peak Total Memory 650.86kB

Distributed Join = false

./presto-cli-326-executable.jar --server localhost:8080 --catalog tpch --execute "SET SESSION distributed_sort=false; SELECT orderkey, count(1) FROM tiny.lineitem GROUP BY 1 ORDER BY 1"
  • Execution Time 14.81s
  • Peak Total Memory 489.67kB

というわけでデータ量が少ないとテストにならない。。。

しかしDistributed Joinの有無でのわかりやすい違いとしては、実行計画の違いがある。 下記のプランをみてもらうとわかるが、Distributed Joinの方が、各ワーカーでのソート処理がは入っている分、全体としてのステージ数が増えている。 基本的には、1ノードでのソート処理が非常に重い処理になるので、ステージが別れてしまうデータ転送などのデメリットがあったとしても、Distributed Jionの方がメモリ効率だけではなく、パフォーマンスも良いのではないかとは思う。

f:id:toru-takahashi:20191202231340p:plain

f:id:toru-takahashi:20191202231353p:plain

まとめ

ローカルでメモリ食う処理をやろうとするとけっこうすぐPrestoが死ぬ。 所詮8GBしか積んでなかった・・・

なので、テストにならないのでやめましょう・・・ とはいえ、ローカルでPrestoを1コマンドで試せて便利なので、どうぞ!