Mapreduce 学习日记


一、搭建环境

重要的事情先说三遍!!!
先搭好环境!!!
先搭好环境!!!
先搭好环境!!!

我是在Ubuntu系统下安装好Hadoop,并通过eclipse来编译运行MapReduce。
本教程主要测试环境:
Ubuntu 14.04
Hadoop 2.6.0(伪分布式)
Eclipse 3.8

1.1安装Ubuntu

我使用的是 Ubuntu 14.04 64位 作为系统环境(Ubuntu 12.04,Ubuntu16.04 也行,32位、64位均可),请自行安装系统(可参考使用VirtualBox安装Ubuntu)。

安装SSH、配置SSH无密码登陆

Ubuntu 默认已安装了 SSH client,此外还需要安装 SSH server:

sudo apt-get install openssh-server

安装后,可以使用如下命令登陆本机:

ssh localhost

此时会有如下提示(SSH首次登陆提示),输入 yes 。然后按提示输入密码 hadoop,这样就登陆到本机了。
在这里插入图片描述
但这样登陆是需要每次输入密码的,我们需要配置成SSH无密码登陆比较方便。

首先退出刚才的 ssh,就回到了我们原先的终端窗口,然后利用 ssh-keygen 生成密钥,并将密钥加入到授权中:

 exit                           # 退出刚才的 ssh localhost
 cd ~/.ssh/                     # 若没有该目录,请先执行一次ssh localhost 
 ssh-keygen -t rsa              # 会有提示,都按回车就可以
 cat ./id_rsa.pub >> ./authorized_keys  # 加入授权

此时再用 ssh localhost 命令,无需输入密码就可以直接登陆了,如下图所示
在这里插入图片描述

1.2安装Java环境

安装Java环境的方式有多种,我就不一一介绍了。
首先,我是手动安装Java环境
这是我下载JDK1.8的安装包jdk-8u162-linux-x64.tar.gz的地址,
可以点击这里到百度云盘下载JDK1.8安装包(提取码:99bg)
。然后把压缩格式的文件jdk-8u162-linux-x64.tar.gz下载到本地电脑,保存在“/下载”目录下。

cd /usr/lib
sudo mkdir jvm #创建/usr/lib/jvm目录用来存放JDK文件
cd ~ #进入hadoop用户的主目录
cd 下载  #注意区分大小写字母,刚才已经下载的JDK安装   包jdk-8u162-linux-x64.tar.gz上传到该目录下
sudo tar -zxvf ./jdk-8u162-linux-x64.tar.gz -C /usr/lib/jvm  #把JDK文件解压到/usr/lib/jvm目录下

设置环境变量:
编译~/.bashrc,在里面加入下面内容

export JAVA_HOME=/usr/lib/jvm/jdk1.8.0_162
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH

保存.bashrc文件并退出编辑器。然后,继续执行如下命令让.bashrc文件的配置立即生效:

source ~/.bashrc

然后查看JAVA环境配置是否有效

java -version 

如果能够在屏幕上返回如下信息,则说明安装成功
在这里插入图片描述

1.3安装Hadoop

Hadoop可以通过 http://mirror.bit.edu.cn/apache/hadoop/common/ 或者
http://mirrors.cnnic.cn/apache/hadoop/common/
下载
我将 Hadoop 安装至 /usr/local/ 中:

sudo tar -zxf ~/下载/hadoop-2.6.0.tar.gz -C /usr/local    # 解压到/usr/local中
cd /usr/local/
sudo mv ./hadoop-2.6.0/ ./hadoop            # 将文件夹名改为hadoop
sudo chown -R hadoop ./hadoop       # 修改文件权限

Hadoop 解压后即可使用。输入如下命令来检查 Hadoop 是否可用,成功则会显示 Hadoop 版本信息:

cd /usr/local/hadoop
./bin/hadoop version

Hadoop伪分布式配置

Hadoop 的配置文件位于 /usr/local/hadoop/etc/hadoop/ 中,伪分布式需要修改2个配置文件 core-site.xml 和 hdfs-site.xml 。Hadoop的配置文件是 xml 格式,每个配置以声明 property 的 name 和 value 的方式来实现。

修改配置文件 core-site.xml (通过 gedit 编辑会比较方便: gedit ./etc/hadoop/core-site.xml),将当中的

修改为下面配置:

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

同样的,修改配置文件 hdfs-site.xml:

<configuration>
    <property>
         <name>dfs.replication</name>
        <value>1</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>

配置完成后,执行 NameNode 的格式化:

cd /usr/local/hadoop
./bin/hdfs namenode -format

在这里插入图片描述
接着开启 NameNode 和 DataNode 守护进程。

cd /usr/local/hadoop
./sbin/start-dfs.sh  #start-dfs.sh是个完整的可执行文件,中间没有空格

若出现如下SSH提示,输入yes即可

启动完成后,可以通过命令 jps 来判断是否成功启动,若成功启动则会列出如下进程: “NameNode”、”DataNode” 和 “SecondaryNameNode”(如果 SecondaryNameNode 没有启动,请运行 sbin/stop-dfs.sh 关闭进程,然后再次尝试启动尝试)。如果没有 NameNode 或 DataNode ,那就是配置不成功,请仔细检查之前步骤,或通过查看启动日志排查原因。

在这里插入图片描述
成功启动后,可以访问 Web 界面 http://localhost:50070/ 查看 NameNode 和 Datanode 信息,还可以在线查看 HDFS 中的文件。

二、介绍MapReduce 体系结构

MapReduce体系结构主要由四个部分组成,分别是:Client、JobTracker、TaskTracker以及Task。

MapReduce 体系结构
1)Client
用户通过client提交程序到JobTracker端
并且我们可以通过Client提供的一些接口查看作业运行状态
2)JobTracker
JobTracker负责资源监控和作业调度
JobTracker 监控所有TaskTracker与Job的健康状况,一旦发现失败,就将相应的任务转移到其他节点
JobTracker 会跟踪任务的执行进度、资源使用量等信息,并将这些信息告诉任务调度器(TaskScheduler),而调度器会在资源出现空闲时,选择合适的任务去使用这些资源
3)TaskTracker
TaskTracker 会周期性地通过“心跳”将本节点上资源的使用情况和任务的运行进度汇报给JobTracker,同时接收JobTracker 发送过来的命令并执行相应的操作(如启动新任务、杀死任务等)
TaskTracker 使用“slot”等量划分本节点上的资源量(CPU、内存等)。一个Task 获取到一个slot 后才有机会运行,而Hadoop调度器的作用就是将各个TaskTracker上的空闲slot分配给Task使用。slot 分为Map slot 和Reduce slot 两种,分别供MapTask 和Reduce Task 使用
4)Task
Task 分为Map Task 和Reduce Task 两种,均由TaskTracker 启动

三、介绍MapReduce 基本的执行流程

一个基于MapReduce的WordCount程序主要由一下几个部分组成:Split、Map、Shuffle/Combine/sort、Reduce
1、Split

将程序的输入数据进行切分,每一个 split 交给一个 Map Task 执行。split的数量可以自己定义。

2、Map

输入为一个split中的数据,对split中的数据进行拆分,并以 < key, value> 对的格式保存数据,其中 key 的值为一个单词,value的值固定为 1。如 < I , 1>、< wish, 1> …

3、Shuffle/Combine/sort

这几个过程在一些简单的MapReduce程序中并不需要我们关注,因为源代码中已经给出了一些默认的Shuffle/Combine/sort处理器,这几个过程的作用分别是:

Combine:对Map Task产生的结果在本地节点上进行合并、统计等,以减少后续整个集群间的Shuffle过程所需要传输的数据量。
Shuffle / Sort:将集群中各个Map Task的处理结果在集群间进行传输,排序,数据经过这个阶段之后就作为 Reduce 端的输入。

4、Reduce

Reduce Task的输入数据其实已经不仅仅是简单的< key, value>对,而是经过排序之后的一系列key值相同的< key, value>对。Reduce Task对其进行统计等处理,产生最终的输出。
MapReduce 基本的执行流程

四、源码

package org.apache.hadoop.examples;

import java.io.IOException;
import java.util.Iterator;
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;
import org.apache.hadoop.util.GenericOptionsParser;

public class WordCount {
 public WordCount() {
}

public static void main(String[] args) throws Exception {
    Configuration conf = new Configuration();
 String[] otherArgs=new String[]{"input","output"}; /* 直接设置输入参数和输出*/
    if(otherArgs.length < 2) {
        System.err.println("Usage: wordcount <in> [<in>...] <out>");
        System.exit(2);
    }

    // 实例化job,传入参数 
    Job job = Job.getInstance(conf, "word count");   /* getInstance 在主函数开始时调用,返回一个实例化对象,此对象是static的,在内存中保留着它的引用,即内存中有一块区域专门用来存放静态方法和变量,*/
    job.setJarByClass(WordCount.class);  //使用反射机制,加载程序
    job.setMapperClass(TokenizerMapper.class);  //设置job的map阶段的执行类
    job.setCombinerClass(IntSumReducer.class);  //设置job的combine阶段的执行类
    job.setReducerClass(IntSumReducer.class);  //设置job的reduce阶段的执行类
    job.setOutputKeyClass(Text.class);  //设置程序的输出的key值的类型
    job.setOutputValueClass(IntWritable.class);  //设置程序的输出的value值的类型

    for(int i = 0; i < otherArgs.length - 1; ++i) {
        FileInputFormat.addInputPath(job, new Path(otherArgs[i]));
    }//获取我们给定的参数中,输入文件所在路径

    FileOutputFormat.setOutputPath(job, new Path(otherArgs[otherArgs.length - 1])); //获取我们给定的参数中,输出文件所在路径
    System.exit(job.waitForCompletion(true)?0:1);//等待任务完成,任务完成之后退出程序
}

public static class IntSumReducer extends Reducer<Text, IntWritable, Text, IntWritable> {     //Reduce() 阶段
    private IntWritable result = new IntWritable();

    public IntSumReducer() {
    }

    public void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
        int sum = 0;

        IntWritable val;
        for(Iterator i$ = values.iterator(); i$.hasNext(); sum += val.get()) {
            val = (IntWritable)i$.next();
        }

        this.result.set(sum);
        context.write(key, this.result);
    }
}

public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable> {  //Map() 阶段阶段
    private static final IntWritable one = new IntWritable(1);
    private Text word = new Text();

    public TokenizerMapper() {
    }

    public void map(Object key, Text value, Mapper<Object, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException {
        StringTokenizer itr = new StringTokenizer(value.toString());

        while(itr.hasMoreTokens()) {
            this.word.set(itr.nextToken());
            context.write(this.word, one);
            }

        }
    }
}

关于源码部分,如果有不清楚的可以参考MapReduce WordCount 源码详细解析

五、结果

在这里插入图片描述

input文件夹就是我输入文件的路径,output文件夹则是输出的结果,都是保存在HDFS上面的,可以自行上传或下载。
在这里插入图片描述
在这里插入图片描述

这是我mapreduce执行的结果,太长了就只截了一点。

总结

通过本次使用eclipse编译运行Mapreduce,使我更加清楚的认识了MapReduce的体系结构和基本执行流程。其体系结构主要包括:Client、JobTracker、TaskTracker以及Task。Client就是用户,用户将程序提交给JobTracker,而JobTracker转手发给Task Scheduler,由Task Scheduler来完成任务分工,再将任务分工发给JobTracker,JobTracker通过“心跳”将任务发送给TaskTracker,由它来执行操作。MapTask负责将数据变成<key,value>的形式,然后将完成的数据发送给JobTracker,JobTracker将分配新的任务给Map Task并将它完成的数据交给Reduce Task统计,TaskTracker 会周期性地通过“心跳”将本节点上资源的使用情况和任务的运行进度汇报给JobTracker。



本次实验是参照[厦门大学数据库实验室完成的](http://dblab.xmu.edu.cn/blog/285/)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值