AWS EC2 搭建 Hadoop 和 Spark 集羣

前言

本篇演示如何使用 AWS EC2 雲服務搭建集羣。固然在只有一臺計算機的狀況下搭建徹底分佈式集羣,還有另外幾種方法:一種是本地搭建多臺虛擬機,好處是免費易操控,壞處是虛擬機對宿主機配置要求較高,我就一臺普通的筆記本,開兩三個虛擬機實在承受不起; 另外一種方案是使用 AWS EMR ,是亞馬遜專門設計的集羣平臺,能快速啓動集羣,且具備較高的靈活性和擴展性,能方便地增長機器。然而其缺點是隻能使用預設的軟件,以下圖:html

若是要另外裝軟件,則須要使用 Bootstrap 腳本,詳見 https://docs.aws.amazon.com/zh_cn/emr/latest/ManagementGuide/emr-plan-software.html?shortFooter=true ,可這並非一件容易的事情,記得以前想在上面裝騰訊的 Angel 就是死活都裝不上去。 另外,若是在 EMR 上關閉了集羣,則裏面的文件和配置都不會保存,下次使用時所有要從新設置,可見其比較適用於一次性使用的場景。java

綜上所述,若是使用純 EC2 進行手工搭建,則既不會受本地資源限制,也具備較高的靈活性,能夠隨意配置安裝軟件。而其缺點就是要手工搭建要耗費較多時間,並且在雲上操做和在本地操做有些地方是不同的,只要有一步出錯可能就要卡殼好久,鑑於網上用 EC2 搭建這方面資料不多,所以這裏寫一篇文章把主要流程記錄下來。node

若是以前沒有使用過 EC2,可能須要花一段時間熟悉,好比註冊以及建立密鑰對等步驟,官方提供了相關教程 。另外個人本地機和雲端機使用的都是 Ubuntu 16.04 LTS 64位,若是你的本地機是 Windows,則須要用 Git 或 PuTTY 鏈接雲端機,詳情參閱 https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/putty.html linux




建立 EC2 實例

下面正式開始,這裏設立三臺機器 (實例),一臺做主節點 (master node),兩臺做從節點 (slaves node)。首先建立實例,選擇 Ubuntu Server 16.04 LTS (HVM) ,實例類型選擇價格低廉的 t2.medium 。若是是第一次用,就不要選價格過高的類型了,否則萬一操做失誤了每個月帳單可承受不起。git


在第 3 步中,由於要同時開三臺機器,Number of Instances 能夠直接選擇3。但若是是每臺分別開的話,下面的 Subnet 都要選擇同一個區域,否則機器間沒法通訊,詳情參閱 https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/using-regions-availability-zones.htmlgithub


第 4 步設置硬盤大小,若是就搭個集羣可能不用動,若是還要裝其餘軟件,可能就須要在這裏增長容量了,我是增長到了 15 GB:web


第 5 和第 6 步直接Next 便可,到第 7 步 Launch 後選擇或新建密鑰對,就能獲得建立好的 3 個實例,這裏能夠設置名稱備註,如 master、slave0一、slave02 等:sql


開啓 3 個終端窗口,ssh 鏈接3個實例,如 ssh -i xxxx.pem ubuntu@ec2-xx-xxx-xxx-xx.us-west-2.compute.amazonaws.com ,其中 xxxx.pem 是你的本地密鑰對名稱,ec2-xx-xxx-xxx-xx.us-west-2.compute.amazonaws.com 是該實例的外部 DNS 主機名,每臺實例都不同。這裏須要說明一下,由於這是和本地開虛擬機的不一樣之處: EC2 的實例都有公有 IP 私有 IP 之分,私有 IP 用於雲上實例之間的通訊,而公有 IP 則用於你的本地機與實例之間的通訊,所以這裏 ssh 鏈接使用的是公有 IP (DNS) 。在下面搭建集羣的步驟中也有須要填寫公有和私有 IP ,注意不要填反了。關於兩者的區別參閱 https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/using-instance-addressing.html?shortFooter=true#using-instance-addressing-common shell




新增 hadoop 用戶、安裝 Java 環境

如下以 master 節點爲例。登錄實例後,默認用戶爲 ubuntu,首先須要建立一個 hadoop 用戶:apache

$ sudo useradd -m hadoop -s /bin/bash   # 增長 hadoop用戶
$ sudo passwd hadoop                    # 設置密碼,須要輸入兩次
$ sudo adduser hadoop sudo              # 爲 hadoop 用戶增長管理員權限
$ su hadoop                             # 切換到 hadoop 用戶,須要輸入密碼
$ sudo apt-get update                   # 更新 apt 源

這一步完成以後,終端用戶名會變爲 hadoop,且 /home 目錄下會另外生成一個 hadoop 文件夾。


Hadoop 依賴於 Java 環境,因此接下來須要先安裝 JDK,直接從官網下載,這裏下的是 Linux x64 版本 jdk-8u231-linux-x64.tar.gz ,用 scp 遠程傳輸到 master 機。注意這裏只能傳輸到 ubuntu 用戶下,傳到 hadoop 用戶下可能會提示權限不足。

$ scp -i xxx.pem jdk-8u231-linux-x64.tar.gz ubuntu@ec2-xx-xxx-xxx-xx.us-west-2.compute.amazonaws.com:/home/ubuntu/  # 本地執行該命令

本篇假設全部軟件都安裝在 /usr/lib 目錄下:

$ sudo mv /home/ubuntu/jdk-8u231-linux-x64.tar.gz /home/hadoop         # 將文件移動到 hadoop 用戶下
$ sudo tar -zxf /home/hadoop/jdk-8u231-linux-x64.tar.gz -C /usr/lib/   # 把JDK文件解壓到/usr/lib目錄下
$ sudo mv /usr/lib/jdk1.8.0_231  /usr/lib/java                         # 重命名java文件夾
$ vim ~/.bashrc                                                        # 配置環境變量,貌似EC2只能使用 vim

添加以下內容:

export JAVA_HOME=/usr/lib/java
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
$ source ~/.bashrc   # 讓配置文件生效
$ java -version    # 查看 Java 是否安裝成功

若是出現如下提示則表示安裝成功:


在 master 節點完成上述步驟後,在兩個 slave 節點完成一樣的步驟 (新增 hadoop 用戶、安裝 Java 環境)




網絡配置

這一步是爲了便於 Master 和 Slave 節點進行網絡通訊,在配置前請先肯定是以 hadoop 用戶登陸的。首先修改各個節點的主機名,執行 sudo vim /etc/hostname ,在 master 節點上將 ip-xxx-xx-xx-xx 變動爲 Master 。其餘節點相似,在 slave01 節點上變動爲 Slave01,slave02 節點上爲 Slave02。

而後執行 sudo vim /etc/hosts 修改本身所用節點的IP映射,以 master 節點爲例,添加紅色區域內信息,注意這裏的 IP 地址是上文所述的私有 IP:


接着在兩個 slave 節點的hosts中添加一樣的信息。完成後重啓一下,在進入 hadoop 用戶,能看到機器名的變化 (變成 Master 了):


對於 ec2 實例來講,還須要配置安全組 (Security groups),使實例可以互相訪問 :


選擇劃線區域,我由於是同時創建了三臺實例,因此安全組都同樣,若是不是同時創建的,這可能三臺都要配置。

進入後點擊 Inbound 再點 Edit ,再點擊 Add Rule,選擇裏面的 All Traffic ,接着保存退出:


三臺實例都設置完成後,須要互相 ping 一下測試。若是 ping 不通,後面是不會成功的:

$ ping Master -c 3   # 分別在3臺機器上執行這三個命令
$ ping Slave01 -c 3
$ ping Slave02 -c 3



接下來安裝 SSH server, SSH 是一種網絡協議,用於計算機之間的加密登陸。安裝完 SSH 後,要讓 Master 節點能夠無密碼 SSH 登錄到各個 Slave 節點上,在Master節點執行:

$ sudo apt-get install openssh-server
$ ssh localhost                                         # 使用 ssh 登錄本機,須要輸入 yes 和 密碼
$ exit                                                  # 退出剛纔的 ssh localhost, 注意不要退出hadoop用戶
$ cd ~/.ssh/                                            # 若沒有該目錄,請先執行一次ssh localhost
$ ssh-keygen -t rsa                                     # 利用 ssh-keygen 生成密鑰,會有提示,瘋狂按回車就行
$ cat ./id_rsa.pub >> ./authorized_keys                 # 將密鑰加入受權
$ scp ~/.ssh/id_rsa.pub Slave01:/home/hadoop/           # 將密鑰傳到 Slave01 節點
$ scp ~/.ssh/id_rsa.pub Slave02:/home/hadoop/           # 將密鑰傳到 Slave02 節點

接着在 Slave01和 Slave02 節點上,將 ssh 公匙加入受權:

$ mkdir ~/.ssh       # 若是不存在該文件夾需先建立,若已存在則忽略
$ cat ~/id_rsa.pub >> ~/.ssh/authorized_keys

這樣,在 Master 節點上就能夠無密碼 SSH 到各個 Slave 節點了,可在 Master 節點上執行以下命令進行檢驗,以下圖所示變爲 Slave01了,再按 exit 可退回到 Master:

至此網絡配置完成。




安裝 Hadoop

去到鏡像站 https://archive.apache.org/dist/hadoop/core/ 下載,我下載的是 hadoop-2.8.4.tar.gz 。在 Master 節點上執行:

$ sudo tar -zxf /home/ubuntu/hadoop-2.8.4.tar.gz -C /usr/lib     # 解壓到/usr/lib中
$ cd /usr/lib/
$ sudo mv ./hadoop-2.8.4/ ./hadoop                               # 將文件夾名改成hadoop
$ sudo chown -R hadoop ./hadoop                                  # 修改文件權限

將 hadoop 目錄加到環境變量,這樣就能夠在任意目錄中直接使用 hadoop、hdfs 等命令。執行 vim ~/.bashrc ,加入一行:

export PATH=$PATH:/usr/lib/hadoop/bin:/usr/lib/hadoop/sbin

保存後執行 source ~/.bashrc 使配置生效。


完成後開始修改 Hadoop 配置文件(這裏也順便配置了 Yarn),先執行 cd /usr/lib/hadoop/etc/hadoop ,共有 6 個須要修改 —— hadoop-env.shslavescore-site.xmlhdfs-site.xmlmapred-site.xmlyarn-site.xml


一、文件 hadoop-env.sh 中把 export JAVA_HOME=${JAVA_HOME} 修改成 export JAVA_HOME=/usr/lib/java ,即 Java 安裝路徑。


二、 文件 slaves 把裏面的 localhost 改成 Slave01和 Slave02 。


三、core-site.xml 改成以下配置:

<configuration>
        <property>
                <name>fs.defaultFS</name>
                <value>hdfs://Master:9000</value>
        </property>
        <property>
                <name>hadoop.tmp.dir</name>
                <value>file:/usr/lib/hadoop/tmp</value>
                <description>Abase for other temporary directories.</description>
        </property>
</configuration>


四、hdfs-site.xml 改成以下配置:

<configuration>
        <property>
                <name>dfs.namenode.secondary.http-address</name>
                <value>Master:50090</value>
        </property>
        <property>
                <name>dfs.replication</name>
                <value>2</value>
        </property>
        <property>
                <name>dfs.namenode.name.dir</name>
                <value>file:/usr/lib/hadoop/tmp/dfs/name</value>
        </property>
        <property>
                <name>dfs.datanode.data.dir</name>
                <value>file:/usr/lib/hadoop/tmp/dfs/data</value>
        </property>
</configuration>


五、文件 mapred-site.xml (可能須要先重命名,默認文件名爲 mapred-site.xml.template):

<configuration>
        <property>
                <name>mapreduce.framework.name</name>
                <value>yarn</value>
        </property>
        <property>
                <name>mapreduce.jobhistory.address</name>
                <value>Master:10020</value>
        </property>
        <property>
                <name>mapreduce.jobhistory.webapp.address</name>
                <value>Master:19888</value>
        </property>
</configuration>


六、文件 yarn-site.xml

<configuration>
        <property>
                <name>yarn.resourcemanager.hostname</name>
                <value>Master</value>
        </property>
        <property>
                <name>yarn.nodemanager.aux-services</name>
                <value>mapreduce_shuffle</value>
        </property>
</configuration>


配置好後,將 Master 上的 /usr/lib/hadoop 文件夾複製到各個 slave 節點上。在 Master 節點上執行:

$ cd /usr/lib
$ tar -zcf ~/hadoop.master.tar.gz ./hadoop   # 先壓縮再複製
$ scp ~/hadoop.master.tar.gz Slave01:/home/hadoop
$ scp ~/hadoop.master.tar.gz Slave02:/home/hadoop

分別在兩個 slave 節點上執行:

$ sudo tar -zxf ~/hadoop.master.tar.gz -C /usr/lib
$ sudo chown -R hadoop /usr/lib/hadoop

安裝完成後,首次啓動須要先在 Master 節點執行 NameNode 的格式化:

$ hdfs namenode -format       # 首次運行須要執行初始化,以後不須要

成功的話,會看到 「successfully formatted」 和 「Exitting with status 0」 的提示,若爲 「Exitting with status 1」 則是出錯。



接着能夠啓動 Hadoop 和 Yarn 了,啓動須要在 Master 節點上進行:

$ start-dfs.sh
$ start-yarn.sh
$ mr-jobhistory-daemon.sh start historyserver

經過命令 jps 能夠查看各個節點所啓動的進程。正確的話,在 Master 節點上能夠看到 NameNode、ResourceManager、SecondrryNameNode、JobHistoryServer 進程,以下圖所示:

在 Slave 節點能夠看到 DataNode 和 NodeManager 進程,以下圖所示:


經過命令 hdfs dfsadmin -report 可查看集羣狀態,其中 Live datanodes (2) 代表兩個從節點都已正常啓動,若是是 0 則表示不成功:


能夠經過下列三個地址查看 hadoop 的 web UI,其中 ec2-xx-xxx-xxx-xx.us-west-2.compute.amazonaws.com 是該實例的外部 DNS 主機名,50070、808八、19888 分別是 hadoop、yarn、JobHistoryServer 的默認端口:

ec2-xx-xxx-xxx-xx.us-west-2.compute.amazonaws.com:50070
ec2-xx-xxx-xxx-xx.us-west-2.compute.amazonaws.com:8088
ec2-xx-xxx-xxx-xx.us-west-2.compute.amazonaws.com:19888




執行 Hadoop 分佈式實例

$ hadoop fs -mkdir -p /user/hadoop   # 在hdfs上建立hadoop帳戶
$ hadoop fs -mkdir input
$ hadoop fs -put /usr/lib/hadoop/etc/hadoop/*.xml input  # 將hadoop配置文件複製到hdfs中
$ hadoop jar /usr/lib/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar grep input output 'dfs[a-z.]+'  # 運行實例

若是成功能夠看到如下輸出:


最後關閉 Hadoop 集羣須要執行如下命令:

$ stop-yarn.sh
$ stop-dfs.sh
$ mr-jobhistory-daemon.sh stop historyserver




安裝 Spark

去到鏡像站 https://archive.apache.org/dist/spark/ 下載,因爲以前已經安裝了Hadoop,因此我下載的是無 Hadoop 版本的,即 spark-2.3.3-bin-without-hadoop.tgz 。在 Master 節點上執行:

$ sudo tar -zxf /home/ubuntu/spark-2.3.3-bin-without-hadoop.tgz -C /usr/lib  # 解壓到/usr/lib中
$ cd /usr/lib/
$ sudo mv ./spark-2.3.3-bin-without-hadoop/ ./spark  # 將文件夾名改成spark
$ sudo chown -R hadoop ./spark                        # 修改文件權限

將 spark 目錄加到環境變量,執行 vim ~/.bashrc 添加以下配置:

export SPARK_HOME=/usr/lib/spark
export PATH=$PATH:$SPARK_HOME/bin:$SPARK_HOME/sbin

保存後執行 source ~/.bashrc 使配置生效。


接着須要配置了兩個文件,先執行 cd /usr/lib/spark/conf

一、 配置 slaves 文件

mv slaves.template slaves  # 將slaves.template重命名爲slaves

slaves文件設置從節點。編輯 slaves 內容,把默認內容localhost替換成兩個從節點的名字:

Slave01
Slave02


二、配置 spark-env.sh 文件

mv spark-env.sh.template spark-env.sh

編輯 spark-env.sh 添加以下內容:

export SPARK_DIST_CLASSPATH=$(/usr/lib/hadoop/bin/hadoop classpath)
export HADOOP_CONF_DIR=/usr/lib/hadoop/etc/hadoop
export SPARK_MASTER_IP=172.31.40.68   # 注意這裏填的是Master節點的私有IP 
export JAVA_HOME=/usr/lib/java


配置好後,將 Master 上的 /usr/lib/spark 文件夾複製到各個 slave 節點上。在 Master 節點上執行:

$ cd /usr/lib
$ tar -zcf ~/spark.master.tar.gz ./spark
$ scp ~/spark.master.tar.gz Slave01:/home/hadoop
$ scp ~/spark.master.tar.gz Slave02:/home/hadoop

而後分別在兩個 slave 節點上執行:

$ sudo tar -zxf ~/spark.master.tar.gz -C /usr/lib
$ sudo chown -R hadoop /usr/lib/spark


在啓動 Spark 集羣以前,先確保啓動了 Hadoop 集羣:

$ start-dfs.sh
$ start-yarn.sh
$ mr-jobhistory-daemon.sh start historyserver
$ start-master.sh  # 啓動 spark 主節點
$ start-slaves.sh  # 啓動 spark 從節點

可經過 ec2-xx-xxx-xxx-xx.us-west-2.compute.amazonaws.com:8080 訪問 spark web UI 。




執行 Spark 分佈式實例

一、經過命令行提交 JAR 包:

$ spark-submit --class org.apache.spark.examples.SparkPi --master spark://Master:7077 /usr/lib/spark/examples/jars/spark-examples_2.11-2.3.3.jar 100 2>&1 | grep "Pi is roughly"

結果以下說明成功:


二、經過 IDEA 遠程鏈接運行程序:

能夠在 本地 IDEA 中編寫代碼,遠程提交到雲端機上執行,這樣比較方便調試。須要注意的是 Master 地址填雲端機的公有 IP 地址。下面以一個 WordVec 程序示例,將句子轉換爲向量形式:

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.log4j.{Level, Logger}
import org.apache.spark.ml.feature.Word2Vec
import org.apache.spark.ml.linalg.Vector
import org.apache.spark.sql.Row
import org.apache.spark.sql.SparkSession

object Word2Vec {
  def main(args: Array[String]) {
    Logger.getLogger("org").setLevel(Level.ERROR)  // 控制輸出信息
    Logger.getLogger("com").setLevel(Level.ERROR)

    val conf = new SparkConf()
      .setMaster("spark://ec2-54-190-51-132.us-west-2.compute.amazonaws.com:7077")  // 填公有DNS或公有IP地址均可以
      .setAppName("Word2Vec")
      .set("spark.cores.max", "4")
      .set("spark.executor.memory", "2g")
    val sc = new SparkContext(conf)

    val spark = SparkSession
      .builder
      .appName("Word2Vec")
      .getOrCreate()

    val documentDF = spark.createDataFrame(Seq(
      "Hi I heard about Spark".split(" "),
      "I wish Java could use case classes".split(" "),
      "Logistic regression models are neat".split(" ")
    ).map(Tuple1.apply)).toDF("text")

    val word2Vec = new Word2Vec()
      .setInputCol("text")
      .setOutputCol("result")
      .setVectorSize(3)
      .setMinCount(0)
    val model = word2Vec.fit(documentDF)

    val result = model.transform(documentDF)
    result.collect().foreach { case Row(text: Seq[_], features: Vector) =>
      println(s"Text: [${text.mkString(", ")}] => \nVector: $features\n") }
  }
}


IDEA 控制檯輸出:


關閉 Spark 和 Hadoop 集羣有如下命令:

$ stop-master.sh
$ stop-slaves.sh
$ stop-yarn.sh
$ stop-dfs.sh
$ mr-jobhistory-daemon.sh stop historyserver



固然最後也是最重要的是,使用完後不要忘了關閉 EC2 實例,否則會 24 小時不間斷產生費用的。





/

相關文章
相關標籤/搜索