基于树莓派的集群spark on yarn

Posted by Hsz on November 26, 2016

基于树莓派的集群实验(一)–spark on yarn

终于有时间尝试集群安装了,可惜没有多余的电脑,手头有树莓派就拿来凑活用了。 本文将具体讲解如何再树莓派上安装hadoop和spark,并与自己本地的mac尝试构建分布式系统集群。 由于树莓派本身性能有限,这篇文章更多的是尝试而非可以用于大规模运算。

sudo apt-get install -y maven build-essential autoconf automake libtool cmake zlib1g-dev pkg-config libssl-dev libfuse-dev libsnappy-dev libsnappy-java libbz2-dev oracle-java8-jdk subversion

单机安装

树莓派集群网络设置

树莓派单机配置coder系统查看我的这篇博文.

单机配置好后集群还需要做一些设定

主机名 ip 账户名 用途
coderMaster 192.168.1.40 pi 作为主机并允许外网ssh访问
coderSlaver01 192.168.1.41 pi 作为从机
coderSlaver02 192.168.1.42 pi 作为从机
coderSlaver03 192.168.1.43 pi 作为从机
coderSta 192.168.1.30 pi 作为反向代理服务器和通信入口,

因此,修改各机的/etc/hosts

修改权限:

sudo chmod ugo+w /etc/hosts

之后在vim中修改:

再在其中添加

192.168.1.40 coderMaster
192.168.1.41 coderSlaver01
192.168.1.42 coderSlaver02
192.168.1.43 coderSlaver03
192.168.1.33 coderSta01

当然也可以用echo

echo "192.168.1.40 coderMaster" >> /etc/hosts
echo "192.168.1.41 coderSlaver01" >> /etc/hosts
echo "192.168.1.42 coderSlaver02" >> /etc/hosts
echo "192.168.1.50 coderSta01" >> /etc/hosts

不过一旦重启修改就会失效,怎么修改呢?

sd卡拔下来修改其中的hosts.txt文件即可

ps: 需要将主机的127.0.1.1 coder一行删除

ssh配置

四台机器通信需要使用ssh无密码通讯

生成本机ssh密匙

首先为各自机器生成一对公钥,私钥

ssh-keygen -t dsa -P "" //用dsa因为它比rsa速度快
cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys
ssh localhost

第一次ssh localhost会要你设置下,以后就可以无密码登陆了。每台机器都这么设置下,要求都能 ssh localhost无密码登陆。

master与slave建立联系

将三台机器上.ssh/文件夹下下载主机的公钥

ssh-copy-id -i ~/.ssh/id_dsa.pub pi@coderSlaver01
ssh-copy-id -i ~/.ssh/id_dsa.pub pi@coderSlaver02
ssh-copy-id -i ~/.ssh/id_dsa.pub pi@coderSlaver03
ssh-copy-id -i ~/.ssh/id_dsa.pub pi@coderSta

这样主机就可以无密码连到从机了.

同样的,将各个从机的公钥传给主机

ssh-copy-id -i ~/.ssh/id_dsa.pub pi@coderMaster

这就算配置好了

编译环境配置

  • 首先是更新apt-get版本和已安装软件的版本(每台都要)

    sudo apt-get update sudo apt-get upgrade -y

  • 之后是安装编译所需库文件(每台最好装下)

    sudo apt-get install -y maven build-essential autoconf automake libtool cmake zlib1g-dev pkg-config libssl-dev libfuse-dev libsnappy-dev libsnappy-java libbz2-dev oracle-java8-jdk subversion

期间因为有些库依赖java1.6所以安装了1.6版本的jvm,需要用

sudo update-alternatives --config java

将其选回java1.8

  • 安装protocol buffers v2.5 (必须2.5)

    wget https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz sudo tar xzvf protobuf-2.5.0.tar.gz sudo chown -R pi protobuf-2.5.0/ cd protobuf-2.5.0 ./configure –prefix=/usr make make check sudo make install

需要注意的是编译安装很慢….要有耐心,不要以为是死机了

  • 安装scala语言(每台都要)

    cd ~ wget http://www.scala-lang.org/files/archive/scala-2.10.4.tgz sudo mkdir lib/scala sudo tar vxzf scala-2.10.4.tgz -C lib/scala

vim 修改/etc/profile

#----------------------------------------------------------------------scala

export SCALA_HOME=/home/pi/lib/scala/scala-2.10.4
export PATH=PATH:SCALA_HOME/bin


#---------------------------------------------------------------------------

hadoop

安装hadoop

因为是编译安装所以很慢很慢,要有耐心

cd ~
wget http://apache.mirrors.spacedump.net/hadoop/core/hadoop-2.6.0/hadoop-2.6.0-src.tar.gz
tar xzvf hadoop-2.6.0-src.tar.gz
sudo chown -R pi hadoop-2.6.0-src/
cd hadoop-2.6.0-src/

打开其中的 pom.xml 文件.将

<additionalparam>-Xdoclint:none</additionalparam>

添加进<properties></properties>标签中然后保存退出编辑

因为是arm处理器,所以要打个补丁

cd hadoop-common-project/hadoop-common/src
wget https://issues.apache.org/jira/secure/attachment/12570212/HADOOP-9320.patch
patch < HADOOP-9320.patch

这样安装的准备工作就完成了,开始使用maven编译安装

sudo mvn package -Pdist,native -DskipTests -Dtar

这个要花近两个小时才能编译完…

编译后的hadoop在hadoop-2.6.0-src/hadoop-dist/target/hadoop2.6.0这个位置

同时会有一个你的本地编译程序.tar包在hadoop-2.6.0-src/hadoop-dist/target/hadoop2.6.0.tar.gz

配置hadoop

首先是环境变量配置,在/etc/profile中添加如下内容(先修改为可读sudo chmod ugo+w /etc/profile )

#-------------------------------------------------------------------java

export JAVA_HOME=/usr/lib/jvm/jdk-8-oracle-arm-vfp-hflt
export CLASS_PATH=$JAVA_HOME/lib:$JAVA_HOME/jre/lib  

#-------------------------------------------------------------------hadoop
export HADOOP_HOME=/home/pi/lib/hadoop/hadoop-2.6.0
export HADOOP_PID_DIR=/data/hadoop/pids
export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native
export HADOOP_OPTS="$HADOOP_OPTS -Djava.library.path=$HADOOP_HOME/lib/native"

export HADOOP_MAPRED_HOME=$HADOOP_HOME
export HADOOP_COMMON_HOME=$HADOOP_HOME
export HADOOP_HDFS_HOME=$HADOOP_HOME
export YARN_HOME=$HADOOP_HOME

export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop
export HDFS_CONF_DIR=$HADOOP_HOME/etc/hadoop
export YARN_CONF_DIR=$HADOOP_HOME/etc/hadoop

export JAVA_LIBRARY_PATH=$HADOOP_HOME/lib/native

export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin

创建用于存储的文件夹

sudo mkdir -p /data/hadoop/{pids,storage}
sudo mkdir -p /data/hadoop/storage/{hdfs,tmp}
sudo mkdir -p /data/hadoop/storage/hdfs/{name,data}
sudo chown -R pi /data
sudo chmod -R ugo+w /data

配置 core-site.xml

<configuration>
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://coderMaster:9000</value>
    </property>
    <property>
        <name>io.file.buffer.size</name>
        <value>131072</value>
    </property>
    <property>
        <name>hadoop.tmp.dir</name>
        <value>file:/data/hadoop/storage/tmp</value>
    </property>
    <property>
        <name>hadoop.proxyuser.hadoop.hosts</name>
        <value>*</value>
    </property>
    <property>
        <name>hadoop.proxyuser.hadoop.groups</name>
        <value>*</value>
    </property>
    <property>
        <name>hadoop.native.lib</name>
        <value>true</value>
    </property>
</configuration>

配置 hdfs-site.xml

<configuration>
    <property>
        <name>dfs.namenode.name.dir</name>
        <value>file:/data/hadoop/storage/hdfs/name</value>
    </property>
    <property>
        <name>dfs.datanode.data.dir</name>
        <value>file:/data/hadoop/storage/hdfs/data</value>
    </property>
    <property>
        <name>dfs.replication</name>
        <value>3</value>
    </property>
    <property>
        <name>dfs.webhdfs.enabled</name>
        <value>true</value>
    </property>
</configuration>

配置 mapred-site.xml

<configuration>
    <property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
    </property>
    <property>
        <name>mapreduce.jobhistory.address</name>
        <value>coderMaster:10020</value>
    </property>

    <property>
        <name>mapreduce.jobhistory.webapp.address</name>
        <value>coderMaster:19888</value>
    </property>
</configuration>

配置 yarn-site.xml

<configuration>
    <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>
    <property>
        <name>yarn.resourcemanager.scheduler.address</name>
        <value>coderMaster:8030</value>
    </property>
    <property>
        <name>yarn.resourcemanager.resource-tracker.address</name>
        <value>coderMaster:8031</value>
    </property>
    <property>
        <name>yarn.resourcemanager.address</name>
        <value>coderMaster:8032</value>
    </property>
    <property>
        <name>yarn.resourcemanager.admin.address</name>
        <value>coderMaster:8033</value>
    </property>
    <property>
        <name>yarn.resourcemanager.webapp.address</name>
        <value>coderMaster:8088</value>
    </property>
</configuration>

配置 hadoop-env.sh

修改JAVA_HOME

JAVA_HOME=/usr/lib/jvm/jdk-8-oracle-arm-vfp-hflt

配置slaves

coderSlaver01

coderSlaver02

coderSlaver03

将 hadoop复制给子节点

sudo scp -r ~/lib/hadoop/hadoop-2.6.0/ pi@coderSlaver01:~/lib/hadoop
sudo scp -r ~/lib/hadoop/hadoop-2.6.0/ pi@coderSlaver02:~/lib/hadoop
sudo scp -r ~/lib/hadoop/hadoop-2.6.0/ pi@coderSlaver03:~/lib/hadoop

尝试运行

hdfs namenode -format #初始化节点
start-dfs.sh          #开启文件系统
start-yarn.sh         #开启yarn
jps                   #查看开启的java进程

如果看到主节点有

ResourceManager
NameNode
SecondaryNameNode

从节点有

NodeManager
DataNode

就说明成功了

Spark

安装spark

cd ~
wget http://apache.crihan.fr/dist/spark/spark-1.3.1/spark-1.3.1-bin-hadoop2.6.tgz
sudo mkdir ~/lib/spark/
sudo tar vxzf spark-1.3.1-bin-hadoop2.6.tgz -C ~/workspace/lib/spark/
echo "#-----------------------------------spark" >> /etc/profile
echo "export SPARK_HOME=/home/pi/lib/spark/spark-1.3.1-bin-hadoop2.6" >> /etc/profile
echo "#----------------------------------------" >> /etc/profile

之后修改$SPARK_HOME/conf/slaves中的值为(没有就新建)

coderMaster
coderSlaver01
coderSlaver02
coderSlaver03

$SPARK_HOME/conf/spark-env.sh中的值为(没有就新建)

export JAVA_HOME=/usr/lib/jvm/jdk-8-oracle-arm-vfp-hflt
export SCALA_HOME=/home/pi/lib/scala/scala-2.10.4
export HADOOP_HOME=/home/pi/lib/hadoop/hadoop-2.6.0
export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop


export SPARK_WORKER_WEBUI_PORT=2023
export SPARK_MASTER_WEBUI_PORT=2022
export SPARK_MASTER_IP=192.168.1.40

export LD_LIBRARY_PATH=/home/pi/lib/hadoop/hadoop-2.6.0/lib/native

将spark复制去各个节点,并如上设置环境变量

sudo scp -r /home/pi/lib/spark/spark-1.3.1-bin-hadoop2.6 pi@coderSlaver01:~/lib/spark
sudo scp -r /home/pi/lib/spark/spark-1.3.1-bin-hadoop2.6 pi@coderSlaver02:~/lib/spark
sudo scp -r /home/pi/lib/spark/spark-1.3.1-bin-hadoop2.6 pi@coderSlaver03:~/lib/spark

测试

运行

$SPARK_HOME/sbin/start-all.sh

依然用jps查看进程,如果主节点多了Master,从节点多了Worker

打开网页http:你的Masterip:2022如果显示有4个worker则说明集群运行正常,如果发现有问题,可以去运行脚本时显示的对应log(.out) 文件中查看哪里出错.

spark on yarn 运行

事实上有两种运行方式,一种是集群模式,集群模式是用来运行application的,还有一种是客户端模式,是在spark-shell中采用集群的方式 就用第二种写个简单的word count演示吧

  • 第一步 将要分析的文本送入hdfs

    hdfs dfs -mkdir /user/pi/sources hdfs dfs -put README.md /user/pi/sources

  • 第二步 进入spark-shell
    $SPARK_HOME/bin/spark-shell  --num-executors 3 --master yarn --executor-memory 200m
    
  • 第三步 运行一个word count

    scala> var text_file = spark.textFile(“hdfs://localhost:9000/user/pi/source/README.md”) scala> var counts = text_file.flatMap(lambda line: line.split(“ “)).map(lambda word: (word, 1)).reduceByKey(lambda a, b: a + b) scala> counts.saveAsTextFile(“hdfs://coderMaster:9000/user/pi/result/wc”)

  • 第四步 另起一个shell 查看结果

    hdfs dfs -copyToLocal hdfs://coderMaster:9000/user/pi/result/wc ~/ cd ~/wc cat part-00000 part-00001 >result cat result

##后日谈:

其实这东西娱乐都不能算,小pi内存太小了,加上节点少,性能差的叫人无语…只能说这是个集群实验了.没钱真可怜.