たごもりすメモ

コードとかその他の話とか。

MRv2/Tezで簡単にクエリのベンチをとった

Hiveしか使ってないので以下のオプションを設定するだけで使える。楽。

SET hive.execution.engine=tez;

なお HDP 2.1 with Hive 0.10, Tez 0.4 での話です。クラスタの概要は以下の通り。

  • master x3
  • slave x20
    • Xeon(R) CPU E5-2630L v2 (6core 12Threads) x2
    • RAM 64GB
    • HDD x12

シナリオ

データの流れとしては以下のようなシナリオを想定する。

  1. 外部から非圧縮plain text tsvでHDFS内のファイルにデータが書かれる
  2. LOADで hourly テーブルに読み込む
  3. dailyで INSERT により daily テーブルに書き込む
    • このときファイルフォーマット変換や圧縮を同時に行う
    • hourly テーブルの変換済みパーティションおよび元の生データは削除する
  4. 普段のクエリは daily テーブルに対して行う

テーブルのスキーマは以下のような感じで、まあ普通にあるWebサーバのアクセスログが入っていると思おう。あとパース時にいくつかフラグを立ててBOOLEANを追加してある感じ。

-- hourly
CREATE TABLE hourly (
       hhmmss STRING,
       vhost STRING,
       path STRING     COMMENT 'with query',
       method STRING,
       status SMALLINT,
       bytes BIGINT    COMMENT 'response body size',
       duration BIGINT COMMENT 'micro sec',
       referer STRING,
       rhost STRING,
       userlabel STRING,
       agent STRING,
       flag BOOLEAN,
       f_redirection BOOLEAN,
       f_errors BOOLEAN,
       f_internal BOOLEAN,
       f_miscfile BOOLEAN,
       f_imagefile BOOLEAN,
       f_bot BOOLEAN,
       query STRING    COMMENT 'request query param json',
       opts STRING     COMMENT 'log optional values json'
)
PARTITIONED BY (service STRING, yyyymmddhh STRING, loadseq STRING)
ROW FORMAT DELIMITED
 FIELDS TERMINATED BY '\t'
 LINES TERMINATED BY '\n'
STORED AS TEXTFILE;

-- daily
CREATE TABLE daily (
       hhmmss STRING,
       vhost STRING,
       path STRING     COMMENT 'with query',
       method STRING,
       status SMALLINT,
       bytes BIGINT    COMMENT 'response body size',
       duration BIGINT COMMENT 'micro sec',
       referer STRING,
       rhost STRING,
       userlabel STRING,
       agent STRING,
       flag BOOLEAN,
       f_redirection BOOLEAN,
       f_errors BOOLEAN,
       f_internal BOOLEAN,
       f_miscfile BOOLEAN,
       f_imagefile BOOLEAN,
       f_bot BOOLEAN,
       query STRING    COMMENT 'request query param json',
       opts STRING     COMMENT 'log optional values json'
)
PARTITIONED BY (service STRING, yyyymmdd STRING)
STORED AS RCFILE;

評価

INSERT

hourlyからdailyへのINSERTにかかる所要時間を計測する。
以下のクエリを MRv2 と Tez で共に用いる。MRv2用のオプションも含めてすべて共通で設定する*1。日時については適当な範囲で指定。

SET hive.exec.dynamic.partition.mode=nonstrict;
SET hive.optimize.sort.dynamic.partition=false;
SET hive.exec.reducers.max=4096;
SET mapreduce.job.reducer=2048;
 
FROM hourly
INSERT OVERWRITE TABLE daily PARTITION (service,yyyymmdd)
  SELECT hhmmss,vhost,path,method,status,bytes,duration,referer,rhost,userlabel,agent,
         flag,f_redirection,f_errors,f_internal,f_miscfile,f_imagefile,f_bot,
         query,opts,
         service, 'yyyymmdd'
  WHERE service LIKE '%' AND yyyymmddhh LIKE 'yyyymmdd%'

非圧縮で約650GB程度のデータを対象にこのクエリを実行したところ、以下のような結果だった。

  • MRv2
    • 17分48秒 (1068秒)
  • Tez
    • 11分53秒 (713秒)

713/1068 = 0.667.. なので、まさに1.5倍ちょうど速くなっている。

SELECT

続けてこのようにして生成したdailyテーブルに以下のような集計クエリをMRv2、Tezでそれぞれ実行し、結果が出るまでの時間を計測した。このときは特に mapreduce.job.reduce などのオプションは指定していない。

SELECT
  hhmmss, COUNT(*) AS c
FROM access_log1
WHERE service LIKE '%' AND yyyymmdd='20141114'
GROUP BY hhmmss
ORDER BY c DESC LIMIT 10

結果は以下の通り。

  • MRv2
    • 436秒
  • Tez
    • 179秒

179/436 = 0.410.. なので2.5倍速い。このクエリはMapReduceだと2段のmapreduceに分解されて実行されることはHive大好きなみなさんならクエリを見た瞬間にわかると思うが、やはりそのようなクエリにおいては1ジョブで効率的に実行できるTezが更に有利になる。

そしてこのような単純な集計クエリは非常に多く実行されている。

まとめ

Tezいいんじゃないですかね! たまに落ちるという話も聞きますが!

ただResourceManagerからHistory URLたどっていっても何も見えないとか、いろいろ実行状況わかんないのは自分の設定のせいなのかなあ。これはトラブル時にだいぶ困る感じがしますね。

*1:当然だが hive.execution.engine=tez は除く