Try   HackMD

Hadoop Ecosystem (HDFS, MapReduce)

tags: Course

Hadoop 必須套件

以下套件為本次安裝過程中會使用到的部分 :

Hadoop 安裝前所需注意的事項

  1. 此處會跳過 ubuntu 16.04 與虛擬機的建置。
  2. 每台虛擬機上的使用者名稱請統一,例如 : hadoop
  3. 本次安裝過程會建立四台虛擬機,MasterDatanode1Datanode2Datanode3
  4. 各虛擬機的 IP 需在同網域且都不相同,可參考虛擬機設定的 橋接介面卡
  5. 每個步驟都會先說明是所有主機都要執行同步驟,還是只有Master 主機需要做而已。

Hadoop Fully-Distribted Operation

本安裝過程皆以 fully-distributed operation 為主,如果要 standalone operation 或 pseudo-distributed operation 請參考 此處

Step 1

所有主機

  • 更新所有主機的套件。
$ sudo apt-get update
  • 安裝 vim 或其他文字編輯器。
$ sudo apt-get install vim
  • 集群、單節點模式都需要用到 ssh 登陸(類似於遠程登陸,你可以登錄某台 Linux 主機,並且在上面運行命令), Ubuntu 默認已安裝了 ssh client ,此外還需要安裝 ssh server 。
$ sudo apt-get install openssh-server
  • 安裝完後,應該可以透過 $ ssh localhost 連到本機,但需要輸入密碼。
  • 退出 ssh 後使用 ssh-keygen 產生各節點的公、私鑰。
$ cd ~/.ssh/
$ ssh-keygen -t rsa
$ cat ./id_rsa.pub >> ./authorized_keys
  • 更新後,使用 $ ssh localhost 就可以無密碼登入了。
  • 修改各主機的 host name , Master 虛擬機叫 Master , Datanode1 虛擬機叫 Datanode1 ,以此類推。
$ sudo vim /etc/hostname
  • 修改各 /etc/hosts 文件中映射到其他節點的 ip 。
$ sudo vim /etc/hosts
  • 修改完應該如下 :
127.0.0.1       localhost
10.1.1.13       Master
10.1.1.14       Datanode1
10.1.1.15       Datanode2
10.1.1.12       Datanode3
# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
  • 如果有多餘的對應,例如 127.0.0.1 對到 Master 等,應該刪除。
  • Datanode1Datanode2Datanode3Master 都要修改 /etc/hosts
  • 修改後,對各節點使用 ping 應該都要有回應,否則失敗。

Step 2

Master 主機

  • 需要讓 Master 可以不用密碼的從 ssh 登入,故將 Master 的公鑰傳至其他節點 (Datanode1Datanode2Datanode3 都要)。
$ scp /home/hadoop/.ssh/id_rsa.pub hadoop@Datanode1:/home/hadoop
$ scp /home/hadoop/.ssh/id_rsa.pub hadoop@Datanode2:/home/hadoop
$ scp /home/hadoop/.ssh/id_rsa.pub hadoop@Datanode3:/home/hadoop
  • 接著登入 Datanode1 並將公鑰加入 authorized_keys ,其他節點照做。
$ mkdir ~/.ssh
$ cat ~/id_rsa.pub >> ~/.ssh/authorized_keys
$ rm ~/id_rsa.pub
  • 如此一來, Master 就可以無密碼登入至其他節點。

Step 3

所有主機

  • 安裝 Java 環境, Java 環境可選擇 Oracle 的 JDK ,或是 OpenJDK 。為圖方便,這邊直接通過命令安裝 OpenJDK 8。
$ sudo apt-get install openjdk-8-jre openjdk-8-jdk
  • 環境變數 文件 ~/.bashrc 的第一列加入下列變數。
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
  • 執行 $ source ~/.bashrc 來使環境變數生效。
  • 可透過下列命令來確認執行是否正確。
$ echo $JAVA_HOME
/usr/lib/jvm/java-8-openjdk-amd64

$ java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-8u191-b12-2ubuntu0.18.04.1-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)

$ $JAVA_HOME/bin/java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-8u191-b12-2ubuntu0.18.04.1-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)
  • 如果以上命令的結果都有正確顯示則表示環境變數沒問題。

Step 4

Master 主機

  • 這裡選擇將 Hadoop 安裝至 /usr/local/ ,先下載 Hadoop 3.2.0 到 ~/Downloads
  • 解壓縮至 /usr/local/ 後再更改 owner 。
$ sudo tar -zxf ~/Downloads/hadoop-3.2.0.tar.gz -C /usr/local
$ cd /usr/local
$ sudo mv ./hadoop-3.2.0 ./hadoop
$ sudo chown -R hadoop ./hadoop
  • 可輸入以下命令來檢查 Hadoop 使否可用 :
$ cd /usr/local/hadoop
$ ./bin/hadoop version
Hadoop 3.2.0
Source code repository https://github.com/apache/hadoop.git -r e97acb3bd8f3befd27418996fa5d4b50bf2e17bf
Compiled by sunilg on 2019-01-08T06:08Z
Compiled with protoc 2.5.0
From source with checksum d3f0795ed0d9dc378e2c785d3668f39
This command was run using /usr/local/hadoop/share/hadoop/common/hadoop-common-3.2.0.jar
  • 如果有出現上述訊息,表示安裝成功。
  • 在集群/分散式模式下,會修改在 /usr/local/hadoop/etc/hadoop 路徑下的五個配置文件 : workerscore-site.xmlhdfs-site.xmlmapred-site.xmlyarn-site.xml
    1. workers 加入所有 DataNode 的 host name :

      ​​​​​​​​Datanode1
      ​​​​​​​​Datanode2
      ​​​​​​​​Datanode3
      

      如果 NameNode 本身也是 DataNode ,也需要在此加入 Master

    2. core-site.xml 加入以下配置 :

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

      fs.defaultFS 是預設的 NameNode 的 URL ,在此為 Master

    3. hdfs-site.xml 加入以下配置 :

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

      dfs.replication 意指有多少的 DataNode 節點。

    4. mapred-site.xml 加入以下配置 :

      ​​​​​​​​<configuration>
      ​​​​​​​​        <property>
      ​​​​​​​​                <name>mapreduce.framework.name</name>
      ​​​​​​​​                <value>yarn</value>
      ​​​​​​​​        </property>
      ​​​​​​​​        <property>
      ​​​​​​​​                <name>yarn.app.mapreduce.am.env</name>
      ​​​​​​​​                <value>HADOOP_MAPRED_HOME=$HADOOP_MAPRED_HOME</value>
      ​​​​​​​​        </property>
      ​​​​​​​​        <property>
      ​​​​​​​​                <name>mapreduce.map.env</name>
      ​​​​​​​​                <value>HADOOP_MAPRED_HOME=$HADOOP_MAPRED_HOME</value>
      ​​​​​​​​        </property>
      ​​​​​​​​        <property>
      ​​​​​​​​                <name>mapreduce.reduce.env</name>
      ​​​​​​​​                <value>HADOOP_MAPRED_HOME=$HADOOP_MAPRED_HOME</value>
      ​​​​​​​​        </property>
      ​​​​​​​​</configuration>
      

      HADOOP_MAPRED_HOME 為 hadoop 的目錄,如果不設定會無法執行 MapReduce 應用,稍後會加入此環境變數。

    5. 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/local/hadoop 資料夾複製到其他節點。
$ cd /usr/local
$ tar -zcf ~/hadoop.master.tar.gz ./hadoop
$ cd ~
$ scp ./hadoop.master.tar.gz Datanode1:/home/hadoop
$ scp ./hadoop.master.tar.gz Datanode2:/home/hadoop
$ scp ./hadoop.master.tar.gz Datanode3:/home/hadoop
  • 在其他節點上執行以下命令來解壓縮並更改 owner :
$ sudo tar -zxf ~/hadoop.master.tar.gz -C /usr/local
$ sudo chown -R hadoop /usr/local/hadoop

Step 5

Master 主機

  • 在環境變數 ~/.bashrc 內加入其他變數,需要加在 $JAVA_HOME 後面 :
export HADOOP_MAPRED_HOME=/usr/local/hadoop
export PATH=$PATH:/usr/local/hadoop/bin:/usr/local/hadoop/sbin:$JAVA_HOME/bin
  • 下命令 $ source ~/.bashrc 來啟用變數。
  • 初始化 NameNode ,只需要跑第一次,之後啟動都不用跑 :
$ hdfs namenode -format
  • 下命令來啟動 NameNode 與 DataNode :
$ start-dfs.sh
Starting namenodes on [Master]
Starting datanodes
Starting secondary namenodes [Master] 
  • 啟動 yarn 資源管理 :
$ start-yarn.sh
Starting resourcemanager
Starting nodemanagers
  • 在各節點下命令 $ jps 應該會看到目前有啟用的 hadoop daemon 。

    • Master 上應該看到 :

      ​​​​​​​​$ jps
      ​​​​​​​​7379 NameNode
      ​​​​​​​​7670 SecondaryNameNode
      ​​​​​​​​7944 ResourceManager
      ​​​​​​​​8266 Jps
      
    • Datanode1Datanode2Datanode3 應該看到 :

      ​​​​​​​​$ jps
      ​​​​​​​​6150 Jps
      ​​​​​​​​5784 DataNode
      ​​​​​​​​5960 NodeManager 
      
  • 成功之後,應該可以透過 Master 的瀏覽器連線到 http://localhost:9870 看到 hadoop 的管理介面。

  • 若要連線到 YARN 的 ResourceManager 介面,可以連線到 http://master:8088

  • 要停止 hadoop ,可以下 $ stop-all.sh 命令。

Reference

hadoop 3.1.1 安裝教程
hadoop 集群配置教程
hadoop cluster setup
hdfs command
hadoop shell command


Hadoop MapReduce Application

這裡會使用最簡單的 WordCount.java 程式來執行 MapReduce 。

Step 1

  • 加入 HADOOP_CLASSPATH 環境變數至 ~/.bashrc 並啟用。
export HADOOP_CLASSPATH=$JAVA_HOME/lib/tools.jar
  • 產生官方的 WordCount.java 檔案 :
import java.io.IOException; import java.util.StringTokenizer; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class WordCount { public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable>{ private final static IntWritable one = new IntWritable(1); private Text word = new Text(); public void map(Object key, Text value, Context context ) throws IOException, InterruptedException { StringTokenizer itr = new StringTokenizer(value.toString()); while (itr.hasMoreTokens()) { word.set(itr.nextToken()); context.write(word, one); } } } public static class IntSumReducer extends Reducer<Text,IntWritable,Text,IntWritable> { private IntWritable result = new IntWritable(); public void reduce(Text key, Iterable<IntWritable> values, Context context ) throws IOException, InterruptedException { int sum = 0; for (IntWritable val : values) { sum += val.get(); } result.set(sum); context.write(key, result); } } public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); Job job = Job.getInstance(conf, "word count"); job.setJarByClass(WordCount.class); job.setMapperClass(TokenizerMapper.class); job.setCombinerClass(IntSumReducer.class); job.setReducerClass(IntSumReducer.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); FileInputFormat.addInputPath(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); System.exit(job.waitForCompletion(true) ? 0 : 1); } }
  • 編譯 WordCount.java :
$ hadoop com.sun.tools.javac.Main WordCount.java 
  • 雖然會報 HADOOP_COM.SUN.TOOLS.JAVAC.MAIN_OPTS: bad substitution 的錯誤,不過還是能產生 class 檔。
  • WordCount*.class 合成一個 jar 檔,名為 wc.jar :
$ jar cf wc.jar WordCount*.class

Step 2

  • 在 HDFS 上建立 輸入 資料夾,不用建立 輸出 資料夾。
$ hadoop fs -mkdir -p /user/hadoop/input
  • 產生兩個 file , testfiletestfile2 ,並將其放入 HDFS 的 input
$ hadoop fs -put testfile /user/hadoop/input/testfile
$ hadoop fs -put testfile2 /user/hadoop/input/testfile2
  • $ hadoop fs -ls /user/hadoop/input 應該會看到兩個檔案。
Found 2 items
-rw-r--r--   3 hadoop supergroup         46 2019-05-08 01:24 /user/hadoop/input/testfile
-rw-r--r--   3 hadoop supergroup         28 2019-05-11 01:00 /user/hadoop/input/testfile2
  • 執行 WordCount :
$ hadoop jar wc.jar WordCount /user/hadoop/input /user/hadoop/output
  • 最後會獲得一連串的 log 。
2019-05-11 01:05:02,272 INFO client.RMProxy: Connecting to ResourceManager at Master/10.1.1.13:8032
2019-05-11 01:05:02,766 WARN mapreduce.JobResourceUploader: Hadoop command-line option parsing not performed. Implement the Tool interface and execute your application with ToolRunner to remedy this.
 .....
	File Input Format Counters 
		Bytes Read=74
	File Output Format Counters 
		Bytes Written=38
  • 可以透過下命令 $hadoop fs -ls /user/hadoop/output 來確認 MapReduce 結果是否成功,若有 _SUCCESS 則表示成功。
Found 2 items
-rw-r--r--   3 hadoop supergroup          0 2019-05-11 01:05 /user/hadoop/output/_SUCCESS
-rw-r--r--   3 hadoop supergroup         38 2019-05-11 01:05 /user/hadoop/output/part-r-00000
  • 透過下命令 $ hadoop fs -cat /user/hadoop/output/part-r-00000 來查看結果。
BBye	2
Bye	2
Hadoop	2
Hello	4
World	3

Reference

MapReduce Tutorial
IT hadoop 鐵人競賽
MapReduce Hadoop Multiple Input


Spark 安裝套件 (Working)

手動安裝 Spark

  • 解壓縮檔案後將目錄一致 /usr/local 底下。
$ cd ~/Downloads
$ tar -xvf spark-2.4.3-bin-hadoop2.7.tgz -C /usr/local
$ sudo mv ./spark-2.4.3-bin-hadoop2.7 ./spark
  • 修改 ~/.bashrc 來加入 Spark 與 HADOOP_CONF_DIR 的環境變數,記得 soruce ~/.bashrc 套用變數。
export HADOOP_MAPRED_HOME=/usr/local/hadoop
export SPARK_HOME=/usr/local/spark
export HADOOP_CONF_DIR=$HADOOP_MAPRED_HOME/etc/hadoop
export PATH=$PATH:/usr/local/hadoop/bin:/usr/local/hadoop/sbin:$JAVA_HOME/bin:$SPARK_HOME/bin
  • 安裝 python
  • 安裝 Scala

Reference