2018년 11월 22일 목요일

x86 hadoop cluster의 HDFS를 IBM POWER linux (ppc64le) 서버에 mount하기

x86 서버로 구성된 hadoop cluster의 HDFS에 AC922과 같은 IBM POWER linux (ppc64le) 서버가 access해야 할 경우가 있습니다.  이럴 때 가장 편리한 방법은 HortonWorks나 Cloudera 등에 포함된 NFS Gateway service를 이용하는 것입니다.   IBM POWER linux 쪽에서는 그냥 NFS mount만 하면 되며, NFS Gateway service는 x86 hadoop cluster에서 설정하면 됩니다.  IBM POWER linux 쪽에서는 그냥 일반 NFS처럼 read/write가 가능합니다.


아래에 정리된 HOW TO는 Cloudera 6.x을 기준으로, 다음 문서부터 시작되는 매뉴얼을 따라 진행했습니다.

https://www.cloudera.com/documentation/enterprise/6/6.0/topics/configure_cm_repo.html#cm_repo


아래에서, powervc131이라는 서버는 Redhat 7.5 x86_64 서버이고, redhat74라는 서버는 Redhat 7.5 ppc64le, 즉 IBM POWER linux 서버입니다.

먼저 Cloudera가 설치된 x86 서버에서 hadoop 버전을 확인합니다.  Cloudera 6.x이므로 hadoop 버전은 3.0.0입니다.

[ibm@powervc131 ~]$ hadoop version
Hadoop 3.0.0-cdh6.0.1
Source code repository http://github.com/cloudera/hadoop -r 47165556c2149deb60153448d73226104921b1ef
Compiled by jenkins on 2018-09-19T16:09Z
Compiled with protoc 2.5.0
From source with checksum a3d0e319db58ceb558757daf384381c
This command was run using /opt/cloudera/parcels/CDH-6.0.1-1.cdh6.0.1.p0.590678/jars/hadoop-common-3.0.0-cdh6.0.1.jar

[ibm@powervc131 ~]$ hadoop fs -df
Filesystem                     Size        Used    Available  Use%
hdfs://powervc131:8020  48294789120  1428176896  11857518592    3%

HDFS의 /user/root 밑에 input이라는 directory를 만들고 거기에 OS의 /etc/hosts 파일을 put 명령으로 복사해 넣습니다.

[ibm@powervc131 ~]$ sudo -u hdfs hadoop fs -mkdir /user/root

[ibm@powervc131 ~]$ sudo -u hdfs hadoop fs -chown root /user/root

[ibm@powervc131 ~]$ sudo hadoop fs -mkdir /user/root/input

[ibm@powervc131 ~]$ sudo hadoop fs -ls
Found 1 items
drwxr-xr-x   - root supergroup          0 2018-11-22 16:06 input

[ibm@powervc131 ~]$ sudo hadoop fs -put /etc/hosts input

그 내용은 아래와 같습니다.

[ibm@powervc131 ~]$ sudo hadoop fs -text input/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
10.10.14.71    powervc131
10.10.14.66    nim


혹시 아직 Cloudera manager에 NFS Gateway service가 추가되어 있지 않다면 다음과 같이 추가하시면 됩니다.  먼저, Cloudera manager에서 '인스턴스' tab을 클릭합니다.  그리고 '역할 인스턴스 추가' 상자를 클릭합니다.



그리고 오른쪽의 'NFS Gateway'의 아래에 있는 '호스트 선택' 부분을 클릭하여 NFS Gateway로 사용할 노드를 지정합니다.  여기서는 1대 뿐인 hadoop cluster이므로, Cloudera manager가 곧 name node요 data node이자 NFS Gateway 서버입니다.  그리고 이 서버에는 이미 NFS Gateway service가 추가되어 있습니다.




이제 '인스턴스' tab에서 보면 '역할 유형'에 NFS Gateway가 보입니다만, 현재는 '중지됨' 상태입니다.  이것을 클릭하여 구성으로 들어갑니다.



NFS Gateway service의 구성을 확인합니다.  기본적으로 다른 모든 서버가 read/write 권한을 가지고 access할 수 있도록, 허용된 호스트 및 권한 (dfs.nfs.exports.allowed.hosts) 부분은 " * rw "로 되어 있습니다.



이제 '인스턴스' tab에서 NFS Gateway를 선택하고 '선택된 작업' 상자를 클릭하여 start 합니다.  또는 아래와 같이 NFS Gateway를 클릭하여 들어간 뒤 '작업' 상자를 클릭하여 start 해도 됩니다.




이때 이 NFS Gateway 서버로 지정된 x86 서버 (여기서는 Cloudera manager 서버이자 data node이자 NFS Gateway 서버)에 혹시 OS에서 NFS 서비스가 활성화된 상태라면 'sudo systemctl stop nfs'로 비활성화를 미리 시켜 두어야 합니다.   그렇지 않을 경우 'NFS 서비스가 이미 start 되어 있다'라는 error가 발생할 것입니다.

[ibm@powervc131 ~]$ sudo systemctl status nfs
● nfs-server.service - NFS server and services
   Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; enabled; vendor preset: disabled)
   Active: inactive (dead) since Thu 2018-11-22 16:35:08 KST; 9min ago
  Process: 30866 ExecStopPost=/usr/sbin/exportfs -f (code=exited, status=0/SUCCESS)
  Process: 30863 ExecStopPost=/usr/sbin/exportfs -au (code=exited, status=0/SUCCESS)
  Process: 30861 ExecStop=/usr/sbin/rpc.nfsd 0 (code=exited, status=0/SUCCESS)
 Main PID: 2270 (code=exited, status=0/SUCCESS)

Nov 22 16:35:08 powervc131 systemd[1]: Stopping NFS server and services...
Nov 22 16:35:08 powervc131 systemd[1]: Stopped NFS server and services.



NFS Gateway service의 start가 완료된 뒤, x86 서버에서 showmount 명령을 통해 이 서버에서 export된 NFS directory를 확인합니다.  이때 10.10.14.71은 물론 x86 서버의 IP address입니다.   다음과 같이 / (OS의 /가 아니라 HDFS의 / 입니다)가 모든 권한을 다 주는 형태로 export 되어있는 것을 확인하실 수 있습니다.

[ibm@powervc131 ~]$ showmount -e 10.10.14.71
Export list for 10.10.14.71:
/ *


이제 IBM POWER linux 서버로 가서, 이 NFS를 mount 합니다.  일반적인 NFS mount와 동일합니다.

[bsyu@redhat74 ~]$ sudo mkdir /hdfs

[bsyu@redhat74 ~]$ sudo mount 10.10.14.71:/ /hdfs

NFS가 hdfs서버인 10.10.14.71로부터 mount되었는지 확인합니다.

[bsyu@redhat74 ~]$ df -h
Filesystem             Size  Used Avail Use% Mounted on
/dev/mapper/rhel-root   26G   16G   11G  58% /
devtmpfs               3.7G     0  3.7G   0% /dev
tmpfs                  3.8G     0  3.8G   0% /dev/shm
tmpfs                  3.8G   16M  3.8G   1% /run
tmpfs                  3.8G     0  3.8G   0% /sys/fs/cgroup
/dev/mapper/mpathb2   1014M  178M  837M  18% /boot
tmpfs                  765M     0  765M   0% /run/user/0
tmpfs                  765M     0  765M   0% /run/user/1001
10.10.14.71:/           45G   35G   11G  76% /hdfs

이제 그 mount point인 /hdfs에 들어가서 어떤 파일이 들어있는지 확인합니다.  HDFS의 /가 mount된 것을 확인하실 수 있습니다.

[bsyu@redhat74 ~]$ cd /hdfs

[bsyu@redhat74 hdfs]$ ls
tmp  user

[bsyu@redhat74 hdfs]$ cd user/

[bsyu@redhat74 user]$ ls
history  hive  hue  oozie  root  spark  yarn

[bsyu@redhat74 user]$ cd root

[bsyu@redhat74 root]$ ls
input

[bsyu@redhat74 root]$ cd input

[bsyu@redhat74 input]$ ls
hosts

아까 넣어둔 hosts 파일도 그대로 보입니다.  이것을 vi로 edit해서 한줄을 더 넣어보겠습니다.

[bsyu@redhat74 input]$ sudo vi hosts
...
10.10.14.66    nim
Cloudera HDFS was accessed by Redhat ppc64le on POWER server using NFS Gateway.

Save한 뒤 이제 다시 x86 서버의 HDFS로 가서 위의 한줄이 저장되어 있는지 확인합니다.

[ibm@powervc131 ~]$ sudo hadoop fs -text input/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
10.10.14.71    powervc131
10.10.14.66    nim
Cloudera HDFS was accessed by Redhat ppc64le on POWER server using NFS Gateway.

잘 된 것을 보실 수 있습니다.




--------------------------------------------------------

별첨 : 아래는 x86서버에 Cloudera를 설치하는 과정입니다. 

[ibm@powervc131 ~]$ sudo wget https://archive.cloudera.com/cm6/6.0.1/redhat7/yum/cloudera-manager.repo -P /etc/yum.repos.d/

[ibm@powervc131 ~]$ sudo rpm --import https://archive.cloudera.com/cm6/6.0.0/redhat7/yum/RPM-GPG-KEY-cloudera

[ibm@powervc131 ~]$ sudo yum install oracle-j2sdk1.8

[ibm@powervc131 ~]$ sudo yum install cloudera-manager-daemons cloudera-manager-agent cloudera-manager-server

[ibm@powervc131 ~]$ sudo yum install postgresql-server

[ibm@powervc131 ~]$ sudo yum install python-pip

[ibm@powervc131 ~]$ sudo pip install psycopg2==2.7.5 --ignore-installed

[ibm@powervc131 ~]$ cat /etc/locale.conf
LANG="en_US.UTF-8"
LC_ALL="en_US.UTF-8"

[ibm@powervc131 ~]$ su - postgres

-bash-4.2$ sudo postgresql-setup initdb

-bash-4.2$ sudo vi /var/lib/pgsql/data/pg_hba.conf
...
host    all             all             127.0.0.1/32            md5  #newly inserted
host    all             all             127.0.0.1/32            ident
...

[ibm@powervc131 ~]$ sudo systemctl enable postgresql

[ibm@powervc131 ~]$ sudo systemctl start postgresql

[ibm@powervc131 ~]$ sudo -u postgres psql

postgres=# CREATE ROLE scm LOGIN PASSWORD 'scm';
CREATE ROLE
postgres=# CREATE DATABASE scm OWNER scm ENCODING 'UTF8';
CREATE DATABASE
postgres=# CREATE ROLE amon LOGIN PASSWORD 'amon';
CREATE ROLE
postgres=# CREATE DATABASE amon OWNER amon ENCODING 'UTF8';
CREATE DATABASE
postgres=# CREATE ROLE rman LOGIN PASSWORD 'rman';
CREATE ROLE
postgres=# CREATE DATABASE rman OWNER rman ENCODING 'UTF8';
CREATE DATABASE
postgres=# CREATE ROLE hue LOGIN PASSWORD 'hue';
CREATE ROLE
postgres=# CREATE DATABASE hue OWNER hue ENCODING 'UTF8';
CREATE DATABASE
postgres=# CREATE ROLE hive LOGIN PASSWORD 'hive';
CREATE ROLE
postgres=# CREATE DATABASE metastore OWNER hive ENCODING 'UTF8';
CREATE DATABASE
postgres=# CREATE ROLE sentry LOGIN PASSWORD 'sentry';
CREATE ROLE
postgres=# CREATE DATABASE sentry OWNER sentry ENCODING 'UTF8';
CREATE DATABASE
postgres=# CREATE ROLE nav LOGIN PASSWORD 'nav';
CREATE ROLE
postgres=# CREATE DATABASE nav OWNER nav ENCODING 'UTF8';
CREATE DATABASE
postgres=# CREATE ROLE navms LOGIN PASSWORD 'navms';
CREATE ROLE
postgres=# CREATE DATABASE navms OWNER navms ENCODING 'UTF8';
CREATE DATABASE
postgres=# CREATE ROLE oozie LOGIN PASSWORD 'oozie';
CREATE ROLE
postgres=# CREATE DATABASE oozie OWNER oozie ENCODING 'UTF8';
CREATE DATABASE
postgres=# ALTER DATABASE metastore SET standard_conforming_strings=off;
ALTER DATABASE
postgres=# ALTER DATABASE oozie SET standard_conforming_strings=off;
ALTER DATABASE


[ibm@powervc131 ~]$ wget https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-5.1.46.tar.gz

[ibm@powervc131 files]$ tar -zxvf ../mysql-connector-java-5.1.46.tar.gz

[ibm@powervc131 files]$ sudo mkdir -p /usr/share/java/

[ibm@powervc131 files]$ cd mysql-connector-java-5.1.46

[ibm@powervc131 mysql-connector-java-5.1.46]$ cp mysql-connector-java-5.1.46-bin.jar /usr/share/java/


[ibm@powervc131 ~]$ sudo /opt/cloudera/cm/schema/scm_prepare_database.sh postgresql scm scm scm
JAVA_HOME=/usr/java/jdk1.8.0_141-cloudera
Verifying that we can write to /etc/cloudera-scm-server
Creating SCM configuration file in /etc/cloudera-scm-server
Executing:  /usr/java/jdk1.8.0_141-cloudera/bin/java -cp /usr/share/java/mysql-connector-java.jar:/usr/share/java/oracle-connector-java.jar:/usr/share/java/postgresql-connector-java.jar:/opt/cloudera/cm/schema/../lib/* com.cloudera.enterprise.dbutil.DbCommandExecutor /etc/cloudera-scm-server/db.properties com.cloudera.cmf.db.
[                          main] DbCommandExecutor              INFO  Successfully connected to database.
All done, your SCM database is configured correctly!


[ibm@powervc131 ~]$ sudo systemctl start cloudera-scm-server

[ibm@powervc131 ~]$ sudo tail -f /var/log/cloudera-scm-server/cloudera-scm-server.log
...
2018-11-22 14:46:30,746 INFO WebServerImpl:org.eclipse.jetty.server.AbstractConnector: Started ServerConnector@143ff757{HTTP/1.1,[http/1.1]}{0.0.0.0:7180}
2018-11-22 14:46:30,750 INFO WebServerImpl:org.eclipse.jetty.server.Server: Started @92563ms
2018-11-22 14:46:30,750 INFO WebServerImpl:com.cloudera.server.cmf.WebServerImpl: Started Jetty server.


이제부터는 http://<서버주소>:7180로 들어갑니다.   기본 id/passwd는 admin/admin입니다.   혹시 web에서 접속이 되지 않을 경우 firewalld와 iptables를 중단시키십시요.

[ibm@powervc131 cm]$ sudo systemctl stop iptables
[ibm@powervc131 cm]$ sudo systemctl stop firewalld















2018년 11월 21일 수요일

Redhat ppc64le 환경에서의 boost와 pyarrow build 및 설치

Redhat 7.5의 기본 gcc 버전은 4.8.5입니다.   OS의 주요 library들도 모두 gcc 4.8.5로 build되어 있습니다.   그런데 Anaconda의 v5.2부터는 python이 gcc 7.2.0으로 build되어 있습니다.

[bsyu@redhat74 cudf]$ python
Python 3.7.0 (default, Jun 28 2018, 13:02:24)
[GCC 7.2.0] :: Anaconda, Inc. on linux

이로 인해 벌어지는 문제 중 하나가, OS의 기본 gcc/g++을 사용해 build한 python package의 경우 아래처럼 undefined symbol error를 내는 경우가 많다는 것입니다.

ImportError: /home/bsyu/anaconda3/lib/python3.7/site-packages/pyarrow/libparquet.so.12: undefined symbol: _ZN5boost13match_resultsIN9__gnu_cxx17__normal_iteratorIPKcNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEESaINS_9sub_matchISB_EEEE12maybe_assignERKSF_

이는 gcc 5.1부터 CXXABI가 달라졌기 때문입니다.  그에 대한 자세한 내용은 아래에 나와 있습니다. 

https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html

이 문제를 해결하려면 gcc 버전을 7.2로 올리는 것이 좋습니다.  그에 대해서는 아래 link를 따라 하시면 됩니다.

http://hwengineer.blogspot.com/2018/05/ppc64le-gcc7-cmake3-source-build.html

이제 gcc 7.2.0을 갖게 되었습니다.

[bsyu@redhat74 files]$ which gcc
/usr/local/bin/gcc

[bsyu@redhat74 files]$ gcc --version
gcc (GCC) 7.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

OS 기본 gcc가 아닌, 새로 만든 gcc 7.2.0을 쓰기 위해서는 PATH와 LD_LIBRARY_PATH를 환경변수에서 /usr/local을 먼저 참조하도록 설정하십시요.

[bsyu@redhat74 files]$ cat ~/.bashrc
...
export PATH=/usr/local/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/lib64:/usr/local/lib:/usr/lib64:/usr/lib:/lib64:/lib:$LD_LIBRARY_PATH
export MAKEFLAGS=-j16
export ARROW_BUILD_TYPE=release

이제 anaconda3를 설치하시고...

[bsyu@redhat74 files]$ ./Anaconda3-5.3.0-Linux-ppc64le.sh

[bsyu@redhat74 files]$ which python
~/anaconda3/bin/python

[bsyu@redhat74 files]$ python
Python 3.7.0 (default, Jun 28 2018, 13:02:24)
[GCC 7.2.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.

pyarrow를 설치하기 위해서는 먼저 boost library들도 gcc 7.2로 build 해야 합니다.  OS에서 기본 제공되는 것들은 맨 위의 예와 같이 undefined symbol error를 내기 때문입니다.

[bsyu@redhat74 files]$ wget https://dl.bintray.com/boostorg/release/1.68.0/source/boost_1_68_0.tar.gz

[bsyu@redhat74 files]$ tar -zxf boost_1_68_0.tar.gz

여기서 나중에 "pyconfig.h Not Found" error를 피하기 위해서 아래와 같이 pyconfig.h를 살짝 link를 걸어 줘야 합니다.

[bsyu@redhat74 include]$ ln -s python3.7m/pyconfig.h pyconfig.h

[bsyu@redhat74 files]$ cd boost_1_68_0

[bsyu@redhat74 boost_1_68_0]$ ./bootstrap.sh --with-python=/home/bsyu/anaconda3/bin/python --with-python-root=/home/bsyu/anaconda3

[bsyu@redhat74 boost_1_68_0]$ ./b2 -j16

[bsyu@redhat74 boost_1_68_0]$ sudo ./b2 install

이제 boost library들이 설치되었습니다.   이제 pyarrow를 build 합니다.

[bsyu@redhat74 files]$ conda install numpy six setuptools cython pandas pytest cmake flatbuffers rapidjson boost-cpp thrift snappy zlib gflags brotli lz4-c zstd -c conda-forge

(base) [bsyu@redhat74 files]$ which cmake
~/anaconda3/bin/cmake
(base) [bsyu@redhat74 files]$ cmake --version
cmake version 3.12.2

(base) [bsyu@redhat74 files]$ git clone https://github.com/apache/arrow.git

(base) [bsyu@redhat74 files]$ cd arrow

(base) [bsyu@redhat74 arrow]$ export CC=/usr/local/bin/gcc
(base) [bsyu@redhat74 arrow]$ export CXX=/usr/local/bin/g++

(base) [bsyu@redhat74 arrow]$ mkdir cpp/build && cd cpp/build

(base) [bsyu@redhat74 build]$ cmake -DCMAKE_BUILD_TYPE=release -DARROW_PYTHON=on -DARROW_PLASMA=on -DARROW_BUILD_TESTS=OFF  -DARROW_PARQUET=ON  ..

(base) [bsyu@redhat74 build]$ make -j16

(base) [bsyu@redhat74 build]$ sudo make install

(base) [bsyu@redhat74 build]$ cd ../../python

(base) [bsyu@redhat74 python]$ export ARROW_HOME=/usr/local

(base) [bsyu@redhat74 python]$ MAKEFLAGS=-j16 python setup.py build_ext --build-type=$ARROW_BUILD_TYPE --with-parquet --inplace

(base) [bsyu@redhat74 python]$ python setup.py build_ext --build-type=release --with-parquet --bundle-arrow-cpp bdist_wheel

위까지 마치면 dist directory 밑에 wheel file이 생성되어 있습니다.

(base) [bsyu@redhat74 python]$ ls -ltr dist
-rw-rw-r-- 1 bsyu bsyu 9645047 Nov 21 10:42 pyarrow-0.11.1.dev264+g7e6bf41.d20181121-cp37-cp37m-linux_ppc64le.whl

이제 이것을 pip로 설치합니다.

(base) [bsyu@redhat74 python]$ pip install ./dist/pyarrow-0.11.1.dev264+g7e6bf41.d20181121-cp37-cp37m-linux_ppc64le.whl

이제 import pyarrow를 해보면 맨 위의 예에서 보이던 undefined symbol error가 없어진 것을 확인하실 수 있습니다.

(base) [bsyu@redhat74 python]$ python
Python 3.7.0 (default, Jun 28 2018, 13:02:24)
[GCC 7.2.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyarrow
>>>

여기서 만든 pyarrow*.whl은 아래 google drive에 올려놓았습니다.   python 3.7용입니다.

https://drive.google.com/open?id=16cF8F9A2a8ZtpnpV0PdckJMyotkVYEns


참고로 ldd로 보면, 이제 lib.cpython-37m-powerpc64le-linux-gnu.so가 OS에서 기본 제공하는 library (/usr/lib64/libstdc++.so.6, /usr/lib/libboost_regex.so 등 )가 아닌 /usr/local/lib64/libstdc++.so.6, /usr/local/lib/libboost_regex.so 등을 참조하는 것을 보실 수 있습니다.

(base) [bsyu@redhat74 ~]$ ldd /home/bsyu/anaconda3/lib/python3.7/site-packages/pyarrow/lib.cpython-37m-powerpc64le-linux-gnu.so
        linux-vdso64.so.1 =>  (0x00003fff9f750000)
        libarrow.so.12 => /usr/local/lib64/libarrow.so.12 (0x00003fff9efc0000)
        libarrow_python.so.12 => /usr/local/lib64/libarrow_python.so.12 (0x00003fff9ee70000)
        libparquet.so.12 => /usr/local/lib64/libparquet.so.12 (0x00003fff9ebf0000)
        libstdc++.so.6 => /usr/local/lib64/libstdc++.so.6 (0x00003fff9e9c0000)
        libm.so.6 => /usr/lib64/libm.so.6 (0x00003fff9e8d0000)
        libgcc_s.so.1 => /usr/local/lib64/libgcc_s.so.1 (0x00003fff9e890000)
        libc.so.6 => /usr/lib64/libc.so.6 (0x00003fff9e6a0000)
        libdl.so.2 => /usr/lib64/libdl.so.2 (0x00003fff9e670000)
        libpthread.so.0 => /usr/lib64/libpthread.so.0 (0x00003fff9e630000)
        libz.so.1 => /usr/lib64/libz.so.1 (0x00003fff9e5f0000)
        libboost_system.so.1.68.0 => /usr/local/lib/libboost_system.so.1.68.0 (0x00003fff9e5c0000)
        libboost_filesystem.so.1.68.0 => /usr/local/lib/libboost_filesystem.so.1.68.0 (0x00003fff9e580000)
        libboost_regex.so.1.68.0 => /usr/local/lib/libboost_regex.so.1.68.0 (0x00003fff9e440000)
        librt.so.1 => /usr/lib64/librt.so.1 (0x00003fff9e410000)
        /lib64/ld64.so.2 (0x000000007f930000)
        libutil.so.1 => /usr/lib64/libutil.so.1 (0x00003fff9e3e0000)