2019.01.16

Hive3とLLAPとDruidを試す ~HDP3.0.1.0~(前編:構築編)



こんにちは。次世代システム研究室のデータベース と Hadoop を担当している M.K. です。

ここのところずっと Hadoop ネタを続けてますが、今回はまだ出てそれほど時間が経ってないHive3(HDP3)をどうしても試してみたくてやってみました。
HiveはHadoop関連技術の中で今や中核となっている、HDFSのファイルをリレーショナルデータベースのテーブルのように扱えるサービスです。

そのHiveが3系となってだいぶバージョンアップされました。大きなところではトランザクション対応が真新しくなりデフォルト対応したことがあります。
またHive3単体だけでなく、Hiveを拡張し常駐プロセスにデータキャッシュなどのメモリ管理をさせるLLAP(low-latency analytical processing)や、OLAP用データストアのDruidのHive統合など、従来になかったHiveの最新機能を試したかったこともあり、Hortonworks社のHadoopパッケージであるHDP3(HDP3.0.1.0)を検証しました。

構築だけでもたくさんあるので構築についてまとめた前編(本編)と、クエリ検証を行った後編に分けました。後編は後日アップする予定です。本編は構築手順を順を追って書いたのでかなり長文です。まとめから読んでいただくなり、飛ばし読みをおすすめします。




目次(前編:構築編)




  1. HDP3の構築
  2. Hive3+LLAP+Druidのパラメータ設定
  3. まとめ



1. HDP3の構築




今回は新たなHadoopクラスタを構築することになるため、一から環境構築しました。ただ、Hadoopの主要サービスが使うデータベースには以前の検証で構築済みのPercona XtraDB Cluster(PXC)を再利用しています。
サーバーは毎度お馴染みのGMO アプリクラウドのサーバーです。




Hadoopクラスタの構成とサーバースペック




Hadoopクラスタのサーバー台数をまず決める必要がありますが、今回はデータ処理のメインとなるスレーブノードは5台、マスターノードは3台、管理ツールのAmbari用に1台、という構成にしました。
GMO アプリクラウドのサーバースペックは 以下のようになります。

・マスターノード&Ambariノード(計4台)
 - 仮想CPU:4
 - ディスク容量:320GB
 - メモリ容量:16GB
 - OS:CentOS7.0
・スレーブノード(計5台)
 - 仮想CPU:6
 - ディスク容量:640G
 - メモリ容量:30GB
 - OS:CentOS7.0




OS周りのセットアップ




Hadoopクラスタ用にサーバーを事前に色々とセットアップします。詳細は以前のブログをご参考ください。




  • DNSは使っていないので/etc/hostsファイルを設定
    • 必ずFQDN形式で記述します
    • 各サーバーにログインして、hostnamectl set-hostnameコマンドでホスト名を変えておきます
    • 今回の環境ではdnssecを無効化する必要があったため、/etc/named.confを編集しnamedを再起動
  • ntpサーバーをインストール&構築
    • Ambariノードに構築したntpを他のノードが見に行く形で設定、ntpd再起動
  • Ambariノードのrootユーザーが他のノードにパスワードなしでssh接続できるように設定
    • ※本番運用ではrootユーザーは避けてrootユーザー権限に准じるようなユーザーを作っておく
  • curlとwgetが入ってなかったらインストール
  • tunedに新しいプロファイルを作成して切り替え
    • transparent_hugepagesを無効化する設定
    • sysctlのパラメータ変更
      • vm.dirty_ratio = 50
      • vm.dirty_background_ratio = 20
      • vm.swappiness = 0
  • リソース制限を変更
    • /etc/security/limits.confを編集(以下の値を大きく増やす)
      • * soft nofile
      • * hard nofile
      • * soft nproc
      • * hard nproc



Ambariの構築とセットアップ




OS周りのセットアップが終わったら、まずAmbariを構築します。




MySQL Connector/J のインストール




Ambariを立てるサーバーに、まずMySQL Connector/Jをインストールします。Ambariのデータ保存にMySQL系のPXCを使うためです。
MySQL のサイトからダウンロードして配置するだけで完了です。
配置場所は/usr/share/javaにします。
今回は現時点で最新のmysql-connector-java-8.0.13を利用しました。




cd /usr/local/src
wget https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-8.0.13.tar.gz
tar zxvf mysql-connector-java-8.0.13.tar.gz
cd mysql-connector-java-8.0.13
mkdir -p /usr/share/java
mv mysql-connector-java-8.0.13.jar /usr/share/java/
chmod 644 /usr/share/java/mysql-connector-java-8.0.13.jar



Ambari のインストール




Ambari を立てるサーバーに、CentOS 7 用の最新の Ambari をインストールします。




cd /var/tmp
wget -nv http://public-repo-1.hortonworks.com/ambari/centos7/2.x/updates/2.7.1.0/ambari.repo -O /etc/yum.repos.d/ambari.repo
yum repolist
yum install ambari-server



データベースにユーザーを作成




PXCにAmbari用のユーザーとスキーマを作成します。ついでに、後で必要になるHive用とDruid用のユーザーとスキーマも作成しておきます。
今回はそれぞれ、ユーザーがambariuser、hiveuser、druiduser、スキーマがambari_db、hive_meta、druid_metaとしました。




ProxySQLのインストール




PXCはMySQLのマスターを複数台立てて冗長化するクラスタ製品で、接続の振り分けは別途行う必要があるため、PXCとセットでよく使われるProxySQLを利用します。
今回PXCにデータを保存する予定があるのはAmbari、Hive、Druidで、HiveとDruidは同じProxySQLを使うつもりなので、Ambariノードにマスターノード1にProxySQLを構築します。




yum install -y libaio
yum install -y http://www.percona.com/downloads/percona-release/redhat/0.1-4/percona-release-0.1-4.noarch.rpm
yum install -y proxysql
yum install -y Percona-Server-client-57



ProxySQLの設定




PXCのクラスタ構成は、以前のブログの構成(書き込みは通常1台、障害があったときだけフェイルオーバーするSingleWrite構成)のままで使うので、そのための設定をします。
ただ以前と違って、ProxySQLのバージョンが上がって色々と変わってしまってハマりました・・。最終的に以下のような設定に落ち着きました。




cp -p /etc/proxysql-admin.cnf /etc/proxysql-admin-conf.bak

echo '# proxysql admin interface credentials.
export PROXYSQL_DATADIR=/var/lib/proxysql
export PROXYSQL_USERNAME=admin
export PROXYSQL_PASSWORD=admin
export PROXYSQL_HOSTNAME=localhost
export PROXYSQL_PORT=6032

# ProxySQL read/write hostgroup
export HOSTGROUP_WRITER_ID=10
export HOSTGROUP_READER_ID=11

# ProxySQL write nodes count  ( 1 for singlewrite mode )
export NUMBER_WRITERS=1

# ProxySQL read/write configuration mode.
export MODE="singlewrite"

# ProxySQL Cluster Node Priority File
export HOST_PRIORITY_FILE=$PROXYSQL_DATADIR/host_priority.conf

# ProxySQL Log File
export ERR_FILE=/var/lib/proxysql/proxysql_galera_checker.log' > /etc/proxysql-admin.cnf



PXCのフェイルオーバーしたときの順番を指定します。PXCを構成するノードのIPアドレスとポート番号を記述します。




echo 'xx.xx.xx.10:3306
xx.xx.xx.20:3306
xx.xx.xx.30:3306' > /var/lib/proxysql/host_priority.conf



ProxySQLの設定が終わったら、ProxySQLを再起動します。
設定ファイルの編集だけで終わりではなく、ProxySQLのデータベースに入って直接設定値を更新します。ProxySQLのデータベースは実はSQLiteなので、そこに入って以下のSQLを順次実施していきます。
まず、以下のようにSQLiteに入ります。SQLiteですがmysqlコマンドで入ったりします。




mysql -u admin -p ***** -h 'localhost' -P 6032 --protocol=tcp --prompt='ProxySQL> '



SQLiteに入ったら、主にPXCのノード監視およびフェイルオーバーのための設定値を更新します。




ProxySQL> INSERT INTO mysql_servers (hostgroup_id, hostname, port, status, weight, comment) VALUES
 (10, 'xx.xx.xx.10', 3306, 'ONLINE', 1000000, 'WRITE'),
 (11, 'xx.xx.xx.20', 3306, 'ONLINE', 1000, 'READ'),
 (11, 'xx.xx.xx.30', 3306, 'ONLINE', 1000, 'READ')
 ;
LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;

ProxySQL> INSERT INTO mysql_users (username, password, default_hostgroup) VALUES
 ('ambariuser', '*****', 10),
 ('hiveuser', '*****', 10),
 ('druiduser', '*****', 10)
;
LOAD MYSQL USERS TO RUNTIME;
SAVE MYSQL USERS TO DISK;

ProxySQL> UPDATE global_variables SET variable_value='pxc_monitor' WHERE variable_name = 'mysql-monitor_username';
UPDATE global_variables SET variable_value='*****' WHERE variable_name = 'mysql-monitor_password';
LOAD MYSQL VARIABLES TO RUNTIME;
SAVE MYSQL VARIABLES TO DISK;

-- 【注意】イケてないことに、comment列を書かなかったり、arg1に'--write-hg=XX 'のように最後の半角スペースが入ってないとうまく動かない。。
ProxySQL> INSERT INTO scheduler (id, active, interval_ms, filename, arg1,comment)
 VALUES (10, 1, 3000, '/usr/bin/proxysql_galera_checker', '--config-file=/etc/proxysql-admin.cnf --write-hg=10 --read-hg=11', 'cluster1')
;
LOAD SCHEDULER TO RUNTIME;
SAVE SCHEDULER TO DISK;



Ambariが使うテーブルを事前に作成




AmbariノードからProxySQL経由でPXCに接続、Ambari用に用意されたテーブル定義SQLを実行します。




mysql -h localhost -P 6033 -u ambariuser -p --protocol=tcp
mysql> use ambari_db;
source /var/lib/ambari-server/resources/Ambari-DDL-MySQL-CREATE.sql



ambari-server の JDBC 設定




続けて、ambari-server の JDBC 設定を行います。




ambari-server setup --jdbc-db=mysql --jdbc-driver=/usr/share/java/mysql-connector-java-8.0.13.jar



ambari-server のセットアップ




JDBC設定まで終わったら、いよいよAmbariをセットアップします。ambari-server setupを実行し、ところどころ、YESかNO (y/n)か、どの番号を選ぶか、名前・パスワードを聞かれるので、以下のように選択します。




Using python  /usr/bin/python
Setup ambari-server
Checking SELinux...
SELinux status is 'disabled'
Customize user account for ambari-server daemon [y/n] (n)? n
Adjusting ambari-server permissions and ownership...
Checking firewall status...
Checking JDK...
[1] Oracle JDK 1.8 + Java Cryptography Extension (JCE) Policy Files 8
[2] Custom JDK
==============================================================================
Enter choice (1): 1
To download the Oracle JDK and the Java Cryptography Extension (JCE) Policy Files you must accept the license terms found at http://www.oracle.com/technetwork/java/javase/terms/license/index.html and not accepting will cancel the Ambari Server setup and you must install the JDK and JCE files manually.
Do you accept the Oracle Binary Code License Agreement [y/n] (y)? y
Downloading JDK from http://public-repo-1.hortonworks.com/ARTIFACTS/jdk-8u112-linux-x64.tar.gz to /var/lib/ambari-server/resources/jdk-8u112-linux-x64.tar.gz
jdk-8u112-linux-x64.tar.gz... 100% (174.7 MB of 174.7 MB)
Successfully downloaded JDK distribution to /var/lib/ambari-server/resources/jdk-8u112-linux-x64.tar.gz
Installing JDK to /usr/jdk64/
Successfully installed JDK to /usr/jdk64/
Downloading JCE Policy archive from http://public-repo-1.hortonworks.com/ARTIFACTS/jce_policy-8.zip to /var/lib/ambari-server/resources/jce_policy-8.zip

Successfully downloaded JCE Policy archive to /var/lib/ambari-server/resources/jce_policy-8.zip
Installing JCE policy...
Check JDK version for Ambari Server...
JDK version found: 8
Minimum JDK version is 8 for Ambari. Skipping to setup different JDK for Ambari Server.
Checking GPL software agreement...
GPL License for LZO: https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html
Enable Ambari Server to download and install GPL Licensed LZO packages [y/n] (n)? y
Completing setup...
Configuring database...
Enter advanced database configuration [y/n] (n)? y
Configuring database...
==============================================================================
Choose one of the following options:
[1] - PostgreSQL (Embedded)
[2] - Oracle
[3] - MySQL / MariaDB
[4] - PostgreSQL
[5] - Microsoft SQL Server (Tech Preview)
[6] - SQL Anywhere
[7] - BDB
==============================================================================
Enter choice (1): 3
Hostname (localhost): 127.0.0.1
Port (3306): 6033
Database name (ambari): ambari_db
Username (ambari): ambariuser
Enter Database Password (bigdata):*****
Re-enter password:*****
Configuring ambari database...
Enter full path to custom jdbc driver: /var/lib/ambari-server/resources/mysql-connector-java.jar
Copying /var/lib/ambari-server/resources/mysql-connector-java.jar to /usr/share/java
Configuring remote database connection properties...
WARNING: Before starting Ambari Server, you must run the following DDL against the database to create the schema: /var/lib/ambari-server/resources/Ambari-DDL-MySQL-CREATE.sql
Proceed with configuring remote database connection properties [y/n] (y)? y
Extracting system views...
ambari-admin-2.7.1.0.169.jar
....
Ambari repo file contains latest json url http://public-repo-1.hortonworks.com/HDP/hdp_urlinfo.json, updating stacks repoinfos with it...
Adjusting ambari-server permissions and ownership...
Ambari Server 'setup' completed successfully.



“Ambari Server ‘setup’ completed successfully”と返ってきたら成功です。




JDK を 配布




Ambariセットアップが無事に終わったら、次はJDKをHadoopクラスタのノードに配布します。Ambariノードで行うと楽ちんです。/usr/jdk64をHadoopクラスタを構成するマスターノードとスレーブノード全台に同じディレクトリにコピーします。




ambari.properties を編集




/etc/ambari-server/conf/ambari.properties の JDBC ドライバーのフルパスを変更しておきます。




  • server.jdbc.driver.path=/usr/share/java/mysql-connector-java.jar



ambari-server 起動




Ambariを稼働させる準備が全て整ったので、Ambariを稼働します。ambari-server startして、以下のようにエラー無く返ってきたら完了です。




Using python  /usr/bin/python
Starting ambari-server
Ambari Server running with administrator privileges.
Organizing resource files at /var/lib/ambari-server/resources...
Ambari database consistency check started...
Server PID at: /var/run/ambari-server/ambari-server.pid
Server out at: /var/log/ambari-server/ambari-server.out
Server log at: /var/log/ambari-server/ambari-server.log
Waiting for server start...............................
Server started listening on 8080

DB configs consistency check: no errors and warnings were found.
Ambari Server 'start' completed successfully.



Ambari の管理画面から Hadoop クラスタ構築




ここからはAmbari管理画面で操作します。 Ambariノードの8080ポートをSSHトンネリングするなどして、Ambari管理画面にブラウザでログインします。
初期状態のアカウントとパスワードは、定番(?)のadmin / adminです。




Install Wizardで構築




Ambari管理画面に初めてログインすると、Launch Install Wizardボタンが出てくるので、それを押してInstall Wizardに従って構築をしていきます。
Get Started
 クラスタ名を記入して「NEXT→」ボタンを押す

Select Version
 HDP-3.0.1.0を選択
 Use Public Repositoryにチェック
  OSがredhat-ppc7とredhat7だけ残してRemove、「NEXT→」ボタンを押す

Install Options
 Target Hosts ⇒以下のようにホスト名をFQDN形式で記入
  hdp3-am.testhdp.com
  hdp3-m1.testhdp.com
  hdp3-m2.testhdp.com
  hdp3-m3.testhdp.com
  hdp3-s1.testhdp.com
  hdp3-s2.testhdp.com
  hdp3-s3.testhdp.com
  hdp3-s4.testhdp.com
  hdp3-s5.testhdp.com

 Host Registration Information
  ”Provide your SSH Private Key to automatically register hosts”にチェック
  ssh private keyに、rootユーザー@hdp3-amがssh-keygenで作成した秘密鍵(.ssh/id_rsa)の内容をコピペ
  SSH User Accountは、rootのまま
  SSH Port Numberは、22のまま
  「Register and Confirm」ボタンを押す

Confirm Hosts
 全ホストともにStatusがSuccessで、”All host checks passed on 9 registered hosts.”の結果であれば、「NEXT→」ボタンを押す

Choose Services
 今回は以下のサービスを使用するので、チェックしたら「NEXT→」ボタンを押す
 Choose File System
  ・HDFS

 Chhose Services
  ・YARN + MapReduce2
  ・Tez
  ・Hive
  ・ZooKeeper
  ・Infra Solr
  ・Ambari Metrics
  ・SmartSence ※チェック外せない
  ・Spark2
  ・Zeppelin Notebook
  ・Druid

Assign Masters
 マスターノード&Ambariノードの4台に、メモリ消費が1台に偏らないようにサービスを分散して配置します。各サービスをそれぞれノードに割り当てて
 「NEXT→」ボタンを押す

Assign Slaves and Clients
 DataNode:スレーブ5台にチェック
 NodeManager:スレーブ5台にチェック
 Druid Histrical:スレーブ5台にチェック
 Druid MiddleManager:スレーブ5台にチェック
 Spark2 Thrift Server:hdp3-m3にチェック
 Client:全ノードにチェック
 上記のようにチェックして「NEXT→」ボタンを押す

Customize Services
 CREDENTIALS ⇒アカウントとパスワードをそれぞれ記入します
  Grafana Admin:初期アカウントとパスワードのadmin/admin
  Druid Metadata User:PXCに作成したアカウントとパスワードのdruiduser/*****
  Hive Database: PXCに作成したアカウントとパスワードのhiveuser/*****
  Activity Explorer’s Admin:パスワードのみで初期パスワードのadmin

 DATABASES ⇒データベース接続に使う情報をそれぞれ記入します
  DRUID
   Druid Metadata storage database name:PXCに作成したDruid用スキーマのdruid_meta
   Druid Metadata storage type:MySQL
   Metadata storage hostname: PXCに繋ぐProxySQLを立てたhdp3-m1.testhdp.com
   Metadata storage port:ProxySQLの6033ポート
   Metadata storage connector url:JDBC接続情報のjdbc:mysql//hdp3-m1.testhdp.com:6033/druid_meta
   ※他の設定情報はCREDENTIALSの情報   
  HIVE
   Hive Database:Existing MySQL / MariaDB
   Database Name:PXCに作成したHive用スキーマのhive_meta
   Database URL: JDBC接続情報のjdbc:mysql//hdp3-m1.testhdp.com:6033/hive_meta
   Hive Datase Type:mysql
   JDBC Driver Class:com.mysql.jdbc.Driver
   一通り設定できたら「TEST CONNECTION」を押して設定が正しいかテストしておく

 DIRECTORIES
  HDFS
   DATA DIRS ⇒利用しているGMOアプリクラウドは/varにたくさんのディスクが割り当てられているので、以下のディレクトリを/var配下にしました
    DataNode directories = /var/hadoop/hdfs/data
    NameNode directories = /var/hadoop/hdfs/namenode
    SecondaryNameNode Checkpoint directories = /var/hadoop/hdfs/namesecondary
    NFSGateway dump directory = /var/tmp/.hdfs-nfs
    NameNode Backup directory = /var/tmp/upgrades
    JournalNode Edits directory = /var/hadoop/hdfs/journalnode
   他はそのままです
  YARN
   DATA DIRS
    YARN NodeManager Local directories = /var/hadoop/yarn/local
   LOG DIRS
    YARN NodeManager Log directories = /var/hadoop/yarn/log
   他はそのままです
  ZOOKEEPER
   DATA DIRS
    ZooKeeper directory = /var/hadoop/zookeeper
   他はそのままです
  その他のサービスについてはそのままにします
  「NEXT→」ボタンを押す

 ACCOUNTS
  何も変えずに「NEXT→」ボタンを押す

 ALL CONFIGURATIONS
  YARN
   ADVANCED
    Application Timeline Server
     AppTimelineServer Java heap sizeだけ8072→4096
     yarn.timeline-service.leveldb-state-store.path = /var/hadoop/yarn/timeline
     yarn.timeline-service.leveldb-timeline-store.path = /var/hadoop/yarn/timeline
  他はこの時点ではそのままにして「NEXT→」ボタンを押す

Review
 「DEPLOY→」ボタンを押す




デプロイでのエラーとその対応




長々と設定してきて「DEPLOY→」ボタンを押せばついにHadoopクラスタ構築完了かと思ったら、「Upload Version Definition File Error」というエラーが発生。やっぱり新しい技術を自分で初めて使うときは色々と出ます。。
Ambariノードの/var/log/ambari-server/ambari-server.logに以下のエラーが出ていました。




Caused by: java.sql.SQLException: Percona-XtraDB-Cluster prohibits use of DML command on a table (ambari_db.repo_tags) without an explicit primary key with pxc_strict_mode = ENFORCING or MASTER



PXCのAmbari用スキーマに作成したテーブルの一つのrepo_tagsにPKがなく、PXCで怒られていました。以前のブログにも書きましたが、PXCはテーブルにPKがあることが前提となっているデータベースのクラスタ製品です。
今まで試したHDP2系ではAmbari用のテーブルでPKがないものはなかったので、HDP3になって変わったみたいです(PKなしでテーブル作るのは本当にやめてほしい・・)。
今回の検証でもPXCを使ってどうかをみるつもりなので、自動採番のダミーカラムを追加してPKにするという対策を取りました。PXCに接続して以下のALTER文を実行しています。




ALTER TABLE repo_tags
 ADD COLUMN id INT NOT NULL AUTO_INCREMENT FIRST,
 ADD CONSTRAINT PRIMARY KEY (id);



これで終わりかと思ったらまた別のエラーが発生。
「Error 500 status code received on PUT method for API: /api/v1/stacks/HDP/versions/3.0/repository_versions/3」
Ambariノードの/var/log/ambari-server/ambari-server.logに今度は以下のエラー が出てました。




Caused by: com.mysql.cj.exceptions.CJCommunicationsException: The last packet successfully received from the server was 114,984 milliseconds ago.  The last packet sent successfully to the server was 114,985 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.



どうやらデータベース接続のタイムアウト時間が短くて怒られたようです。エラーログにwait_timeoutパラメータをもっと増やすようなことが書かれているので、その通りにPXCに接続し以下を実行しました。




SET GLOBAL wait_timeout=600;



これでやっとデプロイが進み、Install Wizardで
Install, Start and Test
Summary

までおわり、ひとまずHadoopクラスタ構築はできました。

がしかし、今度は各種サービスがほとんど立ち上がらず、またハマりました。。
まずHDFSサービスだけを起動したら立ち上がりました。次にYARNサービスを起動してみたらエラーが出て起動できず、YARN Registry DNSのところでこけていました。どうもポートが被っていて上手くいってないようなので、
(参考: https://community.hortonworks.com/articles/225841/yarn-registry-dns-port-conflict-issue.html)
Ambari管理画面で、YARN > CONFIGS > Registryと遷移し、
 RegistryDNS Bind Port を53 → 553
と設定変更し、再起動したらYARNサービスも立ち上がりました。




そして、Hiveサービスが今度は立ち上がらず。
以前のブログの原因と同じで、Hiveがデータベースに格納するテーブルにPKがないことが原因でした。Hive3系になって期待しましたが、あまり変わってなかったようです。Hive用のテーブル定義はHive Metastoreサービスを立てたノードの以下に配置してあるので、今回はこれを編集して事前に手動で作成する方針にしました。
/usr/hdp/3.0.1.0-187/hive/scripts/metastore/upgrade/mysql/hive-schema-3.1.0.mysql.sql
以下に修正したSQLだけ抜粋して書いておきます。




-- 自動採番のDUMMY_IDカラムを追加しそれをPKに
CREATE TABLE IF NOT EXISTS `MV_TABLES_USED` (
  `DUMMY_ID` bigint NOT NULL AUTO_INCREMENT,
  `MV_CREATION_METADATA_ID` bigint(20) NOT NULL,
  `TBL_ID` bigint(20) NOT NULL,
  PRIMARY KEY (`DUMMY_ID`),
  CONSTRAINT `MV_TABLES_USED_FK1` FOREIGN KEY (`MV_CREATION_METADATA_ID`) REFERENCES `MV_CREATION_METADATA` (`MV_CREATION_METADATA_ID`),
  CONSTRAINT `MV_TABLES_USED_FK2` FOREIGN KEY (`TBL_ID`) REFERENCES `TBLS` (`TBL_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- 自動採番のDUMMY_IDカラムを追加しそれをPKに
CREATE TABLE TXN_COMPONENTS (
  DUMMY_ID bigint NOT NULL AUTO_INCREMENT,
  TC_TXNID bigint NOT NULL,
  TC_DATABASE varchar(128) NOT NULL,
  TC_TABLE varchar(128),
  TC_PARTITION varchar(767),
  TC_OPERATION_TYPE char(1) NOT NULL,
  TC_WRITEID bigint,
  PRIMARY KEY (DUMMY_ID),
  FOREIGN KEY (TC_TXNID) REFERENCES TXNS (TXN_ID)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- 自動採番のDUMMY_IDカラムを追加しそれをPKに
CREATE TABLE COMPLETED_TXN_COMPONENTS (
  DUMMY_ID bigint NOT NULL AUTO_INCREMENT,
  CTC_TXNID bigint NOT NULL,
  CTC_DATABASE varchar(128) NOT NULL,
  CTC_TABLE varchar(256),
  CTC_PARTITION varchar(767),
  CTC_TIMESTAMP timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
  CTC_WRITEID bigint,
  CTC_UPDATE_DELETE char(1) NOT NULL,
  PRIMARY KEY (DUMMY_ID)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- NTXN_NEXTカラムをPKに
CREATE TABLE NEXT_TXN_ID (
  NTXN_NEXT bigint NOT NULL,
  PRIMARY KEY(NTXN_NEXT)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO NEXT_TXN_ID VALUES(1);

-- 重複していて意味がない下記インデックス作成はコメントアウト
-- CREATE INDEX HL_TXNID_IDX ON HIVE_LOCKS (HL_TXNID);

-- NL_NEXTカラムをPKに
CREATE TABLE NEXT_LOCK_ID (
  NL_NEXT bigint NOT NULL,
  PRIMARY KEY(NL_NEXT)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO NEXT_LOCK_ID VALUES(1);
-- NCQ_NEXTカラムをPKに
CREATE TABLE NEXT_COMPACTION_QUEUE_ID (
  NCQ_NEXT bigint NOT NULL,
  PRIMARY KEY(NCQ_NEXT)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO NEXT_COMPACTION_QUEUE_ID VALUES(1);

-- 自動採番のDUMMY_IDカラムを追加しそれをPKに
CREATE TABLE WRITE_SET (
  DUMMY_ID bigint NOT NULL AUTO_INCREMENT,
  WS_DATABASE varchar(128) NOT NULL,
  WS_TABLE varchar(128) NOT NULL,
  WS_PARTITION varchar(767),
  WS_TXNID bigint NOT NULL,
  WS_COMMIT_ID bigint NOT NULL,
  WS_OPERATION_TYPE char(1) NOT NULL,
  PRIMARY KEY(DUMMY_ID)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- 自動採番のDUMMY_IDカラムを追加しそれをPKに
CREATE TABLE TXN_TO_WRITE_ID (
  DUMMY_ID bigint NOT NULL AUTO_INCREMENT,
  T2W_TXNID bigint NOT NULL,
  T2W_DATABASE varchar(128) NOT NULL,
  T2W_TABLE varchar(256) NOT NULL,
  T2W_WRITEID bigint NOT NULL,
  PRIMARY KEY(DUMMY_ID)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- 自動採番のDUMMY_IDカラムを追加しそれをPKに
CREATE TABLE NEXT_WRITE_ID (
  DUMMY_ID bigint NOT NULL AUTO_INCREMENT,
  NWI_DATABASE varchar(128) NOT NULL,
  NWI_TABLE varchar(256) NOT NULL,
  NWI_NEXT bigint NOT NULL,
  PRIMARY KEY(DUMMY_ID)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;



上記修正をしたhive-schema-3.1.0.mysql.sqlをPXCのHive用スキーマに繋いで作成します。
Hive Metastoreサービスを立ち上げたときに自動でテーブルを作り直すことがないように、Ambari管理画面で、Hive > Configs > Custom hive-site.xmlと遷移し、
 hive.metastore.schema.verification = false
を追加設定します。
これでHiveサービスが立ち上がり、他のサービスも立ち上がって、ようやくHadoopクラスタの構築が完了しました。ただまだ初期状態なので、さらに追加で設定が必要です。いつもは、YARNのResourceManagerやHiveServer2およびHive Metastoreの冗長化設定を次に行うところですが、今回はメインの目的ではないの後回しにしました。
それで行ったのは、HiveのLLAP機能を有効化することです。




2.Hive+LLAP+Druidのパラメータ設定




Hive LLAP (HiveServer2 Intractive)を有効にする




HiveのLLAP機能を有効にするには、Ambari管理画面で、Hive > CONFIGS > SETTINGS > Interactive Queryと遷移し、Enable Interactive Query (requires YARN pre-emption)のバーをYESにします。括弧の中にも書いてあるようにLLAPはYARNのpre-emption機能の有効化を前提にしているので、 YARN > CONFIGS > SETTINGS > YARN Featuresに遷移して、Pre-emptionのバー
がEnabledになっているか確認します。なってなければEnabledにします。
その他、Interactive Queryの別のメモリ設定などを適当に変えてみたりしてLLAPのサービス名であるHiveServer2 Interactiveを立ち上げてみたところ、当然のごとく立ち上がりませんでした。。
どうやらLLAPはきちんとメモリ割り当て設計をしないとダメなもののようです。ということで調べていくと、設計方針がちゃんとありました。
Hive LLAPのメモリ割り当てに関する記事に詳細がまとまっていたので、ここに書いてあることに従ってメモリ割り当てを行いました。




LLAPノードをどう構成するかとリソースの割り当て




最初に、LLAPのノードをどのように構成するかを考えます。LLAPは実は前回のブログで試したPresto on YARNのように、デーモンが常駐する仕組みを取ります。スレーブノードのリソースをどのようにLLAPに使わせるかを予め設計しないといけません。
参考にした記事によれば、どちらかというと、スレーブノードのうちの何台かをLLAP専用にするような構成をお薦めしていたので、今回その方針で、スレーブノード5台のうち2台を割り当てる感じにしました。
スレーブノードはGMO アプリクラウドのタイプMで、これが設計時の元の情報になります。
 CPU: 6vCPU / メモリ: 30GB / HDD: 640GB

LLAPデーモンがスレーブノード1台で利用するメモリの計算式は以下です。
LLAP daemon = (NM_memory – 2Gb * ceiling((N_Tez_AMs + 1)/N_LLAP_nodes))
それぞれの値を求めて計算します。
・N_LLAP_nodes = 全ノードにおけるLLAPが使うノード数
 5台中2台をLLAP専用にするため、2を設定
・N_Tez_AMs = query coordinators (Tez AMs)の数
 例)同時に9個のクエリを並列で走らせる場合、10 AMを利用
 今回クエリの並列実行数はそれほど考えないので、2を設定
・NM_memory = 1台のNode Managerのメモリ (yarn.nodemanager.resource.memory-mb)
 今回はタイプMのサーバーで30GBメモリなので、26GBを設定
再度計算式に当てはめると、
LLAP daemon = 26Gb – 2Gb * ceiling(3/2)
= 26Gb – 4Gb = 22Gb
LLAPデーモンがスレーブノード1台で利用するメモリは22GBに決まりました。

次にLLAPはYARN上でリソース管理されるので、LLAP用のYARNキューの設計をします。LLAP用のYARNキューのサイズは以下の計算式です。
LLAP queue size = (2Gb * N_TEZ_AMs) + (1Gb [slider AM]) + (daemon_size * N_LLAP_nodes)
さきほど設定した値をそれぞれ当てはめると、
LLAP queue size = (2Gb * 2) + 1Gb + (22Gb * 2)
= 4Gb + 1Gb + 44Gb = 49Gb

全体のYARNキューリソースはNode Managerのメモリ26Gb * 5です。49Gbは全体のおよそ40%なので、LLAP用のYARNキューには40%を割り当てます。

まだ設定は残っていて、LLAPデーモンのヒープサイズとキャッシュサイズを決めます。LLAPデーモンのヒープサイズの計算式は以下で
LLAP Daemon Heap Size = n_executors * memory_per_executor
・n_executors = LLAPデーモンが立ち上げるexecutors数
 今回はタイプMのサーバーで6vCPUで、以下のmemory_per_executorを4Gbにすることから、4を設定
・memory_per_executor
 LLAPが立ち上げるexecutor数より、一つのexecutorに割り当てるメモリ数を4Gb~6Gb当てた方が良いとあるので、4Gbを設定
それぞれ当てはめると、
LLAP Daemon Heap Size = 4 * 4Gb = 16Gb
16Gbになりました。

続いてLLAPデーモンのキャッシュサイズの計算式は以下で
Cache size = LLAP daemon size – LLAP Daemon Heap Size – headroom
・headroom (LLAP Daemon Container Max Headroom)は以下の計算式で求めます
  headroom = 0.06 * LLAP Daemon Heap Size ≒ 1Gb
それぞれ当てはめると、
Cache size = 22 Gb – 16Gb – 1Gb = 5Gb
5Gbになりました。

これでLLAPに割り当てるリソースが決まりました。これに基いて実際の設定を行います。




各種パラメータを実際に設定




Ambari管理画面から以下のように変えます。
YARN > CONFIGS > SETTINGS > Memoryに遷移、下記の値に変更
 Node > Memory allocated for all YARN containers on a node →26GB
 Container > Minimum Container Size (Memory) →2048MB
 Container > Maximum Container Size (Memory) →26624MB

YARN > CONFIGS > ADVANCED > Node Managerに遷移、下記の値に変更
 NodeManager Java heap size →2048MB

Hive > CONFIGS > SETTINGS > Interactive Queryに遷移、下記の値に変更
 Number of nodes used by Hive’s LLAP →2
 Memory per Daemon (=LLAP daemon size) →22528MB
 In-Memory Cache per Daemon (=Cache size) →5120MB
 Number of executors per LLAP Daemon (=n_executors) →4

Hive > CONFIGS > SETTINGS > Optimizationに遷移、 下記の値に変更
 Tez > Tez Container Size →4096MB

Hive > CONFIGS > ADVANCED > Advanced hive-interactive-envに遷移、下記の値に変更
 HiveServer Interactive Heap Size →2048MB
 LLAP Daemon Container Max Headroom →1024MB
 LLAP Daemon Heap Size (MB) →16384
 Number of Node(s) for running Hive LLAP daemon →2

Hive > CONFIGS > ADVANCED > Advanced hive-interactive-siteに遷移、下記の値に変更
 hive.tez.container.size →4096(MB)

Hive > CONFIGS > ADVANCED > Advanced tez-interactive-siteに遷移、下記の値に変更
 tez.am.resource.memory.mb →2048(MB)

Tez > CONFIGS > Generalに遷移、下記の値に変更
 tez.am.resource.memory.mb →2048(MB)
 tez.task.resource.memory.mb →4096(MB)

上記のように設定を変更しようとすると、影響する他のパラメータ変更をAmbariからおすすめされます。今回はそれらもチェックしてあわせて変更しました。

最後にYARNキューの設定が残っているので、Ambari管理画面一番上のバーの右端にあるViewアイコンからYARN Queue Managerに遷移して、llapキューとdefaultキューの設定を変更します。llapキューの優先度は1に変えます。
 ・llapキュー
  Capacity →40%、Max Capacity →40%
  Priority →1
 ・defaultキュー
  Capacity →60%、Max Capacity →60%

上記一通り設定変更できたら関係するサービスをすべて再起動します。 とてもやることが多いですが、Hive + LLAP + DruidのHadoopクラスタ環境はついに完成です。




まとめ




環境構築後、Hive LLAPとDruidを使ったクエリの検証を色々試していて詳しくは後編にまとめますが、先に少し触れておくとLLAPとDruidで大規模データを使うところで苦戦してます・・。
長時間のクエリを実行中にLLAPデーモンがよく落ちたり、Druidにデータが上手く書き込めなかったり。実はパラメータも色々設定を試したんですが、上記のパラメータ設定にしてからLLAPデーモンがすぐに落ちることがなくなり安定しました。YARNコンテナを2GB、Hive Tezコンテナサイズ関連を4GBで合わせるようにしました。メモリ設計が怪しいとLLAPは挙動が不安定になります。
今回の構築でわかった大事なポイントを以下にまとめます。




  • 最初の状態では、Hive LLAP (HiveServer2 Interactive)を使わないとDruidとHiveの連携ができない。
    • というか、Ambari管理画面においてHive ⇔ Druid連携で必要なパラメータ設定がHiveServer2 Interactiveの方にしかない
  • LLAPはリソースの割り当て(特にメモリ)を事前にしっかり考えておく必要がある。何よりもスレーブノード1台あたりのメモリ搭載量が少ないと話にならない。
    • 今回試した30GBのメモリ搭載量は検証であっても最低レベルだと思います。ワークロード次第なのはもちろんですが、小規模のHadoopクラスタ環境ではLLAPキューに全体の50%前後のリソースを割り当てないと、大きなデータを扱う際のパフォーマンスが出ない感じもあり、そこまでリソースを削ってLLAPを使いたいのかどうかは大きなポイントです。LLAPを実践で使うなら、スレーブノード1台あたり128GB以上はないとそれなりの大規模データを扱うには厳しい印象です。
  • Hive+LLAP+Druidはパラメータ設定で考えることが多すぎて導入コストが高い。
    • 今回は肝心のHive⇔Druid間やDruid自体のパラメータ設定を深堀りできていないですが、Hive、LLAP、Druidそれぞれで考えるべき設定項目が多く、また、そもそもDruidは時系列データを格納するようにできておりHiveのテーブルを時系列テーブルに変換しないといけないため、当初思い描いたほど気軽にはDruidを使えない感じでした。 商用サポートのサブスクリプションを買ってほしいHortonworks社の狙いなのかもしれませんが(笑)。



Hortonworks社とCloudera社の統合が決まって製品も将来的に合わせていくようなので、HDPにImpalaを統合してくれればもっと選択肢が増えて嬉しいなとちょっと思ったりしました。




おまけ




後編まで待てない(?)方のために、HiveでDruidのテーブルの例だけ載せておきます。とても簡単ですね。
HDP3のHiveクライアントはbeelineに統一されたようなので、このようにしてHive LLAPに繋ぎます。HiveとHive LLAPで繋ぐ先が違うので要注意です。
beeline -n hive -u “jdbc:hive2://hdp3-m1.testhdp.com:2181,hdp3-m2.testhdp.com:2181,hdp3-m3.testhdp.com:2181/hivedb;serviceDcoveryMode=zooKeeper;zooKeeperNamespace=hiveserver2-interactive”




CREATE EXTERNAL TABLE druidtbl_page_views(
 `__time`        timestamp,
 uuid            string,
 document_id     int,
 platform        int,
 geo_location    string,
 traffic_source  int)
STORED BY 'org.apache.hadoop.hive.druid.DruidStorageHandler'
TBLPROPERTIES(
'druid.segment.granularity'='SECOND',
'druid.query.granularity'='SECOND',
'druid.datasource'='druidtbl_page_views');



Druidテーブルの注意点は、
・Hiveの外部テーブルとして作成する(CREATE EXTERNAL TABLE)
・実質的なPKは自動的にタイムスタンプの「__time」(※先頭にアンダーバー二つ)カラムとなるため必ず定義する
 タイムスタンプ型のカラムは基本的には1テーブルに1つしか定義できない
・TBLPROPERTIES句に、druid.datasourceを書かないとエラーが出る




今回は構築編ということでHive+LLAP+Druid環境の構築とパラメータ設定を試しました。後編では、実際にデータをロードして、Hive LLAPやDruidのクエリ検証やマテリアライズドビューなどを試した結果をまとめる予定です。




最後に




次世代システム研究室では、データ分析エンジニアやアーキテクトを募集しています。ビッグデータの解析業務など次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ 募集職種一覧 からご応募をお願いします。




皆さんのご応募をお待ちしています。