2013年10月1日火曜日

HadoopでHDFS化したログをHiveとImpalaで高速検索


◆ 目的
HadoopでHDFSを組んだ環境に、HiveとImpalaを導入し、
高速ログ検索を実現させる。
Hdoop、Hive、Impalaの設定はすべて終わっており、
利用できる状態にあるものとする。

ここではどのようにログを取り込み、
検索を実施するのか一通りの手順を記載する。

Hadoop、Hiveは耳にしたことがあっても、
まだImpalaについては知らないという人もいるだろうか。
Impalaについてのまとまった記事



◆ 環境
説明するための環境を定義しておく。

・ログの収集対象であるアプリケーションサーバ名
app1
app2
app3


・上記アプリケーションサーバのログ出力形式
ホスト名と日時が付与され、1時間おきにローテートされる。
app_app1_2013100100.log.gz ←app1の2013年10月01日00時ログ
app_app1_2013100101.log.gz ←app1の2013年10月01日01時ログ
app_app1_2013100102.log.gz ←app1の2013年10月01日02時ログ

app_app2_2013100100.log.gz
app_app2_2013100101.log.gz
app_app2_2013100102.log.gz

app_app3_2013100100.log.gz
app_app3_2013100101.log.gz
app_app3_2013100102.log.gz


・ログ収集サーバ
log1サーバ
log2サーバ
log3サーバ




何台いてもいいのだが、これらサーバ群の特定領域をHDFS化させている。
HDFS領域
/log/

そしてこのサーバ上でHiveとImpalaを動作させている。

appサーバ群のログを取得する際の一時的な保管場所は以下をする。
HDFS化していないローカルディスク(log1にあるとする)である。
/tmp/log/



◆ ログ投入事前作業
・テーブル作成
logサーバ群上でテーブルを作成する。
当然テーブルを作成するのは最初だけである。

どういったログ検索を事前に行うか決まっていないため、
柔軟性を優先し、ログはそのままmsgというカラムに入れる。
パーティションとして日時を付与する。dtと名称する。

logサーバ群のマスタ上で実行する。
$ sudo -u hdfs hive
> CREATE TABLE app_log    (msg STRING) PARTITIONED BY (dt STRING) ROW FORMAT DELIMITED LINES TERMINATED BY '\n';
> CREATE TABLE app_impala (msg STRING) PARTITIONED BY (dt STRING) ROW FORMAT DELIMITED LINES TERMINATED BY '\n' STORED AS SEQUENCEFILE;


・テーブルの確認
> SHOW TABLES;
log
log_impala

> DESC app_log;
msg string
dt string

> DESC app_log_impala;
msg string
dt string



◆ ローカルディレクトリへのログ収集
まずはlogサーバのローカルディスクである/tmp/log/へ
appサーバ群のログを持ってくる。
scpなりで定期的にバッチ処理させればよい。
expectを利用してscpを自動化
sshで多段接続をしてscp



◆ HDFSへのログ投入
ローカルディスクである/tmp/log/からログをHDFSへ取り込む。
時間ごとのログ単位でパーティションを切っていく。

・HDFS化
(2013年10月01日00時のログを投入する場合の実行例)
% sudo -u hdfs /usr/bin/hive -e "LOAD DATA LOCAL INPATH '/tmp/log/*2013100100*' \
INTO TABLE app_log PARTITION (dt='2013100100')"

(2013年10月01日01時のログを投入する場合の実行例)
% sudo -u hdfs /usr/bin/hive -e "LOAD DATA LOCAL INPATH '/tmp/log/*2013100101*' \
INTO TABLE app_log PARTITION (dt='2013100101')"

(2013年10月01日02時のログを投入する場合の実行例)
% sudo -u hdfs /usr/bin/hive -e "LOAD DATA LOCAL INPATH '/tmp/log/*2013100102*' \
INTO TABLE app_log PARTITION (dt='2013100102')"

※取り込み元のローカルパス名に''必須


・パーティションの設定の確認
$ sudo -u hdfs hive
> SHOW PARTITIONS app_log;
dt=2013100100
dt=2013100101
dt=2013100102


・ファイルが取り込まれたことの確認
% hdfs dfs -ls -R /log/app_log/
/log/app_log/dt=2013100100/app_app1_2013100100.log.gz
/log/app_log/dt=2013100101/app_app1_2013100101.log.gz
/log/app_log/dt=2013100102/app_app1_2013100102.log.gz

/log/app_log/dt=2013100100/app_app2_2013100100.log.gz
/log/app_log/dt=2013100101/app_app2_2013100101.log.gz
/log/app_log/dt=2013100102/app_app2_2013100102.log.gz

/log/app_log/dt=2013100100/app_app3_2013100100.log.gz
/log/app_log/dt=2013100101/app_app3_2013100101.log.gz
/log/app_log/dt=2013100102/app_app3_2013100102.log.gz



◆ Impalaへのログ投入
HDFSにログが格納された。
それをHive経由で取得し、Impalaのテーブルに入れ込む。

・Impalaへの取り込み
(2013年10月01日00時のログを投入する場合の実行例)
sudo -u hdfs /usr/bin/hive -hiveconf hive.exec.compress.output=true \
-hiveconf hive.stats.autogather=false \
-hiveconf mapred.max.split.size=256000000 \
-hiveconf mapred.output.compression.type=BLOCK \
-hiveconf mapred.output.compression.codec=org.apache.hadoop.io.compress.SnappyCodec \
-e "INSERT INTO TABLE app_log_impala PARTITION (dt='20131000') \ 
SELECT msg FROM app_log where dt='2013100100'"
※オプションは各環境ごとに変えればよい。

(2013年10月01日01時のログを投入する場合の実行例)
sudo -u hdfs /usr/bin/hive -hiveconf hive.exec.compress.output=true \
-hiveconf hive.stats.autogather=false \
-hiveconf mapred.max.split.size=256000000 \
-hiveconf mapred.output.compression.type=BLOCK \
-hiveconf mapred.output.compression.codec=org.apache.hadoop.io.compress.SnappyCodec \
-e "INSERT INTO TABLE app_log_impala PARTITION (dt='2013100101') \ 
SELECT msg FROM app_log where dt='2013100101'"

(2013年10月01日02時のログを投入する場合の実行例)
sudo -u hdfs /usr/bin/hive -hiveconf hive.exec.compress.output=true \
-hiveconf hive.stats.autogather=false \
-hiveconf mapred.max.split.size=256000000 \
-hiveconf mapred.output.compression.type=BLOCK \
-hiveconf mapred.output.compression.codec=org.apache.hadoop.io.compress.SnappyCodec \
-e "INSERT INTO TABLE app_log_impala PARTITION (dt='2013100102') \ 
SELECT msg FROM app_log where dt='2013100102'"


・ファイルが取り込まれたことの確認
% hdfs dfs -ls -R /log/app_log_impala/



◆ 削除処理
ログを削除する手順も残しておく。

・パーティションごと削除する場合
% sudo -u hdfs /usr/bin/hive -e "ALTER TABLE app_log DROP PARTITION (dt='2013100100')"
% sudo -u hdfs /usr/bin/hive -e "ALTER TABLE app_log DROP PARTITION (dt='2013100101')"
% sudo -u hdfs /usr/bin/hive -e "ALTER TABLE app_log DROP PARTITION (dt='2013100102')"

% sudo -u hdfs /usr/bin/hive -e "ALTER TABLE app_log_impala DROP PARTITION (dt='2013100100')"
% sudo -u hdfs /usr/bin/hive -e "ALTER TABLE app_log_impala DROP PARTITION (dt='2013100101')"
% sudo -u hdfs /usr/bin/hive -e "ALTER TABLE app_log_impala DROP PARTITION (dt='2013100102')"


・テーブルごと削除する場合
% sudo -u hdfs /usr/bin/hive -e "DROP TABLE log"
% sudo -u hdfs /usr/bin/hive -e "DROP TABLE log_impala"



◆ 検索
・Hiveでの検索例
% sudo -u hdfs hive
> SELECT msg FROM app_log WHERE dt='2013100100' AND msg LIKE '%hoge%';
> SELECT msg FROM app_log WHERE dt REGEXP '2013100[012]' AND msg LIKE '%hoge%' AND msg LIKE '%piyo%';

 シェルモードに入らない場合は-eオプションを使う。
% sudo -u hdfs hive -e "SELECT ~"


・停止処理
検索処理実行後Killコマンドが発行される。
Ctrl+Cで抜けただけではバックエンドで検索が続けられるため、
提示されたこのコマンドで停止させること。
Kill Command = $HADOOP_PATH/bin/hadoop job -kill job_201310012000_0001


・Impalaでの検索
% sudo -u hdfs -i impala-shell -r
> SELECT ~
検索対象テーブルとしてapp_log_impalaを指定する以外はhiveと違いはない。

-rオプションを付与しないとメタデータがずっとキャッシュされる

シェルモードに入らない場合は-qオプションを使う。
% /usr/bin/impala-shell -i -r -q "SELECT ~"
オプションの詳細参照

Hiveと違ってImpalaはctrl+cで抜ければ全ノードのimpalad処理が停止する