Hadoop From Scratch

  • Tutorial
Эта статья послужит практическим руководством по сборке, начальной настройке и тестированию работоспособности 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 
│   └── hadoop 
├── include 
├── lib 
│   └── native 
├── libexec 
├── logs 
├── sbin 
└── share 
    ├── doc 
    │   └── hadoop 
    └── hadoop 
        ├── common 
        ├── hdfs 
        ├── httpfs 
        ├── kms 
        ├── mapreduce 
        ├── tools 
        └── 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 
│   │   │   │   │   └── VERSION 
│   │   │   │   ├── scanner.cursor 
│   │   │   │   └── tmp 
│   │   │   └── VERSION 
│   │   └── in_use.lock 
│   └── nn 
│       ├── current 
│       │   ├── edits_inprogress_0000000000000000001 
│       │   ├── fsimage_0000000000000000000 
│       │   ├── fsimage_0000000000000000000.md5 
│       │   ├── seen_txid 
│       │   └── VERSION 
│       └── in_use.lock 
└── yarn 
    ├── filecache 
    ├── log 
    ├── nmPrivate 
    └── 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 
│   │   │   │   └── subdir0 
│   │   │   │       └── subdir0 
│   │   │   │           ├── blk_1073741825 
│   │   │   │           └── blk_1073741825_1001.meta 
│   │   │   ├── rbw 
│   │   │   └── VERSION 
│   │   ├── scanner.cursor 
│   │   └── tmp 
│   └── VERSION 
└── 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 
│   └── application_1483628783579_0001 
│       ├── container_1483628783579_0001_01_000001 
│       │   ├── stderr 
│       │   ├── stdout 
│       │   └── syslog 
│       ├── container_1483628783579_0001_01_000002 
│       │   ├── stderr 
│       │   ├── stdout 
│       │   └── syslog 
│       ├── container_1483628783579_0001_01_000003 
│       │   ├── stderr 
│       │   ├── stdout 
│       │   └── syslog 
│       └── container_1483628783579_0001_01_000004 
│           ├── stderr 
│           ├── stdout 
│           └── syslog 
├── nmPrivate 
│   └── application_1483628783579_0001 
│       ├── container_1483628783579_0001_01_000001 
│       │   ├── container_1483628783579_0001_01_000001.pid 
│       │   ├── container_1483628783579_0001_01_000001.tokens 
│       │   └── launch_container.sh 
│       ├── container_1483628783579_0001_01_000002 
│       │   ├── container_1483628783579_0001_01_000002.pid 
│       │   ├── container_1483628783579_0001_01_000002.tokens 
│       │   └── launch_container.sh 
│       ├── container_1483628783579_0001_01_000003 
│       │   ├── container_1483628783579_0001_01_000003.pid 
│       │   ├── container_1483628783579_0001_01_000003.tokens 
│       │   └── launch_container.sh 
│       └── container_1483628783579_0001_01_000004 
│           ├── container_1483628783579_0001_01_000004.pid 
│           ├── container_1483628783579_0001_01_000004.tokens 
│           └── launch_container.sh 
└── usercache 
    └── root 
        ├── appcache 
        │   └── 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 
        │       │   │   └── 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 
        │       │   └── tmp 
        │       │       └── Jetty_0_0_0_0_37883_mapreduce____.rposvq 
        │       │           └── webapp 
        │       │               └── webapps 
        │       │                   └── 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 
        │       │   └── 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 
        │       │   └── 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 
        │       │   └── tmp 
        │       ├── filecache 
        │       │   ├── 10 
        │       │   │   └── job.splitmetainfo 
        │       │   ├── 11 
        │       │   │   └── job.jar 
        │       │   │       └── job.jar 
        │       │   ├── 12 
        │       │   │   └── job.split 
        │       │   └── 13 
        │       │       └── job.xml 
        │       └── work 
        └── filecache 

42 directories, 50 files

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

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

/data/yarn/ 
├── filecache 
├── log 
├── nmPrivate 
└── usercache 
    └── root 
        ├── appcache 
        └── 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. Если найдете ошибки или неточности, пожалуйста напишите. Буду очень признателен.

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 1

    0

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

    Only users with full accounts can post comments. Log in, please.