Эта статья послужит практическим руководством по сборке, начальной настройке и тестированию работоспособности Hadoop начинающим администраторам. Мы разберем, как собрать Hadoop из исходников, сконфигурировать, запустить и проверить, что все работает, как надо. В статье вы не найдете теоретической части. Если вы раньше не сталкивались с Hadoop, не знаете из каких частей он состоит и как они взаимодействуют, вот пара полезных ссылок на официальную документацию:

hadoop.apache.org/docs/r2.7.3/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html
hadoop.apache.org/docs/r2.7.3/hadoop-yarn/hadoop-yarn-site/YARN.html

Почему просто не использовать готовый дистрибутив?

— Обучение. Похожие статьи часто начинаются с рекомендаций скачать образ виртуальной машины с дистрибутивом Cloudera или HortonWorks. Как правило, дистрибутив – сложная экосистема с уймой компонент. Новичку будет непросто разобраться, где что, и как это все взаимодействует. Начиная from scratch мы немного уменьшаем порог вхождения, так как имеем возможность рассматривать компоненты по одной.

— Функциональные тесты и бенчмарки. Есть небольшой лаг между выходом новой версии продукта, и моментом, когда она появляется в дистрибутиве. Если вам необходимо протестировать новые функции только что появившейся версии, Вы не сможете использовать готовый дистрибутив. Также будет сложно сравнить производительность двух версий одного и того же софта, так как в готовых дистрибутивах как правило отсутствует возможность обновить версию какого-либо одного компонента, оставив все остальное как есть.

— Just for fun.

Почему собираем из исходников? Ведь бинарные сборки Hadoop также доступны.

Часть кода Hadoop написана на C/C++. Не знаю, на какой системе делает сборки команда разработчиков, но С-библиотеки, поставляемые вместе с бинарными сборками Hadoop, зависят от версии libc, которой нет ни в RHEL, ни в Debian/Ubuntu. Неработоспособность С-библиотек Hadoop в общем случае не критично, но некоторые фичи без них работать не будут.

Зачем заново описывать все то, что и так есть в официальной документации?

Статья призвана сэкономить время. Официальная документация не содержит quickstart-инструкций – делай так и оно заработает. Если вам по той или иной причине необходимо собрать “ванильный” Hadoop, но нет времени на то, чтоб делать это методом проб и ошибок, вы зашли по адресу.

Сборка


Для сборки будем использовать CentOS 7. Если верить Сloudera, большинство кластеров работают именно на RHEL и производных (CentOS, Oracle Linux). 7-я версия подходит больше всего, так как в ее репозиториях уже есть библиотека protobuf нужной версии. Если Вы хотите использовать CentOS 6, будет необходимо собрать protobuf самостоятельно.

Сборку и прочие эксперименты будем проводить с привилегиями root (чтоб не усложнять статью).

Где-то 95% кода Hadoop написано на Java. Для сборки нам понадобятся Oracle JDK и Maven.

Загружаем последнюю версию JDK с сайта Oracle и разархивируем в /opt. Так же добавим переменную JAVA_HOME (используется Hadoop) и добавим /opt/java/bin в PATH для пользователя root (для удобства):

cd ~ 
wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u112-b15/jdk-8u112-linux-x64.tar.gz 
tar xvf ~/jdk-8u112-linux-x64.tar.gz 
mv ~/jdk1.8.0_112 /opt/java 
echo "PATH=\"/opt/java/bin:\$PATH\"" >> ~/.bashrc 
echo "export JAVA_HOME=\"/opt/java\"" >> ~/.bashrc 

Устанавливаем Мaven. Он будет необходим только на этапе сборки. По-этому установим его в наш home (после окончания сборки все файлы, которые останутся в home, можно будет удалить).

cd ~ 
wget http://apache.rediris.es/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz 
tar xvf ~/apache-maven-3.3.9-bin.tar.gz 
mv ~/apache-maven-3.3.9 ~/maven 
echo "PATH=\"/root/maven/bin:\$PATH\"" >> ~/.bashrc 
source ~/.bashrc 

Где-то 4-5% кода Hadoop написано на C/C++. Установим компилятор и прочие пакеты необходимые для сборки:

 yum -y install gcc gcc-c++ autoconf automake libtool cmake

Также нам понадобятся некоторые сторонние библиотеки:

yum -y install zlib-devel openssl openssl-devel snappy snappy-devel bzip2 bzip2-devel protobuf protobuf-devel 

Система готова. Скачиваем, собираем и устанавливаем Hadoop в /opt:

cd ~ 
wget http://apache.rediris.es/hadoop/common/hadoop-2.7.3/hadoop-2.7.3-src.tar.gz 
tar -xvf ~/hadoop-2.7.3-src.tar.gz 
mv ~/hadoop-2.7.3-src ~/hadoop-src 
cd ~/hadoop-src 
mvn package -Pdist,native -DskipTests -Dtar 
tar -C/opt -xvf ~/hadoop-src/hadoop-dist/target/hadoop-2.7.3.tar.gz 
mv /opt/hadoop-* /opt/hadoop 
echo "PATH=\"/opt/hadoop/bin:\$PATH\"" >> ~/.bashrc 
source ~/.bashrc 

Первичная конфигурация


Hadoop насчитывает около тысячи параметров. К счастью, чтобы запустить Hadoop и сделать некоторые первые шаги в освоении достаточно около 40, оставив остальное по умолчанию.

Приступим. Если помните, мы установили Hadoop в /opt/hadoop. Все конфигурационные файлы находятся в /opt/hadoop/etc/hadoop. В общей сложности потребуется отредактировать 6 конфигурационных файлов. Все конфиги ниже привожу в виде команд. Для того, чтобы те, кто пытается собрать свой Hadoop по этой статье, могли просто копипастить команды в консоль.

Во-первых, установим переменную окружения JAVA_HOME в файлах hadoop-env.sh и yarn-env.sh. Так мы дадим всем компонентам знать, где установлена java, которую они должны использовать.

sed -i '1iJAVA_HOME=/opt/java' /opt/hadoop/etc/hadoop/hadoop-env.sh 
sed -i '1iJAVA_HOME=/opt/java' /opt/hadoop/etc/hadoop/yarn-env.sh 

Сконфигурируем URL для HDFS в файле core-site.xml. Он состоит из префикса hdfs://, имени хоста, на котором запущен NameNode и порта. Если этого не сделать, Hadoop не будет использовать распределенную файловую систему, а будет работать с локальной ФС на вашем компьютере (URL по умолчанию: file:///).

cat << EOF > /opt/hadoop/etc/hadoop/core-site.xml 
<configuration> 
  <property><name>fs.defaultFS</name><value>hdfs://localhost:8020</value></property> 
</configuration> 
EOF 

В файле hdfs-site.xml конфигурируем 4 параметра. Количество реплик устанавливаем в 1, так как наш “кластер” состоит всего из одной ноды. Также конфигурируем директории, где будут хранить данные NameNode, DataNode и SecondaryNameNode.

cat << EOF > /opt/hadoop/etc/hadoop/hdfs-site.xml 
<configuration> 
  <property><name>dfs.replication</name><value>1</value></property> 
  <property><name>dfs.namenode.name.dir</name><value>/data/dfs/nn</value></property> 
  <property><name>dfs.datanode.data.dir</name><value>/data/dfs/dn</value></property> 
  <property><name>dfs.namenode.checkpoint.dir</name><value>/data/dfs/snn</value></property> 
</configuration> 
EOF

Мы закончили настройку HDFS. Можно было бы запустить NameNode и DataNode, и поработать с ФС. Но оставим это для следующего раздела. Перейдем к конфигурации YARN.

cat << EOF > /opt/hadoop/etc/hadoop/yarn-site.xml 
<configuration> 
  <property><name>yarn.resourcemanager.hostname</name><value>localhost</value></property> 
  <property><name>yarn.nodemanager.resource.memory-mb</name><value>4096</value></property> 
  <property><name>yarn.nodemanager.resource.cpu-vcores</name><value>4</value></property> 
  <property><name>yarn.scheduler.maximum-allocation-mb</name><value>1024</value></property> 
  <property><name>yarn.scheduler.maximum-allocation-vcores</name><value>1</value></property> 
  <property><name>yarn.nodemanager.vmem-check-enabled</name><value>false</value></property> 
  <property><name>yarn.nodemanager.local-dirs</name><value>/data/yarn</value></property> 
  <property><name>yarn.nodemanager.log-dirs</name><value>/data/yarn/log</value></property> 
  <property><name>yarn.log-aggregation-enable</name><value>true</value></property> 
  <property><name>yarn.nodemanager.aux-services</name><value>mapreduce_shuffle</value></property> 
  <property><name>yarn.nodemanager.aux-services.mapreduce_shuffle.class</name><value>org.apache.hadoop.mapred.ShuffleHandler</value></property> 
</configuration>
EOF 

Параметров довольно много. Пройдемся по ним по порядку.

Параметр yarn.resourcemanager.hostname указывает, на каком хосте запущен сервис ResourceManager.

Параметры yarn.nodemanager.resource.memory-mb и yarn.nodemanager.resource.cpu-vcores являются, пожалуй, самыми важными. В них мы сообщаем кластеру, сколько памяти и ядер CPU может использовать каждая нода в общей сложности для запуска контейнеров.

Параметры yarn.scheduler.maximum-allocation-mb и yarn.scheduler.maximum-allocation-vcores указывают, сколько памяти и ядер максимально может выделяться под отдельный контейнер. Нетрудно видеть, что с данной конфигурацией в нашем “кластере”, состоящим из одной ноды, могут одновременно быть запущены 4 контейнера (с 1GB памяти каждый).

Параметр yarn.nodemanager.vmem-check-enabled установленный в false, отключает проверку количества используемой виртуальной памяти. Как видно из предыдущего абзаца, каждому контейнеру доступно не так много памяти, и при такой конфигурации любое приложение наверняка привысит лимит доступной виртуальной памяти.

Параметр yarn.nodemanager.local-dirs указывает, где будут храниться временные данные контейнеров (jar с байткодом приложения, файлы конфигурации, временные данные, сгенерированные во время исполнения, …)

Параметр yarn.nodemanager.log-dirs указывает, где локально будут храниться логи каждого таска.

Параметр yarn.log-aggregation-enable указывает хранить логи в HDFS. После окончания исполнения приложения, его логи из yarn.nodemanager.log-dirs каждой ноды будут перемещены в HDFS (по умолчанию – в директорию /tmp/logs).

Параметры yarn.nodemanager.aux-services и yarn.nodemanager.aux-services.mapreduce_shuffle.class указывают сторонний shuffle-сервис для фреймворка MapReduce.

Вот пожалуй и все для YARN. Приведу также конфигурацию для MapReduce (один из возможных фреймворков распределенных вычислений). Хоть он в последнее время и потерял популярность в связи с появлением Spark, однако еще много где используется.

cat << EOF > /opt/hadoop/etc/hadoop/mapred-site.xml 
<configuration> 
  <property><name>mapreduce.framework.name</name><value>yarn</value></property> 
<property><name>mapreduce.jobhistory.address</name><value>localhost:10020</value></property> 
  <property><name>mapreduce.jobhistory.webapp.address</name><value>localhost:19888</value></property> 
  <property><name>mapreduce.job.reduce.slowstart.completedmaps</name><value>0.8</value></property> 
  <property><name>yarn.app.mapreduce.am.resource.cpu-vcores</name><value>1</value></property> 
  <property><name>yarn.app.mapreduce.am.resource.mb</name><value>1024</value></property> 
  <property><name>yarn.app.mapreduce.am.command-opts</name><value>-Djava.net.preferIPv4Stack=true -Xmx768m</value></property> 
  <property><name>mapreduce.map.cpu.vcores</name><value>1</value></property> 
  <property><name>mapreduce.map.memory.mb</name><value>1024</value></property> 
  <property><name>mapreduce.map.java.opts</name><value>-Djava.net.preferIPv4Stack=true -Xmx768m</value></property> 
  <property><name>mapreduce.reduce.cpu.vcores</name><value>1</value></property> 
  <property><name>mapreduce.reduce.memory.mb</name><value>1024</value></property> 
  <property><name>mapreduce.reduce.java.opts</name><value>-Djava.net.preferIPv4Stack=true -Xmx768m</value></property> 
 </configuration>
EOF 

Параметр mapreduce.framework.name указывает, что мы будем запускать задачи MapReduce в YARN (значение по умолчанию local используется только для отладки – все задачи запускаются в одной и той же jvm на одной и той же машине).

Параметры mapreduce.jobhistory.address и mapreduce.jobhistory.webapp.address указывают имя ноды, на которой будет запущен сервис JobHistory.

Параметр mapreduce.job.reduce.slowstart.completedmaps указывает запускать фазу reduce не ранее, чем выполнится 80% фазы map.

Остальные параметры задают максимально фозможные значения памяти и ядер CPU и jvm heap для мапперов, редьюсеров и application master-ов. Как видите, они не должны превышать соответствующим значениям для контейнеров YARN, которые мы определили в yarn-site.xml. Значения jvm heap как правило устанавливают в 75% от параметров *.memory.mb.

Пуск


Создадим директорию /data, в которой будут храниться данные HDFS, а так же временные файлы контейнеров YARN.

mkdir /data

Отформатируем HDFS

hadoop namenode -format 

И, наконец, запустим все сервисы нашего «кластера»:


/opt/hadoop/sbin/hadoop-daemon.sh start namenode 
/opt/hadoop/sbin/hadoop-daemon.sh start datanode 
/opt/hadoop/sbin/yarn-daemon.sh start resourcemanager 
/opt/hadoop/sbin/yarn-daemon.sh start nodemanager 
/opt/hadoop/sbin/mr-jobhistory-daemon.sh start historyserver 

Если все прошло удачно (можно проверить сообщения об ошибках в логах в /opt/hadoop/logs), Hadoop развернут и готов к работе…

Проверка работоспособности


Посмотрим на структуру директорий hadoop:

/opt/hadoop/ 
+-- bin 
+-- etc 
¦   L-- hadoop 
+-- include 
+-- lib 
¦   L-- native 
+-- libexec 
+-- logs 
+-- sbin 
L-- share 
    +-- doc 
    ¦   L-- hadoop 
    L-- hadoop 
        +-- common 
        +-- hdfs 
        +-- httpfs 
        +-- kms 
        +-- mapreduce 
        +-- tools 
        L-- yarn 

Сам Hadoop (исполняемый java-байткод) находится в директории share и разбит на компоненты (hdfs, yarn, mapreduce, etc...). В директории lib находятся библиотеки, написанные на C.

Назначение остальных директорий интуитивно понятно: bin – утилиты командной строки для работы с Hadoop, sbin – скрипты запуска, etc – конфиги, logs – логи. Нас в первую очередь будут интересовать две утилиты из директории bin: hdfs и yarn.

Если вы помните, мы уже отформатировали HDFS и запустили все необходимые процессы. Посмотрим, что у нас в HDFS:


hdfs dfs -ls -R / 
drwxrwx---   - root supergroup          0 2017-01-05 10:07 /tmp 
drwxrwx---   - root supergroup          0 2017-01-05 10:07 /tmp/hadoop-yarn 
drwxrwx---   - root supergroup          0 2017-01-05 10:07 /tmp/hadoop-yarn/staging 
drwxrwx---   - root supergroup          0 2017-01-05 10:07 /tmp/hadoop-yarn/staging/history 
drwxrwx---   - root supergroup          0 2017-01-05 10:07 /tmp/hadoop-yarn/staging/history/done 
drwxrwxrwt   - root supergroup          0 2017-01-05 10:07 /tmp/hadoop-yarn/staging/history/done_intermediate 

Хотя мы явно не создавали эту структуру директорий, ее создал сервис JobHistory (последний запущеный демон: mr-jobhistory-daemon.sh start historyserver).

Посмотрим, что в директории /data:

/data/ 
+-- dfs 
¦   +-- dn 
¦   ¦   +-- current 
¦   ¦   ¦   +-- BP-1600342399-192.168.122.70-1483626613224 
¦   ¦   ¦   ¦   +-- current 
¦   ¦   ¦   ¦   ¦   +-- finalized 
¦   ¦   ¦   ¦   ¦   +-- rbw 
¦   ¦   ¦   ¦   ¦   L-- VERSION 
¦   ¦   ¦   ¦   +-- scanner.cursor 
¦   ¦   ¦   ¦   L-- tmp 
¦   ¦   ¦   L-- VERSION 
¦   ¦   L-- in_use.lock 
¦   L-- nn 
¦       +-- current 
¦       ¦   +-- edits_inprogress_0000000000000000001 
¦       ¦   +-- fsimage_0000000000000000000 
¦       ¦   +-- fsimage_0000000000000000000.md5 
¦       ¦   +-- seen_txid 
¦       ¦   L-- VERSION 
¦       L-- in_use.lock 
L-- yarn 
    +-- filecache 
    +-- log 
    +-- nmPrivate 
    L-- usercache 

Как видите, в /data/dfs/nn NameNode создал файл fsimage и первый edit-файл. В /data/dfs/dn DataNode создал директорию для хранения блоков данных, но самих данных еще нет.

Скопируем какой-нибудь файл с локальной ФС в HDFS:

hdfs dfs -put /var/log/messages /tmp/

hdfs dfs -ls /tmp/messages 
-rw-r--r--   1 root supergroup     375974 2017-01-05 09:33 /tmp/messages

Снова посмотрим на содержимое /data

/data/dfs/dn 
+-- current 
¦   +-- BP-1600342399-192.168.122.70-1483626613224 
¦   ¦   +-- current 
¦   ¦   ¦   +-- finalized 
¦   ¦   ¦   ¦   L-- subdir0 
¦   ¦   ¦   ¦       L-- subdir0 
¦   ¦   ¦   ¦           +-- blk_1073741825 
¦   ¦   ¦   ¦           L-- blk_1073741825_1001.meta 
¦   ¦   ¦   +-- rbw 
¦   ¦   ¦   L-- VERSION 
¦   ¦   +-- scanner.cursor 
¦   ¦   L-- tmp 
¦   L-- VERSION 
L-- in_use.lock 

Ура!!! Появился первый блок и его контрольная сумма.

Запустим какое-нибудь приложение, чтобы убедится, что YARN работает как надо. Например, pi из пакета hadoop-mapreduce-examples.jar:

yarn jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.3.jar pi 3 100000
…
Job Finished in 37.837 seconds 
Estimated value of Pi is 3.14168000000000000000 

Если посмотреть на содержимое /data/yarn во время исполнения приложения, можно узнать много интересного о том, как исполняются приложения YARN:

/data/yarn/ 
+-- filecache 
+-- log 
¦   L-- application_1483628783579_0001 
¦       +-- container_1483628783579_0001_01_000001 
¦       ¦   +-- stderr 
¦       ¦   +-- stdout 
¦       ¦   L-- syslog 
¦       +-- container_1483628783579_0001_01_000002 
¦       ¦   +-- stderr 
¦       ¦   +-- stdout 
¦       ¦   L-- syslog 
¦       +-- container_1483628783579_0001_01_000003 
¦       ¦   +-- stderr 
¦       ¦   +-- stdout 
¦       ¦   L-- syslog 
¦       L-- container_1483628783579_0001_01_000004 
¦           +-- stderr 
¦           +-- stdout 
¦           L-- syslog 
+-- nmPrivate 
¦   L-- application_1483628783579_0001 
¦       +-- container_1483628783579_0001_01_000001 
¦       ¦   +-- container_1483628783579_0001_01_000001.pid 
¦       ¦   +-- container_1483628783579_0001_01_000001.tokens 
¦       ¦   L-- launch_container.sh 
¦       +-- container_1483628783579_0001_01_000002 
¦       ¦   +-- container_1483628783579_0001_01_000002.pid 
¦       ¦   +-- container_1483628783579_0001_01_000002.tokens 
¦       ¦   L-- launch_container.sh 
¦       +-- container_1483628783579_0001_01_000003 
¦       ¦   +-- container_1483628783579_0001_01_000003.pid 
¦       ¦   +-- container_1483628783579_0001_01_000003.tokens 
¦       ¦   L-- launch_container.sh 
¦       L-- container_1483628783579_0001_01_000004 
¦           +-- container_1483628783579_0001_01_000004.pid 
¦           +-- container_1483628783579_0001_01_000004.tokens 
¦           L-- launch_container.sh 
L-- usercache 
    L-- root 
        +-- appcache 
        ¦   L-- application_1483628783579_0001 
        ¦       +-- container_1483628783579_0001_01_000001 
        ¦       ¦   +-- container_tokens 
        ¦       ¦   +-- default_container_executor_session.sh 
        ¦       ¦   +-- default_container_executor.sh 
        ¦       ¦   +-- job.jar -> /data/yarn/usercache/root/appcache/application_1483628783579_0001/filecache/11/job.jar 
        ¦       ¦   +-- jobSubmitDir 
        ¦       ¦   ¦   +-- job.split -> /data/yarn/usercache/root/appcache/application_1483628783579_0001/filecache/12/job.split 
        ¦       ¦   ¦   L-- job.splitmetainfo -> /data/yarn/usercache/root/appcache/application_1483628783579_0001/filecache/10/job.splitmetainfo 
        ¦       ¦   +-- job.xml -> /data/yarn/usercache/root/appcache/application_1483628783579_0001/filecache/13/job.xml 
        ¦       ¦   +-- launch_container.sh 
        ¦       ¦   L-- tmp 
        ¦       ¦       L-- Jetty_0_0_0_0_37883_mapreduce____.rposvq 
        ¦       ¦           L-- webapp 
        ¦       ¦               L-- webapps 
        ¦       ¦                   L-- mapreduce 
        ¦       +-- container_1483628783579_0001_01_000002 
        ¦       ¦   +-- container_tokens 
        ¦       ¦   +-- default_container_executor_session.sh 
        ¦       ¦   +-- default_container_executor.sh 
        ¦       ¦   +-- job.jar -> /data/yarn/usercache/root/appcache/application_1483628783579_0001/filecache/11/job.jar 
        ¦       ¦   +-- job.xml 
        ¦       ¦   +-- launch_container.sh 
        ¦       ¦   L-- tmp 
        ¦       +-- container_1483628783579_0001_01_000003 
        ¦       ¦   +-- container_tokens 
        ¦       ¦   +-- default_container_executor_session.sh 
        ¦       ¦   +-- default_container_executor.sh 
        ¦       ¦   +-- job.jar -> /data/yarn/usercache/root/appcache/application_1483628783579_0001/filecache/11/job.jar 
        ¦       ¦   +-- job.xml 
        ¦       ¦   +-- launch_container.sh 
        ¦       ¦   L-- tmp 
        ¦       +-- container_1483628783579_0001_01_000004 
        ¦       ¦   +-- container_tokens 
        ¦       ¦   +-- default_container_executor_session.sh 
        ¦       ¦   +-- default_container_executor.sh 
        ¦       ¦   +-- job.jar -> /data/yarn/usercache/root/appcache/application_1483628783579_0001/filecache/11/job.jar 
        ¦       ¦   +-- job.xml 
        ¦       ¦   +-- launch_container.sh 
        ¦       ¦   L-- tmp 
        ¦       +-- filecache 
        ¦       ¦   +-- 10 
        ¦       ¦   ¦   L-- job.splitmetainfo 
        ¦       ¦   +-- 11 
        ¦       ¦   ¦   L-- job.jar 
        ¦       ¦   ¦       L-- job.jar 
        ¦       ¦   +-- 12 
        ¦       ¦   ¦   L-- job.split 
        ¦       ¦   L-- 13 
        ¦       ¦       L-- job.xml 
        ¦       L-- work 
        L-- filecache 

42 directories, 50 files

В частности видим, что логи пишутся в /data/yarn/log (параметр yarn.nodemanager.log-dirs из yarn-site.xml).

По окончании работы приложения /data/yarn приходит в свой первозданный вид:

/data/yarn/ 
+-- filecache 
+-- log 
+-- nmPrivate 
L-- usercache 
    L-- root 
        +-- appcache 
        L-- filecache

Если мы снова взглянем на содержимое HDFS, увидим, что log aggregation работает (логи только что выполненного приложения были перемещены из локальной ФС /data/yarn/log в HDFS /tmp/logs).

Также увидим, что сервис JobHistory сохранил информацию о нашем приложении в /tmp/hadoop-yarn/staging/history/done.

hdfs dfs -ls -R / 
drwxrwx---   - root supergroup          0 2017-01-05 10:12 /tmp 
drwxrwx---   - root supergroup          0 2017-01-05 10:07 /tmp/hadoop-yarn 
drwxrwx---   - root supergroup          0 2017-01-05 10:12 /tmp/hadoop-yarn/staging 
drwxrwx---   - root supergroup          0 2017-01-05 10:07 /tmp/hadoop-yarn/staging/history 
drwxrwx---   - root supergroup          0 2017-01-05 10:13 /tmp/hadoop-yarn/staging/history/done 
drwxrwx---   - root supergroup          0 2017-01-05 10:13 /tmp/hadoop-yarn/staging/history/done/2017 
drwxrwx---   - root supergroup          0 2017-01-05 10:13 /tmp/hadoop-yarn/staging/history/done/2017/01 
drwxrwx---   - root supergroup          0 2017-01-05 10:13 /tmp/hadoop-yarn/staging/history/done/2017/01/05 
drwxrwx---   - root supergroup          0 2017-01-05 10:13 /tmp/hadoop-yarn/staging/history/done/2017/01/05/000000 
-rwxrwx---   1 root supergroup      46338 2017-01-05 10:13 /tmp/hadoop-yarn/staging/history/done/2017/01/05/000000/job_1483628783579_0001-1483629144632-root-QuasiMonteCarlo-1483629179995-3-1-SUCCEEDED-default-1483629156270.jhist 
-rwxrwx---   1 root supergroup     117543 2017-01-05 10:13 /tmp/hadoop-yarn/staging/history/done/2017/01/05/000000/job_1483628783579_0001_conf.xml 
drwxrwxrwt   - root supergroup          0 2017-01-05 10:12 /tmp/hadoop-yarn/staging/history/done_intermediate 
drwxrwx---   - root supergroup          0 2017-01-05 10:13 /tmp/hadoop-yarn/staging/history/done_intermediate/root 
drwx------   - root supergroup          0 2017-01-05 10:12 /tmp/hadoop-yarn/staging/root 
drwx------   - root supergroup          0 2017-01-05 10:13 /tmp/hadoop-yarn/staging/root/.staging 
drwxrwxrwt   - root supergroup          0 2017-01-05 10:12 /tmp/logs 
drwxrwx---   - root supergroup          0 2017-01-05 10:12 /tmp/logs/root 
drwxrwx---   - root supergroup          0 2017-01-05 10:12 /tmp/logs/root/logs 
drwxrwx---   - root supergroup          0 2017-01-05 10:13 /tmp/logs/root/logs/application_1483628783579_0001 
-rw-r-----   1 root supergroup      65829 2017-01-05 10:13 /tmp/logs/root/logs/application_1483628783579_0001/master.local_37940 
drwxr-xr-x   - root supergroup          0 2017-01-05 10:12 /user 
drwxr-xr-x   - root supergroup          0 2017-01-05 10:13 /user/root

Тестирование в распределенном кластере


Возможно вы обратили внимание, что до сих пор я брал “кластер” в кавычки. Ведь у нас все работает на одной и той же машине. Исправим это досадное недоразумение. Протестируем наш Hadoop в настоящем распределенном кластере.

Прежде всего, подправим конфигурацию Hadoop. На данный момент имя хоста в конфигурации Hadoop указано как localhost. Если сейчас просто скопировать эту конфигурацию на другие ноды, каждая нода будет пытаться найти NameNode, ResourceManager и JobHistory сервисы на своем хосте. Поэтому определимся заранее с именем хоста с этими сервисами и внесем правки в конфиги.

В моем случае, все выше master-сервисы (NameNode, ResourceManager, JobHistory) будут выполняться на хосте master.local. Заменим localhost на master.local в конфигурации:

cd /opt/hadoop/etc/hadoop
sed -i 's/localhost/master.local/' core-site.xml hdfs-site.xml yarn-site.xml mapred-site.xml

Теперь я просто клонирую виртуальную машину, на которой я проводил сборку два раза, чтоб получить две slave-ноды. На slave-нодах нужно установить уникальное имя хоста (в моем случае это slave1.local и slave2.local). Также на всех трех нодах нашего кластера сконфигурируем /etc/hosts, чтоб каждая машина кластера могла обращаться к другим по имени хоста. В моем случае это выглядит так (одно и то же содержимое на всех трех машинах):

cat /etc/hosts
…
192.168.122.70   master.local 
192.168.122.59   slave1.local 
192.168.122.217 slave2.local 

Дополнительно на нодах slave1.local и slave2.local нужно очистить содержимое /data/dfs/dn

rm -rf /data/dfs/dn/*

Все готово. На master.local запускаем все сервисы:

/opt/hadoop/sbin/hadoop-daemon.sh start namenode 
/opt/hadoop/sbin/hadoop-daemon.sh start datanode 
/opt/hadoop/sbin/yarn-daemon.sh start resourcemanager 
/opt/hadoop/sbin/yarn-daemon.sh start nodemanager 
/opt/hadoop/sbin/mr-jobhistory-daemon.sh start historyserver 

На slave1.local и slave2.local запускаем только DataNode и NodeManager:

/opt/hadoop/sbin/hadoop-daemon.sh start datanode 
/opt/hadoop/sbin/yarn-daemon.sh start nodemanager 

Проверим, что наш кластер теперь состоит из трех нод.

Для HDFS посмотрим на вывод команды dfsadmin -report и убедимся, что все три машины включены в список Live datanodes:

hdfs dfsadmin -report
...
Live datanodes (3): 
…
Name: 192.168.122.70:50010 (master.local) 
...
Name: 192.168.122.59:50010 (slave1.local) 
...
Name: 192.168.122.217:50010 (slave2.local) 

Или зайдем на веб страничку NameNode:

master.local:50070/dfshealth.html#tab-datanode


Для YARN посмотрим на вывод команды node -list:

yarn node -list -all 
17/01/06 06:17:52 INFO client.RMProxy: Connecting to ResourceManager at master.local/192.168.122.70:8032 
Total Nodes:3 
         Node-Id             Node-State Node-Http-Address       Number-of-Running-Containers 
slave2.local:39694              RUNNING slave2.local:8042                                  0 
slave1.local:36880              RUNNING slave1.local:8042                                  0 
master.local:44373              RUNNING master.local:8042                                  0 

Или зайдем на веб страничку ResourceManager

master.local:8088/cluster/nodes


Все ноды должны быть в списке со статусом RUNNING.

Напоследок убедимся, что запускаемые приложения MapReduce используют ресурсы на всех трех нодах. Запустим уже знакомое нам приложение Pi из hadoop-mapreduce-examples.jar:

yarn jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.3.jar pi 30 1000

Во время выполнения приложения еще раз посмотрим вывод yarn node -list -all:

...
         Node-Id             Node-State Node-Http-Address       Number-of-Running-Containers 
slave2.local:39694              RUNNING slave2.local:8042                                  4 
slave1.local:36880              RUNNING slave1.local:8042                                  4 
master.local:44373              RUNNING master.local:8042                                  4 

Number-of-Running-Containers — 4 на каждой ноде.

Также мы можем зайти на master.local:8088/cluster/nodes и посмотреть, сколько ядер и памяти используется всеми приложениями в общей сложности на каждой ноде.



Заключение


Мы собрали Hadoop из исходного кода, установили, сконфигурировали и протестировали работоспособность на отдельной машине и в распределенном кластере. Если тема вам интересна, если есть желание подобным образом собрать другие сервисы из экосистемы Hadoop, оставлю ссылку на скрипт, который поддерживаю для собственных нужд:

github.com/hadoopfromscratch/hadoopfromscratch

С его помошью вы сможете установить zookeeper, spark, hive, hbase, cassandra, flume. Если найдете ошибки или неточности, пожалуйста напишите. Буду очень признателен.
Поделиться с друзьями
-->

Комментарии (1)


  1. Crandel
    08.01.2017 11:16

    Во всех нормальных инструкциях сборка пакетов происходит в /tmp чтобы не чистить все вручную