HAWQ を CDH で動かす

HAWQとは
-----------------------
[HAWQ](http://pivotal.io/big-data/white-paper/a-true-sql-engine-for-hadoop-pivotal-hd-hawq)は[Pivotal](http://pivotal.io/)が開発した[Hadoop](http://hadoop.apache.org/)上で動作するSQL実行エンジンです。
現在はApacheに寄贈され、[Apache HAWQ](http://hawq.incubator.apache.org/)として公開されています。
HAWQに近い位置付けのものには、[Cloudera](http://www.cloudera.com/)が主導する[Impala](http://impala.io/)があります。
HAWQの中身は[PostgreSQL](http://www.postgresql.org/)をベースに分散環境に対応した[Greenplum](http://pivotal.io/big-data/pivotal-greenplum)をHadoopに対応したものと考えればよいと思います。
PostgreSQLをベースにしていることから、数あるSQL on Hadoopの中でもSQLへの準拠レベルが高いことが特徴になっています。
詳細は[Enterprise SQL on Hadoop with Pivotal HDB](https://pivotal.io/big-data/hadoop/sql-on-hadoop)が参考になります。

PivotalとODPi
-----------------------
[ODPi](https://www.odpi.org/)はHadoopの相互運用性を目的として[Hortonworks](http://hortonworks.com/)、Pivotalを中心に設立された団体です。
Hadoopはディストリビューションが乱立していて、それぞれが独自の機能を組み込むため、相互運用性が危うくなっています。
そのような状況の中、コア仕様を定義することで相互運用性を維持しようというのがODPiの趣旨です。
しかし実態は、ODPiの各社がHortonworksの[HDP](http://hortonworks.com/products/hdp/)をOEMとして採用する状況にあり、マーケティング戦略であるとの批判があります。
実際、Pivotalは自身のディストリビューションである[Pivotal HD](http://pivotalhd.docs.pivotal.io/)をHDPベースに切り替えています。
そのような事情から、HAWQはPivotal HDやHDPへ容易にインストールすることができます。[^1]
インストールはプロビジョニング/管理ツールである[Ambari](https://ambari.apache.org/)を使用して、ウィザードに従ってクリックしていくだけです。

[^1]: [Install HAWQ and PXF with Ambari](http://hawq.docs.pivotal.io/docs-hawq/topics/install-ambari.html)

HAWQをインストールする前に
-----------------------
HAWQはHadoop上で動作するSQL実行エンジンなので、Clouderaの[CDH](https://www.cloudera.com/products/apache-hadoop/key-cdh-components.html)でも動作するはずです。
しかし、AmbariがHDPにしか対応していないため[^2]、Ambariを使ってCDHのHadoopクラスタにインストールすることができません。
そこで今回はHAWQを手動でインストールすることにします。
HAWQは[ビルド環境](https://cwiki.apache.org/confluence/display/HAWQ/Build+and+Install)を整えるのも一苦労なので、Pivotalが配布している[Pivotal HDB](https://network.pivotal.io/products/pivotal-hdb)を使用します。
なお、ダウンロードには[Pivotal Network](https://network.pivotal.io/)への登録が必要です。

[^2]: [[AMBARI-3524] Set up generic puppet module architecture to manage both HDP and CDH (and Apache?) stacks](https://issues.apache.org/jira/browse/AMBARI-3524)

HAWQのインストール
-----------------------
HAWQを手動でインストールする方法は[Installing HAWQ from the Command Line](http://hawq.docs.pivotal.io/docs-hawq/topics/InstallingHAWQ.html)に書かれています。
多少、空気を読んで手順を飛ばしたり、追加したりしながら進めます。

まず始めに、マスタに最低限の環境を構築します。
これはマスタの資材を、pssh/pscpのようなツールを用いて、スレーブにインストールするためです。
このツールを使うために、最初のインストールが必要なわけです。

ダウンロードしたtarファイルを解凍してrpmをインストールします。
gpadminユーザー/グループが無いという警告は無視して構いません。

``` console
# tar xvf PADS-1.3.1.1-19631-rhel5_x86_64.tgz
# rpm -ivh PADS-1.3.1.1/hawq-1.3.1.1-19631.x86_64.rpm
```

HAWQのスクリプトを.bash_profileに追加します。

``` console
# echo . /usr/local/hawq/greenplum_path.sh >> .bash_profile
# . .bash_profile
```

全ノードにHAWQをインストールします。ホスト名の一覧を用意して、まとめてインストールを行います。(マスタにHAWQを2回インストールしていますが、気にしないことにします...)
この過程で、鍵交換によりrootユーザーのパスワードレスログインが許可されます。

``` console
# mkdir /opt/servers
# vi /opt/servers/all_hosts
hawq-ma01          # マスタ
hawq-sl01          # スレーブ
hawq-sl02          # 〃
:

# gpssh-exkeys -f /opt/servers/all_hosts
# gpscp -f /opt/servers/all_hosts PADS-1.3.1.1/hawq-1.3.1.1-19631.x86_64.rpm =:~/
# gpssh -f /opt/servers/all_hosts -e "rpm -ivh hawq-1.3.1.1-19631.x86_64.rpm"
```

gpadminユーザーを作成します。
Hadoopと連携して動かす場合は、hadoopグループに所属したほうが使い勝手がよいです。
パスワードはご自由に変更してください。

``` console
# gpssh -f /opt/servers/all_hosts -e 'useradd -d /home/gpadmin -s /bin/bash -g hadoop -m gpadmin'
# gpssh -f /opt/servers/all_hosts -e 'echo -e "gpadmin\ngpadmin" | passwd gpadmin'
```

gpadminユーザーにsuして.bash_profileにパスの設定を行います。
ここでgpadminユーザーのパスワードレスログインが許可されます。

``` console
# su - gpadmin
$ source /usr/local/hawq/greenplum_path.sh
$ gpssh-exkeys -f /opt/servers/all_hosts
$ gpssh -f /opt/servers/all_hosts -e "echo . /usr/local/hawq/greenplum_path.sh >> .bash_profile"
```

インストールができたか確認しましょう。

``` console
$ gpssh -f /opt/servers/all_hosts -e "ls -l $GPHOME"
  bin
  :
```

ディレクトリの作成
-----------------------
HAWQが使用するローカルディレクトリを作成します。

1. マスタのディレクトリ
    NameNodeのメタデータを格納しているディレクトリに、HAWQ用のディレクトリを用意します。

    ``` console
    # vi /opt/servers/master_hosts
    hawq-ma01          # マスタ

    # gpssh -f /opt/servers/master_hosts -e 'mkdir -p /hadoop/data/hawq/master'
    # gpssh -f /opt/servers/master_hosts -e 'chown -R gpadmin /hadoop/data/hawq/master'
    ```

1. スレーブのディレクトリ
    DataNodeのデータディレクトリに、HAWQ用のディレクトリに用意します。
    スレーブのディスク数に合わせてディレクトリを作成します。

    ``` console
    # vi /opt/servers/slave_hosts
    hawq-sl01          # スレーブ
    hawq-sl02          # 〃
    :

    # gpssh -f /opt/servers/slave_hosts -e 'mkdir -p /hadoop/data{0,1,2,3}/hawq/tmp'
    # gpssh -f /opt/servers/slave_hosts -e 'chown -R gpadmin /hadoop/data{0,1,2,3}/hawq/tmp'
    # gpssh -f /opt/servers/slave_hosts -e 'mkdir -p /hadoop/data{0,1,2,3}/hawq/primary'
    # gpssh -f /opt/servers/slave_hosts -e 'chown -R gpadmin /hadoop/data{0,1,2,3}/hawq/primary'
    ```

作成したディレクトリを確認します。

``` console
# gpssh -f /opt/servers/master_hosts -e "ls -l /hadoop/data/hawq"
master

# gpssh -f /opt/servers/slave_hosts -e "ls -l /hadoop/data{0,1,2,3}/hawq"
primary
tmp
:
```

OSの設定
-----------------------
[Set the OS Parameters](http://hawq.docs.pivotal.io/docs-hawq/topics/InstallingHAWQ.html#settingtheosparameters)を参考に、全ノードに対してOSの設定を変更します。
マスタの設定を変更してからスレーブにコピーします。

``` console
# vi /etc/sysctl.conf
kernel.shmmax = 500000000
kernel.shmmni = 4096
kernel.shmall = 4000000000
kernel.sem = 250 512000 100 2048
kernel.sysrq = 1
kernel.core_uses_pid = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.msgmni = 2048
net.ipv4.tcp_syncookies = 0
net.ipv4.ip_forward = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_max_syn_backlog = 200000
net.ipv4.conf.all.arp_filter = 1
net.ipv4.ip_local_port_range = 1025 65535
net.core.netdev_max_backlog = 200000
vm.overcommit_memory = 2
fs.nr_open = 3000000
kernel.threads-max = 798720
kernel.pid_max = 798720
net.core.rmem_max = 2097152
net.core.wmem_max = 2097152

# gpscp -f /opt/servers/slave_hosts /etc/sysctl.conf =:/etc
```
``` console
# vi /etc/security/limits.d/hawq.conf
gpadmin soft nofile 65536
gpadmin hard nofile 65536
gpadmin soft nproc 131072
gpadmin hard nproc 131072

# gpscp -f /opt/servers/slave_hosts /etc/security/limits.d/hawq.conf =:/etc/security/limits.d/
```

設定を反映するにはOSの再起動が必要です。
なお、OSの設定を変更したくない場合でも、"kernel.sem"だけは設定します。
これは「could not create semaphores: No space left on device」を避けるためです。([PostgreSQLのドキュメント](http://www.postgresql.org/docs/8.2/static/server-start.html)が詳しいです)

HAWQの初期化
-----------------------
初期設定ファイルをインストールディレクトリからコピーして修正します。

``` console
# su - gpadmin
$ mkdir gpconfigs
$ cp /usr/local/hawq/docs/cli_help/gpconfigs/gpinitsystem_config ~/gpconfigs/
$ chmod u+w ~/gpconfigs/gpinitsystem_config

$ vi ~/gpconfigs/gpinitsystem_config
:
declare -a DATA_DIRECTORY=(/hadoop/data0/hawq/primary /hadoop/data0/hawq/primary /hadoop/data1/hawq/primary /hadoop/data1/hawq/primary /hadoop/data2/hawq/primary /hadoop/data2/hawq/primary /hadoop/data3/hawq/primary /hadoop/data3/hawq/primary)
                                            # HAWQのデータディレクトリ。スレーブの台数 x ディレクトリ数分繰り返す
MASTER_HOSTNAME=hawq-ma01                   # HAWQのマスタのホスト名
MASTER_DIRECTORY=/hadoop/data/hawq/master   # HAWQのマスタのディレクトリ
DFS_URL=hawq-ma01:8020/hawq                 # HAWQのHDFS上のディレクトリへのURL
DATABASE_NAME=hawq_db                       # HAWQのDB名。後でcreatedbで作成することもできる
MACHINE_LIST_FILE=/opt/servers/slave_hosts  # スレーブの一覧を記述したファイル
```

NameNode HAを使用している場合は、初期化の前に設定を変更します。
なお、HAWQ自身はHAの仕組みがなく、PostgreSQLと同じ方式で実現するようです。[^1]

[^1]: http://hawq.docs.pivotal.io/docs-hawq/docs-hawq-shared/admin_guide/highavail/topics/g-overview-of-high-availability-in-greenplum-database.html

``` console
$ vi ~/gpconfigs/gpinitsystem_config
DFS_URL=nn-cluster/hawq    # NameServiceIDに変更する
```

``` console
# vi /usr/local/hawq/etc/hdfs-client.xml
<!-- HA -->
<property>
  <name>dfs.nameservices</name>
  <value>nn-cluster</value>
</property>

<property>
  <name>dfs.ha.namenodes.nn-cluster</name>
  <value>nn1,nn2</value>
</property>

<property>
  <name>dfs.namenode.rpc-address.nn-cluster.nn1</name>
  <value>hawq-ma01:8020</value>
</property>

<property>
  <name>dfs.namenode.rpc-address.nn-cluster.nn2</name>
  <value>hawq-ma02:8020</value>
</property>

<property>
  <name>dfs.namenode.http-address.nn-cluster.nn1</name>
  <value>hawq-ma01:50070</value>
</property>

<property>
  <name>dfs.namenode.http-address.nn-cluster.nn2</name>
  <value>hawq-ma02:50070</value>
</property>

# gpscp -f /opt/servers/all_hosts /usr/local/hawq/etc/hdfs-client.xml =:/usr/local/hawq/etc
```

HDFS上にHAWQのディレクトリを用意します。

``` console
# su - hdfs
$ hdfs dfs -mkdir /hawq
$ hdfs dfs -chown gpadmin /hawq
$ hdfs dfs -mkdir /user/gpadmin
$ hdfs dfs -chown gpadmin /user/gpadmin
```

いよいよHAWQの初期化を実行します！

``` console
# su - gpadmin
$ gpinitsystem -c ~/gpconfigs/gpinitsystem_config
:
Continue with Greenplum creation Yy/Nn>
y
```

ちなみに初期化の破棄は以下のコマンドです。
エラーが発生して初期化をやり直す場合に使用します。

``` console
$ /bin/bash /home/gpadmin/gpAdminLogs/backout_gpinitsystem_gpadmin_yyyyMMdd_hhmmss    # yyyyMMdd_hhmmssは初期化した日付
```

初期化後の設定
-----------------------
.bash_profileに環境変数を追加します。

``` console
# su - gpadmin
$ vi ~/.bash_profile
export MASTER_DATA_DIRECTORY=/hadoop/data/hawq/master/gpseg-1
```

[Prepare HDFS](http://hawq.docs.pivotal.io/docs-hawq/topics/InstallingHAWQ.html#preparingtoinstallhawq)を参考にHadoopクラスタの設定を見直します。
ポイントはショートサーキットリードを有効にするところです。
中でも最近のHadoopでは不要な"dfs.block.local-path-access.user"が必要です。

``` console
# vi /etc/hadoop/conf/hdfs-site.xml
:
<property>
  <name>dfs.client.read.shortcircuit</name>
  <value>true</value>
</property>

<property>
  <name>dfs.block.local-path-access.user</name>
  <value>gpadmin</value>
</property>

<property>
  <name>dfs.datanode.data.dir.perm</name>
  <value>750</value>
</property>
```

任意のクライアントからHAWQのマスタへの接続を許可する場合はpg_hba.confを修正します。
PostgreSQLと同じですね。

``` console
# vi /hadoop/data/hawq/master/gpseg-1/pg_hba.conf
:
#host     all         gpadmin         172.27.1.102/32       trust
host     all         gpadmin         172.27.1.0/24       trust
```

HAWQの利用
-----------------------
初期化のタイミングでHAWQが起動しているので、すでに利用できます。
hawq_dbデータベースも作成されています。

``` console
# su - gpadmin
$ vi t_user.csv
1	ajis_ka
2	adachij2002
3	takeuchikzm

$ psql hawq_db
hawq_db=#
  CREATE TABLE t_user
  (
    id INTEGER,
    name TEXT
  )
  WITH (appendonly=true) DISTRIBUTED RANDOMLY;
CREATE TABLE

hawq_db=# COPY t_user FROM '/home/gpadmin/t_user.csv' DELIMITER E'\t';
COPY 3

hawq_db=# SELECT * FROM t_user ORDER BY id;
 id |    name
----+-------------
  1 | ajis_ka
  2 | adachij2002
  3 | takeuchikzm
(3 rows)
```

動きました！

次回予告
-----------------------
ここまでで気付いた人もいると思うのですが、HAWQはHDFS上の特定のディレクトリ(今回なら/hawq)を専用に使用します。

``` console
# sudo -u hdfs hdfs dfs -ls /hawq
drwx------   - gpadmin supergroup          0 2016-04-22 22:23 /hawq/gpseg0
drwx------   - gpadmin supergroup          0 2016-04-22 22:23 /hawq/gpseg1
:
```

HDFSの他のファイルは読めないのでしょうか？
Hiveとの連携は？

その答えは[PXF(Pivotal eXtension Framework)](http://hawq.docs.pivotal.io/docs-hawq/topics/PXFInstallationandAdministration.html)にあります。
次回はPXFをインストールして、HDFS上のファイルやHiveとの連携を試してみたいと思います。

追記
-----------------------
[PXFについて](http://qiita.com/adachij2002/items/e652f172aa48898b4825)続きを書きました。