Problemas con la memoria del Cluster Hadoop

Habiendo entendido que los nodos del cluster quedaron configurados con la mitad de memoria que se suponía iban a tener, comenzamos a experimentar problemas de memoria (no relacionados con el mal de Alzheimer que nos acosa a los señores mayores).

Dado este problema comenzamos a hacer lo que todo “hombre de la casa” debe hacer: No leer el manual y empezar a tocar parámetros al azar hasta que funcione. Bueno, al poco tiempo se evidenció que no es la mejor técnica. Lástima… Estaba preparando un artículo sobre eso…

Por suerte encontré la información debidamente tabulada por la gente de Hortonworks aquí. Fue de gran utilidad.

Anuncios

Configurando un Cluster

He configurado un cluster casero con 4 nodos, las versiones del software son estables, quizás no sean las últimas. Lo único que lamento, es no haber podido configurar Hadoop serie 2 con YARN… La próxima será. Las versiones del software que configuré son:

Luego de bajar los paquetes, los pasos para la instalación y configuración son los siguientes:

    • Primero vamos a crear un usuario en todos los nodos para que corra hadoop:
      sudo useradd -d /home/hadoopuser -m hadoopuser
      sudo passwd hadoopuser
    • Y vamos a agregarlo a un grupo con tal de darle permisos de lectura, escritura y ejecución en los recursos de Hadoop.
    • Vamos a sanear los nombres de host en todos los servidores y la unificación de /etc/hosts si no contamos con un DNS. Esto parece trivial, pero es con lo que más dolores de cabeza nos da Hadoop.
    • Crear un directorio para la instalación de Hadoop, al que setearemos en la variable de entorno HADOOP_HOME
    • Descomprimir allí dentro el tar de hadoop (tar xfz hadoop-xxxx)
    • Verificar que esté definida la variable JAVA_HOME
    • Verificar la configuración de NTP en el cluster.
    • Agregar al Path del directorio bin de Hadoop.
    • Crear un directorio para los logs de hadoop.
    • Verificar loopback en cada máquina:
      sudo /etc/hosts

      Verificar que haya 2 entradas a 127.0.0.1 (localhost y el nombre de la máquina) ya que ubuntu suele usar el 127.0.1.1

    • Crear directorios data, log, data/mapred/local/ , data/mapred/system , data/namenode y data/datanode dentro de la estructura de Hadoop.
    • Hay que habilitar en el namenode la posibilidad de que se comunique vía ssh a todos los esclavos sin tener que utilizar una password. Para eso hay un buen tutorial aquí. Desde el namenode (hacer su al usuario que va a correr hadoop):
      ssh-keygen -t rsa
      ssh-copy-id hadoopuser@remotemachine (esto para cada nodo)
    • Hacer ssh a cada nodo para ver que pueda acceder sin necesidad de poner pwd.
    • Editar dentro del directorio conf (HADOOP_CONF_DIR), hdfs-site.xml y setear el directorio donde se almacenará los datos del namenode (namespace y transaction log), y agregar la lista (separada por comas) de directorios (todos previamente creados) donde se almacenan los datos. Usé 32Mb de blocksize para el file system distribuido… El default es 128Mb, me parece mucho para un fin académico. Por ejemplo:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<configuration>
     <property>
         <name>dfs.name.dir</name>
         <value>/opt/hadoop/hadoop-1.1.2/data/namenode</value>
     </property>
     <property>
         <name>dfs.blocksize</name>
         <value>33554432</value>
     </property>
     <property>
         <name>dfs.data.dir</name>
         <value>/opt/hadoop/hadoop-1.1.2/data/datanode</value>
     </property>
</configuration>
    • En mapred-site.xml se configura la ubicación del job.tracker (en nuestro caso es el mimo equipo que el namenode):
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<!-- Put site-specific property overrides in this file. -->

<configuration>
  <property> 
    <name>mapred.job.tracker</name> 
    <value>192.168.1.33:9001</value> 
  </property>
  <property> 
    <name>mapred.system.dir</name>
    <value>/opt/hadoop/hadoop-1.1.2/data/mapred/system/</value> 
  </property>
  <property>
    <name>mapred.local.dir</name>
    <value>/opt/hadoop/hadoop-1.1.2/data/mapred/local/</value> 
</property>
</configuration>
        • Configuración del archivo slaves. Este es como el machinefiles de MPI. Una lista de todos los workers.
        • Configuración del archivo masters. Contiene una lista de todos los hosts masters (en nuestro caso, hay uno sólo).
        • Configuramos el archivo taskcontroller.cfg:
mapred.local.dir=/opt/hadoop/hadoop-1.1.2/mapredlocaldir
hadoop.log.dir=/opt/hadoop/hadoop-1.1.2/log
mapred.tasktracker.tasks.sleeptime-before-sigkill=60
mapreduce.tasktracker.group=hadoopuser
      • El archivo core-site.xml configura los parámetros del file system distribuido:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!-- Put site-specific property overrides in this file. -->
<configuration>
  <property>
         <name>fs.default.name</name>
         <value>hdfs://192.168.1.33:9000</value>
  </property>
</configuration>
      • Sincronizar Hadoop con todos los clientes
      • Ahora configuramos ZooKeeper
      • Dentro de la estructura de Hadoop, armamos un directorio para su deployment y descomprimimos su tarball.
      • Creamos los siguientes directorios (dentro de la estructura):
sudo mkdir -p /usr/local/ZooKeeper/data 
sudo mkdir -p /usr/local/ZooKeeper/datalog 
sudo chown hadoopuser -R /usr/local/ZooKeeper
sudo mkdir /usr/local/ZooKeeper/var/datalog 
sudo chown hadoopuser /usr/local/ZooKeeper/var/datalog
      • Vamos a instalarlo en el master de forma standalone, pero en un cluster serio debería haber corriendo 3 copias.
      • Dentro del /conf de zookeeper, editar java.env y setear JAVA_HOME y ZK_HOME, por ejemplo:
JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64 
ZK_HOME=/opt/hadoop/zookeeper-3.4.5
      • Copiar zoo_sample.cfg a zoo.cfg y cambiar el contenido de modo que quede de la siguiente manera:
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial 
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between 
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just 
# example sakes.
dataDir=/usr/local/ZooKeeper/var/data
dataLogDir=/usr/local/ZooKeeper/var/datalog
# the port at which the clients will connect
clientPort=2181
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
server.0=192.168.1.33:2181
      • Sincronizar zookeeper con los clientes.
      • En el master, en /usr/local/ZooKeeper/data crear un file myid conteniendo un “1”.
      • Para ver si levanta, en el /bin del server hacemos ./zkServer.sh start para conectarnos desde los clientes, $ZK_HOME/bin/zkCli.sh -server master1:2181 y allí, ls / y finalmente para bajarlo, zkServer.sh stop en el server.
      • Ahora vamos a configurar HBase, para lo que descomprimimos el tarball dentro de la estructura de Hadoop, en un directorio especial para tal fin.
      • HBase debiera correr con un usuario distinto que hadoop, pero esta no es una instalación tan securitizada, por lo que se utilizará el mismo usuario que en hadoop.
      • Hay que formatear el HDFS:
hdfs namenode -format
      • En /conf de HBase vamos a configurar los regionservers (en nuestro caso son iguales que los datanodes) en un file llamado regionservers conteniendo una lista de los servidores para tal fin.
      • En hbase-env.sh configuramos las variables de entorno que hagan falta, como por ejemplo:
export HBASE_OPTS="-XX:+UseConcMarkSweepGC"
export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64
export HADOOP_CONF_DIR=/opt/hadoop/hadoop-1.1.2/conf
export HBASE_MANAGES_ZK=false
export HADOOP_HOME=/opt/hadoop/hadoop-1.1.2
export HBASE_HOME=/opt/hadoop/hbase-0.92.2
      • Las configuraciones más importantes ocurren en hbase-site.xml:
<configuration>
  <property> 
    <name>hbase.rootdir</name> 
    <value>hdfs://192.168.1.33:9000/hbase</value> 
  </property> 
  <property> 
    <name>hbase.cluster.distributed</name> 
    <value>true</value> 
  </property> 
     <property> 
         <name>hbase.tmp.dir</name> 
         <value>/tmp</value> 
     </property> 
     <property> 
         <name>hbase.zookeeper.quorum</name> 
         <value>192.168.1.33</value> 
     </property> 
</configuration>
        • Verificar si el límite de archivos abiertos es 1024:
           ulimit -n

          Verificar la cantidad de procesos (unlimitted):

           ulimit

          Cambiar el límite:

          sudo nano /etc/security/limits.conf
          hadoop user soft nofile 65535
          hadoop user hard nofile 65535
          hadoop user soft nproc 32000
          hadoop user hard nproc 32000

          Copiar las librerias correctas:

          rm /opt/hadoop/hbase-0.92.2/lib/hadoop-core-*.jar
          rm /opt/hadoop/hbase-0.92.2/lib/zookeeper-*.jar
          cp /opt/hadoop/hadoop-1.1.2/hadoop-core-*.jar /opt/hadoop/hbase-0.92.2/lib/
          cp /opt/hadoop/hadoop-1.1.2/lib/commons-configuration-1.6.jar /opt/hadoop/hbase-0.92.2/lib/
          cp /opt/hadoop/zookeeper-3.4.5/zookeeper-*.jar /opt/hadoop/hbase-0.92.2/lib/
        • Sincronizar con los regionservers.
        • Para levantar todo, armé un script único:
sudo su - hadoopuser -c "/opt/hadoop/hadoop-1.1.2/bin/start-all.sh"
sudo su - hadoopuser -c "/opt/hadoop/zookeeper-3.4.5/bin/zkServer.sh start"
sudo su - hadoopuser -c "/opt/hadoop/hbase-0.92.2/bin/start-hbase.sh"
    • Para bajar todo, armé también un script:
sudo su - hadoopuser -c "/opt/hadoop/hbase-0.92.2/bin/stop-hbase.sh"
sudo su - hadoopuser -c "/opt/hadoop/zookeeper-3.4.5/bin/zkServer.sh stop"
sudo su - hadoopuser -c "/opt/hadoop/hadoop-1.1.2/bin/stop-all.sh"