Hadoop From Scratch

от автора

Эта статья послужит практическим руководством по сборке, начальной настройке и тестированию работоспособности 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. Если найдете ошибки или неточности, пожалуйста напишите. Буду очень признателен.
ссылка на оригинал статьи https://habrahabr.ru/post/319048/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *