Apache Hadoop 3 と Apache Hive 3 を Homebrew で macOS にインストールする


概要

  • macOS 1台に Homebrew で Apache Hadoop と Apache Hive をインストールし、シングルノードで疑似分散モードのクラスターを構築する
  • Hadoop の分散ファイルシステム HDFS (Hadoop Distributed File System) を使用する
  • Apache Hive から HiveQL でテーブル作成・データ追加・データ参照する
  • 今回の環境: macOS Catalina + Java 8 (AdoptOpenJDK 1.8.0_265) + Apache Hadoop 3.3.0 + Apache Hive 3.1.2

Java 8 のインストール

Java 8 をインストールしていない場合は、Homebrew などでインストールしておき、JAVA_HOME となるべきディレクトリの場所を確認しておく。

$ brew tap AdoptOpenJDK/openjdk

$ brew cask install adoptopenjdk8

$ /usr/libexec/java_home -v 1.8
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home

Apache Hive が Java 9 以降に対応していないため、Java 9 以降を使用すると以下のようなエラーが発生するので注意。

Exception in thread "main" java.lang.ClassCastException: class jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to class java.net.URLClassLoader (jdk.internal.loader.ClassLoaders$AppClassLoader and java.net.URLClassLoader are in module java.base of loader 'bootstrap')
  at org.apache.hadoop.hive.ql.session.SessionState.<init>(SessionState.java:413)
  at org.apache.hadoop.hive.ql.session.SessionState.<init>(SessionState.java:389)
  at org.apache.hadoop.hive.cli.CliSessionState.<init>(CliSessionState.java:60)
  at org.apache.hadoop.hive.cli.CliDriver.run(CliDriver.java:705)
  at org.apache.hadoop.hive.cli.CliDriver.main(CliDriver.java:683)
  at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.base/java.lang.reflect.Method.invoke(Method.java:564)
  at org.apache.hadoop.util.RunJar.run(RunJar.java:323)
  at org.apache.hadoop.util.RunJar.main(RunJar.java:236)

Apache Hadoop と Apache Hive のインストール

Homebrew で Apache Hive をインストールすると依存関係で Apache Hadoop もインストールされる。

$ brew install hive

Hadoop のバージョンを確認。

$ hadoop version
Hadoop 3.3.0
Source code repository https://gitbox.apache.org/repos/asf/hadoop.git -r aa96f1871bfd858f9bac59cf2a81ec470da649af
Compiled by brahma on 2020-07-06T18:44Z
Compiled with protoc 3.7.1
From source with checksum 5dc29b802d6ccd77b262ef9d04d19c4
This command was run using /usr/local/Cellar/hadoop/3.3.0/libexec/share/hadoop/common/hadoop-common-3.3.0.jar

Hive のバージョンを確認。

$ hive --version
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/usr/local/Cellar/hive/3.1.2_1/libexec/lib/log4j-slf4j-impl-2.10.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/usr/local/Cellar/hadoop/3.3.0/libexec/share/hadoop/common/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
Hive 3.1.2
Git git://HW13934/Users/gates/tmp/hive-branch-3.1/hive -r 8190d2be7b7165effa62bd21b7d60ef81fb0e4af
Compiled by gates on Thu Aug 22 15:01:18 PDT 2019
From source with checksum 0492c08f784b188c349f6afb1d8d9847

疑似分散モード (pseudo-distributed mode) の設定

設定ファイルは /usr/local/Cellar/hadoop/3.3.0/libexec/etc/hadoop にある。
core-site.xml と hdfs-site.xml を以下のように書き換える。

core-site.xml

core-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
  <property>
    <name>fs.defaultFS</name>
    <value>hdfs://localhost:9000</value>
  </property>
</configuration>

hdfs-site.xml

hdfs-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
  <property>
    <name>dfs.replication</name>
    <value>1</value>
  </property>
</configuration>

hadoop.tmp.dir の変更

Hadoop で使用するデータが格納されているディレクトリはデフォルトでは /tmp/hadoop-${user.name} になっているため、macOS の再起動等のタイミングでデータが失われる。

必要に応じて core-site.xml に以下のような hadoop.tmp.dir についての設定を追加することでデータが格納されているディレクトリを指定することができる。

<property>
  <name>hadoop.tmp.dir</name>
  <value>/Users/foo/hadoop</value>
</property>

JAVA_HOME の設定

/usr/local/Cellar/hadoop/3.3.0/libexec/etc/hadoop にある hadoop-env.sh に JAVA_HOME を記述する。
ここで指定した JAVA_HOME の JVM が Apache Hive からも使われる。

以下は Homebrew でインストールした AdoptOpenJDK 8 の JAVA_HOME を指定する例。

export JAVA_HOME="/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home"

リモートログインの許可

macOS の「システム環境設定」→「共有」の「リモートログイン」にチェックを入れてアクセスを許可する必要がある。

リモートログインが許可されていない場合、Hadoop 起動時に以下のようなエラーが発生する。

$ /usr/local/Cellar/hadoop/3.3.0/sbin/start-dfs.sh
Starting namenodes on [localhost]
localhost: ssh: connect to host localhost port 22: Connection refused
Starting datanodes
localhost: ssh: connect to host localhost port 22: Connection refused
Starting secondary namenodes [mymacos.local]
mymacos.local: ssh: connect to host mymacos.local port 22: Connection refused

パスフレーズなし ssh の設定

パスフレーズなしの秘密鍵・公開鍵を作成し、ssh 接続を許可するリストに追加する。

$ ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
$ chmod 0600 ~/.ssh/authorized_keys

すでに ~/.ssh/id_rsa ファイルが存在しており上書きしたくない場合は、任意のファイル名で作成しても良い。
例えば id_rsa_for_my_hadoop というファイル名を指定する。

$ ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa_for_my_hadoop
$ cat ~/.ssh/id_rsa_for_my_hadoop.pub >> ~/.ssh/authorized_keys
$ chmod 0600 ~/.ssh/authorized_keys

任意のファイル名で作成した場合は、Hadoop が ssh を使用する際に指定するオプションを記述できる環境変数 HADOOP_SSH_OPTS にて、秘密鍵のパスを使用するように指定する。
HADOOP_SSH_OPTS は hadoop-env.sh に記述する。

$ export HADOOP_SSH_OPTS="-i ~/.ssh/id_rsa_for_my_hadoop"

パスフレーズなしでローカルホストに ssh できない場合、Hadoop 起動時に以下のようなエラーが発生する。

$ /usr/local/Cellar/hadoop/3.3.0/sbin/start-dfs.sh
Starting namenodes on [localhost]
localhost: Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.
localhost: foo@localhost: Permission denied (publickey,password,keyboard-interactive).
Starting datanodes
localhost: foo@localhost: Permission denied (publickey,password,keyboard-interactive).
Starting secondary namenodes [mymacos.local]
mymacos.local: Warning: Permanently added 'mymacos.local' (ECDSA) to the list of known hosts.
mymacos.local: [email protected]: Permission denied (publickey,password,keyboard-interactive).

ファイルシステムのフォーマット

Hadoop で使用する環境を HDFS (Hadoop Distributed File System) でフォーマットする。

$ hdfs namenode -format

Hadoop の起動

HDFS を管理する NameNode (メタ情報) と DataNode (データの実体) を起動する。

$ /usr/local/Cellar/hadoop/3.3.0/sbin/start-dfs.sh

「WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable」という警告が出るが、このネイティブライブラリは macOS には対応していないので無視する。

Apache Hadoop 3.3.0 – Native Libraries Guide

The native hadoop library is supported on *nix platforms only. The library does not to work with Cygwin or the Mac OS X platform.

Hive で使用するディレクトリの作成

Hive で使用するディレクトリを HDFS 上に作成する。

$ hadoop fs -mkdir /tmp
$ hadoop fs -mkdir /user
$ hadoop fs -mkdir /user/hive
$ hadoop fs -mkdir /user/hive/warehouse
$ hadoop fs -chmod g+w /tmp
$ hadoop fs -chmod g+w /user/hive/warehouse

メタストアの作成

Hive に関する情報を管理するメタストアを作成する。

$ schematool -initSchema -dbType derby
(中略)
Metastore connection URL:  jdbc:derby:;databaseName=metastore_db;create=true
Metastore Connection Driver :  org.apache.derby.jdbc.EmbeddedDriver
Metastore connection User:   APP
Starting metastore schema initialization to 3.1.0
Initialization script hive-schema-3.1.0.derby.sql
(中略)
Initialization script completed
schemaTool completed

Hive CLI の起動

Hive CLI をインタラクティブモードで起動する。

$ hive

データベースの作成

create database でデータベースを作成する。

hive> create database foo_database;
OK
Time taken: 0.696 seconds
hive> show databases;
OK
default
foo_database
Time taken: 0.159 seconds, Fetched: 2 row(s)

テーブルの作成

create table でテーブルを作成する。
読み込むデータのフォーマットとして、カラムをカンマ区切り、レコードを改行コードで区切るように指定する。

hive> create table foo_database.foo_table(
    >   id int,
    >   name string,
    >   updated_at timestamp)
    > row format delimited
    > fields terminated by ','
    > lines terminated by '\n';
OK
Time taken: 0.887 seconds
hive> show tables from foo_database;
OK
foo_table
Time taken: 0.058 seconds, Fetched: 1 row(s)

Hive CLI から抜けるときは exit; を入力する。

hive> exit;

データのロード

カラムをカンマ区切り、レコードを改行コードで区切るように指定した CSV ファイルを用意する。
今回は /Users/foo/data.csv というパスに以下の内容のファイルを設置した。

data.csv
100,Alice,2020-02-29 00:00:00.000000001
200,ボブ,1999-12-31 23:59:59

load data で CSV ファイルのパスを指定してテーブルにファイルを読み込む。

hive> LOAD DATA LOCAL INPATH 'file:/Users/foo/data.csv' OVERWRITE INTO TABLE foo_database.foo_table;
Loading data to table foo_database.foo_table
OK
Time taken: 1.307 seconds

データの参照

クエリ実行時にカラム名を出力するように設定。

hive> set hive.cli.print.header=true;

select でレコードを取得して表示する。

hive> select * from foo_database.foo_table;
OK
foo_table.id    foo_table.name  foo_table.updated_at
100     Alice   2020-02-29 00:00:00.000000001
200     ボブ     1999-12-31 23:59:59
Time taken: 0.131 seconds, Fetched: 2 row(s)

Hadoop の停止

$ /usr/local/Cellar/hadoop/3.3.0/sbin/stop-dfs.sh

参考資料

Homebrew

Apache Hadoop

Apache Hive