Edited at

hadoop & hive & metastore on mysql & S3AFileSystem をMac上にて動かすまで

More than 1 year has passed since last update.


各種バージョン

この記事の時点でのAmazon EMRは

Hadoop ディストリビューションは、Amazon 2.7.3となっていてhadoop 2.7.3で

アプリケーションは、Hive 2.1.1, Tez 0.8.4 なので極力これに近付ける


  • MacOS Sierra 10.12.3

  • Java 1.8

  • hadoop 2.7.3

  • hive 2.1.1

  • mysql 5.5.49

EMRのバージョンと関連バージョンの確認はこちら

https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-release-components.html

alt



インストール作業


1.java

# javaをインストール

$ brew cask install java

# JAVA_HOMEを設定
$ echo 'export JAVA_HOME=`/usr/libexec/java_home -v 1.8`' >> ~/.bash_profile
$ echo 'export PATH="PATH=$JAVA_HOME/bin:$PATH"' >> ~/.bash_profile

# バージョンを確認
$ java -version
java version "1.8.0_112"
Java(TM) SE Runtime Environment (build 1.8.0_112-b16)
Java HotSpot(TM) 64-Bit Server VM (build 25.112-b16, mixed mode)


2.mysql

# 既に入っていたら消す my.cnfとかも消す方が吉

$ brew uninstall mysql

# インストール
$ brew tap homebrew/versions
$ brew install mysql55

# パスを追加
$ echo 'export PATH="/usr/local/opt/mysql@5.5/bin:$PATH"' >> ~/.bash_profile

# mysql起動
$ brew services start mysql@5.5

# バージョンを確認
$ mysql -u root
Server version: 5.5.49 Homebrew


  • ハマりポイント

# 5.5系でないと、hive 2.1.0のmetastoreの作成が、

# InnoDBでPK・Uniqueカラムのフィールド長の制限に引っ掛かる
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes


3.hadoop

# インストール

$ brew install hadoop

# 環境変数を設定
$ echo 'export HADOOP_HOME="/usr/local/Cellar/hadoop/2.7.3"' >> ~/.bash_profile
$ echo 'export HADOOP_CONF_DIR="$HADOOP_HOME/libexec/etc/hadoop"' >> ~/.bash_profile

# バージョンを確認
$ hadoop version
Hadoop 2.7.3


4.hive

# brewでは、2.1.0までしかないので、本家からダウンロードする

$ curl -O http://ftp.yz.yamagata-u.ac.jp/pub/network/apache/hive/hive-2.1.1/apache-hive-2.1.1-bin.tar.gz

# 解凍
$ tar xvzf apache-hive-2.1.1-bin.tar.gz

# インストール (今回わかりやすくするため、/usr/local/Cellar/hive/2.1.1へ配置)
$ sudo mv apache-hive-2.1.1-bin /usr/local/Cellar/hive/2.1.1

# 環境変数を設定
$ echo 'export HIVE_HOME="/usr/local/Cellar/hive/2.1.1"' >> ~/.bash_profile
$ echo 'export PATH="PATH=$HIVE_HOME/bin:$PATH"' >> ~/.bash_profile

# バージョンを確認
$ hive -H
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/usr/local/Cellar/hive/2.1.1/lib/log4j-slf4j-impl-2.4.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]

2.1.1でないと、パーティショニング MSCK REPAIR TABLEがエラーになる。

ここまでで、インストールと環境設定が終わり、次は各種設定



設定作業


1.localhostへのssh接続できるようにする設定

Macの場合

システム環境設定 → 共有 から、「リモートログイン」にチェックを入れます。

以下のコマンドでauthorized_keysを追加します。

※まだ公開鍵を作成していない場合はssh-keygenで作成します。

$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

$ chmod 600 ~/.ssh/authorized_keys

以下のコマンドでlocalhostにsshで接続できることを確認します。

$ ssh localhost


2.HDFS設定

疑似分散モードでHDFSを構成します。


$HADOOP_CONF_DIR/core-site.xml

<configuration>

<property>
<name>fs.defaultFS</name>
<value>hdfs://localhost:9000</value>
</property>
</configuration>


$HADOOP_CONF_DIR/hdfs-site.xml

<configuration>

<property>
<name>dfs.name.dir</name>
<value>/var/lib/hdfs/name</value>
</property>
<property>
<name>dfs.data.dir</name>
<value>/var/lib/hdfs/data</value>
</property>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>


3.S3上のファイルへのアクセス設定

hadoopがS3にアクセス出来るようにします。


3.1.awsのjarにパスを通す

S3AFileSystemを使えるようにするため、「hadoop-aws-2.7.2.jar」にCLASSPATHを通します。

hadoop-env.shに以下を追記します。


$HADOOP_CONF_DIR/hadoop-env.sh

export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:$HADOOP_HOME/libexec/share/hadoop/tools/lib/*



3.2.S3AFileSystemとアクセスキーを設定


$HADOOP_CONF_DIR/yarn-site.xml

<configuration>

<property>
<name>fs.s3a.impl</name>
<value>org.apache.hadoop.fs.s3a.S3AFileSystem</value>
</property>
<property>
<name>fs.s3a.access.key</name>
<value>※ここにAWSのアクセスキー※</value>
</property>
<property>
<name>fs.s3a.secret.key</name>
<value>※ここにAWSのシークレットキー※</value>
</property>
</configuration>


4.mysqlをmetastore用のデータベースとして設定


4.1.データベースを作成

$ mysql -u root

# databaseのcharactersetはlaten1にしておく必要があります。
# 以下を参照
# http://tagomoris.hatenablog.com/entry/20110310/1299738606
mysql> create database metastore default character set 'latin1';
mysql> use metastore;
mysql> create user 'hive'@'localhost' identified by 'hive';
mysql> grant select, insert, update, delete, alter, create, index, references on metastore.* to 'hive'@'localhost';


4.2.jdbcドライバをhiveのライブラリへ追加

# ダウンロード

$ curl -O https://cdn.mysql.com//Downloads/Connector-J/mysql-connector-java-5.1.40.tar.gz

# 解凍
$ tar xvzf mysql-connector-java-5.1.40.tar.gz

# hiveのライブラリディレクトリに配置
$ mv mysql-connector-java-5.1.40/mysql-connector-java-5.1.40-bin.jar $HIVE_HOME/lib


4.3.mysqlのmetastoreデータベースをhadoopのメタストアとして使用するための設定


$HIVE_HOME/conf/hive-site.xml

<configuration>

<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://localhost/metastore?useSSL=false</value>
</property>
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>hive</value>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>hive</value>
</property>
<property>
<name>datanucleus.fixedDatastore</name>
<value>false</value>
</property>
<property>
<name>hive.exec.local.scratchdir</name>
<value>/tmp/hive</value>
</property>
<property>
<name>hive.downloaded.resources.dir</name>
<value>/tmp/hive</value>
</property>
<property>
<name>hive.querylog.location</name>
<value>/tmp/hive</value>
</property>

<!-- hiveでdynamodbを利用する場合の設定 -->
<property>
<name>dynamodb.endpoint</name>
<value>http://localhost:8000</value>
</property>
<property>
<name>dynamodb.awsAccessKeyId</name>
<value>hoge</value>
</property>
<property>
<name>dynamodb.awsSecretAccessKey</name>
<value>hogehoge</value>
</property>
</configuration>



4.4.metastoreの初期化

# schematoolで初期化を実行します。

$ schematool -dbType mysql -initSchema -verbose


5.HDFSのフォーマット

$ hdfs namenode -format


6.namenodeの起動とhdfsとS3への接続確認

以下のコマンドでHDFSを起動します。

YARN (Yet-Another-Resource-Negotiator)も起動したいので、 $HADOOP_HOME/sbin/start-all.shを実行する。

※停止する場合は $HADOOP_HOME/sbin/stop-all.sh

# パスワード聞かれたら、入力する

$ $HADOOP_HOME/sbin/start-all.sh

# hdfsへの接続確認(この時点では、まだHDFS上にファイルが無いので一覧には何も表示されません。)
$ hadoop fs -ls /

# s3のバケットが見れるかも確認
$ hadoop fs -ls s3a://※ここにS3のbucket名※/

お疲れ様です。

ここまでで、各種設定が終わりました。

次は、S3上に配置したTSVファイルに対してhiveでクエリを投げてみます。



S3上に配置したTSVファイルに対してhiveでクエリを投げてみます!


1.S3バケットの状態

# S3バケットには、カレンダーマスターを年でパーティショニングした状態で、TSVファイルを置いてある

$ hadoop fs -ls s3a://hivelocal/input/calendar_master/
Found 2 items
drwxrwxrwx - 0 1970-01-01 09:00 s3a://hivelocal/input/calendar_master/year=2016
drwxrwxrwx - 0 1970-01-01 09:00 s3a://hivelocal/input/calendar_master/year=2017

# こんな感じ
$ hadoop fs -ls s3a://hivelocal/input/calendar_master/year=2016/
Found 1 items
-rw-rw-rw- 1 5855 2017-02-19 14:06 s3a://hivelocal/input/calendar_master/year=2016/calendar_master.csv
$ hadoop fs -ls s3a://hivelocal/input/calendar_master/year=2017/
Found 1 items
-rw-rw-rw- 1 5840 2017-02-19 14:06 s3a://hivelocal/input/calendar_master/year=2017/calendar_master.csv


2.hiveQLを準備

データベース作って、テーブル作って、ロードして、パーティショニングするスクリプト


/src/hive/create_calendar_master.q

-- データベースを作成

CREATE DATABASE IF NOT EXISTS HIVE_TEST;

USE HIVE_TEST;

-- カレンダーマスタテーブルを削除
DROP TABLE IF EXISTS calendar_master;

-- カレンダーマスタテーブルを作成
CREATE EXTERNAL TABLE IF NOT EXISTS calendar_master (
dt date, -- 日付
yobi tinyint, -- 曜日
shukujitsu_code tinyint -- 祝日コード
)
PARTITIONED BY (`year` string)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE
LOCATION '${INPUT}/calendar_master/';

-- テーブルにすべてのパーティションを挿入
MSCK REPAIR TABLE calendar_master;



3.テスト用のシェルを用意


/test.sh

#!/bin/sh

# hiveコマンドのオプション debug
OPTS=-v
# hiveQLソースがあるフォルダ
SRC=./src/hive
# INPUTデータがある、S3バケット指定
INPUT=s3a://hivelocal/input
# OUTPUTデータの出力先S3バケット指定
OUTPUT=s3a://hivelocal/output

hive $OPTS -f $SRC/create_calendar_master.q -dINPUT=$INPUT || { echo oops!; exit 1; }



4.いざ実行!

$ sh test.sh 

CREATE DATABASE IF NOT EXISTS HIVE_TEST
OK
Time taken: 1.738 seconds

USE HIVE_TEST
OK
Time taken: 0.019 seconds

DROP TABLE IF EXISTS calendar_master
OK
Time taken: 0.127 seconds

CREATE EXTERNAL TABLE IF NOT EXISTS calendar_master (
dt date, -- 日付
yobi tinyint, -- 曜日
shukujitsu_code tinyint -- 祝日コード
)
PARTITIONED BY (`year` string)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE
LOCATION '${INPUT}/calendar_master/'
OK
Time taken: 1.667 seconds

MSCK REPAIR TABLE calendar_master
OK
Partitions not in metastore: calendar_master:year=2016 calendar_master:year=2017
Repair: Added partition to metastore calendar_master:year=2016
Repair: Added partition to metastore calendar_master:year=2017
Time taken: 3.469 seconds, Fetched: 3 row(s)

お! Partitionも作られてるね〜イイね!


5.確認してみる

$ hive

# データベースあった!
hive> use HIVE_TEST;
OK
Time taken: 1.254 seconds

# テーブルもあった!
hive> show tables;
OK
calendar_master
Time taken: 0.283 seconds, Fetched: 1 row(s)

# パーティションもあった!
hive> show partitions calendar_master;
OK
year=2016
year=2017
Time taken: 0.266 seconds, Fetched: 2 row(s)

# TSVのデータも取り込まれている!
hive> select * from calendar_master;
OK
2016-01-01 6 1 2016
2016-01-02 7 0 2016
2016-01-03 1 0 2016
2016-01-04 2 0 2016
2016-01-05 3 0 2016
〜省略

2016-12-30 6 0 2016
2016-12-31 7 0 2016
2017-01-01 1 1 2017
2017-01-02 2 9 2017
2017-01-03 3 0 2017
2017-01-04 4 0 2017
2017-01-05 5 0 2017

Time taken: 0.251 seconds, Fetched: 731 row(s)
hive>

やった〜!

お次は、S3上に出力できるか試せたら、追記します。


終わりに

hadoop,hiveは、構成がいろいろ出てて、初心者にはかなりハードル高い感じでした。

CDH? EMR なんだかんだ・・・

docker使えば一発じゃんとかあるかもしれませんが

今回は、理解を進める上でも、オールインワンは使わずやってみました。