1. 程式人生 > >Hadoop-2.8.0實踐——搭建Hadoop叢集

Hadoop-2.8.0實踐——搭建Hadoop叢集

在本地測試hadoop成功後,我們在多臺主機上搭建hadoop叢集,用於處理大規模資料…

一、準備工作

1.1 系統環境

三臺 Ubuntu 16.04 64位筆記本(一臺作為Master節點,另外兩臺作為Slave節點)

1.2 建立使用者

建立使用者,併為其新增root許可權:

sudo adduser hadoop
sudo vim /etc/sudoers
# 修改內容如下:
root 	ALL=(ALL:ALL) ALL
hadoop 	ALL=(ALL:ALL) ALL

給hadoop使用者建立目錄,並新增到sudo使用者組中:

sudo chown hadoop /home/hadoop
# 新增到sudo使用者組
sudo adduser hadoop sudo

最後登出當前使用者,使用新建立的hadoop使用者登陸。

1.3 設定Master與Slave的SSH無密登陸

1.3.1 準備工作

首先要確保你的linux系統中已經安裝了ssh,對於ubuntu系統一般預設只安裝了ssh client,所以還需要我們手動安裝ssh server:

sudo apt-get install openssh-server
1.3.2 SSH基本原理

SSH採用公鑰加密來保證安全。過程如下:
1.遠端主機收到使用者的登入請求,把自己的公鑰發給使用者;
2.使用者使用這個公鑰,將登入密碼加密後,傳送回來;
3.遠端主機用自己的私鑰,解密登入密碼,如果密碼正確,就同意使用者登入。

1.3.3 基本用法

SSH預設埠號為:22,可以根據自己的需要修改預設埠號。SSH遠端登陸:

# 使用預設的22埠
ssh 192.168.0.1
# 若修改過SSH預設埠號(例如:修改為了10000),則登陸時需要指定埠號10000
ssh 192.168.0.1 -p 10000
1.3.4 配置SSH無密登陸

Hadoop執行過程中需要管理遠端Hadoop守護程序,在Hadoop啟動以後,NameNode是通過SSH(Secure Shell)來啟動和停止各個DataNode上的各種守護程序的。這就必須在節點之間執行指令的時候是不需要輸入密碼的形式,故我們需要配置SSH運用無密碼公鑰認證的形式,這樣NameNode使用SSH無密碼登入並啟動DataName程序,同樣原理,DataNode上也能使用SSH無密碼登入到 NameNode。

  • 首先,執行ssh localhost來產生/home/使用者名稱/.ssh目錄,然後將生成的 “ id_rsa.pub ” 追加到授權的key裡面去。這樣的效果是實現了當前使用者無密SSH登陸到自己:
cd ~/.ssh  # 如果找不到這個資料夾,先執行一下 "ssh localhost"
ssh-keygen -t rsa
# 將id_rsa.pub追加到authorized_keys(切記是追加,不是覆蓋)
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
  • 如果要實現無密登陸到其它的主機,只需將生成的 “ id_rsa.pub " 追加到其它主機的 ” ~/.ssh/authorized_keys “ 中去。這裡我們使用的方法是先將本機的 ” ~/.ssh/id_rsa.pub “ 拷貝到你想無密登陸的主機上,再在相應的主機上將” ~/.ssh/id_rsa.pub “ 追加到該主機的 ” ~/.ssh/authorized_keys “ 中。
# 假設我們的主機名為:A,使用者名稱:hadoop,ip:192.168.0.1
# 想要無密SSH登陸的主機名為:B, 使用者名稱:hadoop,ip:192.168.0.2

# 首先,我們使用A中的hadoop使用者拷貝 " ~/.ssh/id_rsa.pub " 到B的 " /home/hadoop/ " 目錄下
scp ~/.ssh/id_rsa.pub [email protected]:/home/hadoop/
# 這裡的ip也可以換為主機名

# 然後,ssh登陸B,將 " /home/hadoop/id_rsa.pub " 追加到 " ~/.ssh/authorized_keys " 中去。
cat /home/hadoop/id_rsa.pub >> ~/.ssh/authorized_keys

現在,我們就可以在A中使用SSH無密登陸到B的hadoop使用者了,同理如果想無密登陸其它的主機都可以使用此方法。需要注意的是配置hadoop叢集時需要Master和Slave可以互相SSH無密登陸。

二、網路配置

這裡使用了三臺主機搭建叢集,選定master後,在該主機的/etc/hostname中,修改機器名為master,將其他主機命名為slave1、slave2等。

接著將"主機名與IP地址對應資訊"寫入/etc/hosts檔案中:

127.0.0.1 localhost
# 填入以下資訊:
192.168.199.133 master
192.168.199.204 slave1
192.168.199.194 slave2

注:各臺主機(包括Master和Slave)都要進行相應的配置。

配置好之後,在各個主機上執行ping master和ping slave1測試,驗證是否相互ping得通。

在這裡插入圖片描述(說明:這裡將slave主機命名為node1、node2,只要前後對應即可。)

三、安裝Hadoop

  • 選擇下載 hadoop-2.8.0.tar.gz
  • 將下載的壓縮檔案解壓至/home/hadoop/目錄

四、配置叢集/分散式環境

叢集/分散式模式需要修改/home/hadoop/hadoop-2.8.0/etc/hadoop/下的5個配置檔案。

slaves

將原有的localhost刪掉,寫入所有slave的主機名,每行一個。例如:

slave1
slave2

core-site.xml

修改如下:

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

hdfs-site.xml

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

mapred-site.xml

這個檔案不存在,首先需要從模板中複製一份

cp mapred-site.xml.template mapred-site.xml

然後配置如下:

<configuration>
    <property>
        <name>mapreduce.framework.name</name>
        <value>yarn</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上的hadoop檔案複製到其他節點上

# 先壓縮
sudo tar -zcf ~/hadoop-2.8.0.tar.gz ~/hadoop-2.8.0
# 再複製
scp ~/hadoop-2.8.0.tar.gz [email protected]:/home/hadoop
# slave端解壓
sudo tar -zxf ~/hadoop-2.8.0.tar.gz ~/
# 修改hadoop-2.8.0及其子目錄下所有檔案的許可權
sudo chown -R hadoop:hadoop ~/hadoop-2.8.0

五、啟動叢集

5.1 刪除臨時檔案

如果之前跑過偽分佈模式,在切換到叢集模式之前應該先刪除臨時檔案(不然會產生衝突):

rm -rf ~/hadoop/tmp

5.2 啟動

在master主機上:

cd ~/hadoop-2.8.0/
bin/hdfs namenode -format
sbin/start-dfs.sh
sbin/start-yarn.sh

有時會發現slave節點的DataNode啟動失敗,則可以按如下順序執行命令:
(原因:namenode啟動有一定時間延遲)

bin/hdfs namenode -format
sbin/hadoop-daemon.sh start namenode
sbin/hadoop-daemon.sh start datanode
sbin/start-yarn.sh

5.3 檢視各個節點啟動的程序

  • 通過jps命令可以檢視各個節點啟動的程序

    master節點:
    在這裡插入圖片描述

    slave1節點:
    在這裡插入圖片描述

  • 在master節點通過命令bin/hdfs dfsadmin -report可以檢視DataNode是否正常啟動。
    在這裡插入圖片描述

5.4 關閉叢集

在master節點執行:

sbin/stop-dfs.sh
sbin/stop-yarn.sh
# 或者
sbin/stop-all.sh

六、示例:執行 WordCount

6.1 上傳檔案到 HDFS

在本地新建一個檔案 words.txt,寫入將要分析的內容,如:

When You Are Old
When you are old and grey and full of sleep
And nodding by the fire take down this book
And slowly read and dream of the soft look
Your eyes had once and of their shadows deep
How many loved your moments of glad grace
And loved your beauty with love false or true
But one man loved the pilgrim soul in you
And loved the sorrows of your changing face
And bending down beside the glowing bars
Murmur a little sadly how Love fled
And paced upon the mountains overhead
And hid his face amid a crowd of stars

然後在分散式檔案系統中新建一個資料夾/wordcount/input/,用於上傳測試檔案words.txt:

# 在 hdfs 新建資料夾
bin/hdfs dfs -mkdir /wordcount
bin/hdfs dfs -mkdir /wordcount/input

# 上傳檔案
bin/hdfs dfs -put words.txt /wordcount/input/

# 檢視
bin/hdfs dfs -ls /wordcount/input

6.2 編寫 WordCount 程式

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 MyWordCount {
    public static class MyTokenizerMapper
        extends Mapper<Object, Text, Text, IntWritable>{
        private final static IntWritable one = new IntWritable(1);
        private Text word = new Text();

        /**
         * 將句子分解成單詞,並將<word, 1>寫入context
         * @param key
         * @param value
         * @param context
         * @throws IOException
         * @throws InterruptedException
         */
        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 MyIntSumReducer
        extends Reducer<Text, IntWritable, Text, IntWritable>{
        private IntWritable result = new IntWritable();

        /**
         * 累計求和,結果寫入context
         * @param key
         * @param values 一個 key 對應一組 value
         * @param context
         * @throws IOException
         * @throws InterruptedException
         */
        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, "my word count");           // 新建job
        job.setJarByClass(MyWordCount.class);                       // 設定Jar
        job.setMapperClass(MyTokenizerMapper.class);                // 設定Mapper
        job.setCombinerClass(MyIntSumReducer.class);                // 設定Combiner
        job.setReducerClass(MyIntSumReducer.class);                 // 設定Reducer
        job.setOutputKeyClass(Text.class);                          // 設定輸出的key
        job.setOutputValueClass(IntWritable.class);                 // 設定輸出的value
        FileInputFormat.addInputPath(job, new Path(args[0]));       // 設定輸入路徑
        FileOutputFormat.setOutputPath(job, new Path(args[1]));     // 設定輸出路徑
        System.exit(job.waitForCompletion(true) ? 0 : 1);           // 執行job
    }
}

6.3 打包並提交任務

# 環境變數配置:(/etc/profile 或 ~/.bashrc)
export JAVA_HOME=/usr/java/default
export PATH=${JAVA_HOME}/bin:${PATH}
export HADOOP_CLASSPATH=${JAVA_HOME}/lib/tools.jar

# 編譯並打包成jar:
bin/hadoop com.sun.tools.javac.Main WordCount.java
jar cf wc.jar WordCount*.class

# 提交任務(在hadoop根目錄下執行)
bin/hadoop jar wc.jar WordCount /wordcount/input /wordcount/output

# 檢視執行結果:
bin/hadoop fs -cat /wordcount/output/part-r-00000