mapreduce原理--伪分布式hadoop的配置

几个重要的流程理解:
1.HDFS的读写流程

2.NameNode启动流程

3.YARN的架构

4.MapReduce的计算流程
输入—map()–shuffle–reduce()—输出

map()方法的输出:context.write(key, value) key:1
reduce()方法的输入:key {1,1,1}

shuffle两个阶段:
map()方法结束
第一阶段:map shuffle
第二阶段:reduce shuffle
reduce()方法执行

map阶段:
map的输出结果会直接写到本地磁盘(map方法运行的NodeManager上)

shuffle的流程

map side阶段:
1. map输出以后,并没有直接写入磁盘,而是使用了缓存,进行了一些预排序的过程,
这样可以使mapreduce更有效率
2. 每一个map方法都具有一个环形缓冲区(circular memory buffer),这里是先接受
map输出的地方。环形缓冲区大小默认100M,可以在mapreduce.task.io.sort.mb属性
中设置。当缓冲区达到80%的时候,就会溢写到磁盘。
3. partition阶段在写到磁盘之前,会首先被分区,而分区的数量和最终要发送到的
reducer的数量是一致的。
4. 在每一个分区中都进行了一次sort by key
5. 如果有一个combiner的函数,那么此时会将排序的输出作为输入,进行执行。
combiner实际是一个在map端执行的reducer
6. merge:在map task结束之前,所有的spills file会被合并成一个分过区的排过序
的文件在这里,一次合并的小文件的数量配置:mapreduce.task.io.sort.factor,
默认是10
7. compress压缩,设置mapreduce.map.output.compress=true

网络传输

reduce side
1. reduce会从不同的服务器上将对应分区的结果文件拷贝到本地
2. map端与ApplicationMaster保持一个心跳,当map端执行完成时,会通知
ApplicationMaster,reduce端会随时询问ApplicationMaster,一旦得知有map
执行完成,就会去下载输出文件
3. 被拷贝来的map输出文件如果是被压缩过的,那么在执行合并之前要进行解压缩。
4. sort阶段:When all the map outputs have been copied, the reduce task
moves into the sort phase
5. merge:merges the map outputs, maintaining their sort ordering
默认一次合并文件的数量是10,设置: mapreduce.task.io.sort.factor
6. 在合并之后会发送给reduce处理(排过序)

reduce处理:(key ,{1,1,1..})
处理的结果会直接发送到HDFS(流式写入)

注意:
map的数量和split的数量是一致的
split的数量和block的数量关系是可以配置的,默认情况下是1:1
默认情况下:一个block就是一个map
如果200M一个文件:会有2个map任务执行
如果有1一个文件是10M,另一个文件是100M:会有2个map任务执行
partition的数量和reducer的数量是一致的,默认reducer的数量是1
reducer的数量决定了partition的数量

实现Partition
根据provinceId除以3余数不同,来分成3个区

package com.ibeifeng.hadoop;

import java.io.IOException;

import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Partitioner;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class PVMapReduce {
public static void main(String[] args) throws Exception {
//1.get Job
Job job = Job.getInstance(new Configuration());

    //2.set Jar
    job.setJarByClass(PVMapReduce.class);

    //3.set Mapper
    job.setMapperClass(PVMapper.class);
    job.setMapOutputKeyClass(Text.class);
    job.setMapOutputValueClass(LongWritable.class);

    //3.5 set Partition
    job.setPartitionerClass(MyPartitioner.class);
    //set number of Reducer
    job.setNumReduceTasks(new Integer(args[2]));

    //4.set Reducer
    job.setReducerClass(PVReducer.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(LongWritable.class);

    //5.PathIn  PathOut
    FileInputFormat.setInputPaths(job, new Path(args[0]));
    FileOutputFormat.setOutputPath(job, new Path(args[1]));

    //6.submit
    job.waitForCompletion(true);
}

//map method
public static class PVMapper extends Mapper{
    Text text = new Text();
    LongWritable longWritable = new LongWritable(1);
    @Override
    protected void map(LongWritable key, Text value, Context context)
            throws IOException, InterruptedException {
        String line = value.toString();
        String[] split = line.split("\t");

        // length >= 30 is useful
        if (split.length < 30) {
            //counter defination
            context.getCounter("my error counter", "length is less than 30").increment(1);
            return;
        }

        // url is null is useless
        if ( StringUtils.isBlank(split[1])) {
            context.getCounter("my error counter", "url is null").increment(1);
            return;
        }

        // provinceId null is useless
        if (StringUtils.isBlank(split[23])) {
            context.getCounter("my error counter", "provinceId is null").increment(1);
            return;
        }

        // provinceId should be a number
        try {
            new Integer(split[23]);
        } catch (NumberFormatException e) {
            context.getCounter("my error counter", "provinceId is not a number").increment(1);
            e.printStackTrace();
            return ;
        }

        //text.set(provinceId)
        text.set(split[23]);
        context.write(text, longWritable);
    }
}

/*
 * 自定义分区
 * partition的输入是map的输出
 * numPatitions:传来的partition的数量
 */
public static class MyPartitioner extends Partitioner{

    /*
     * return的值就是partition
     * 在这里就分成了3个区
     */
    @Override
    public int getPartition(Text key, LongWritable value, int numPartitions) {
        Integer num = Integer.valueOf(key.toString());
        if (num % 3 == 0) {
            return 0;
        }else if (num % 3 == 1) {
            return 1;
        }
        return 2;
    }
}


public static class PVReducer extends Reducer{
    LongWritable value = new LongWritable();

    @Override
    protected void reduce(Text key, Iterable iterable,
            Context context)
            throws IOException, InterruptedException {
        long count = 0;
        for (LongWritable longWritable : iterable) {
            long l = longWritable.get();
            count += l;
        }
        value.set(count);
        //key:provinceId    value:number of provinceId
        context.write(key, value);
    }
}

}

执行:
$ ./hadoop jar /opt/data/pvcountpar.jar /nicole/input/2015082818 /nicole/outputpvcount_par1 1
此时:设置reducer的数量是1,那么partition的数量也就是1

$ ./hadoop jar /opt/data/pvcountpar.jar /nicole/input/2015082818 /nicole/outputpvcount_par3 3
此时:设置reducer的数量是3,那么partition的数量也就是3

$ ./hadoop jar /opt/data/pvcountpar.jar /nicole/input/2015082818 /nicole/outputpvcount_par4 4
此时:设置reducer的数量是4,那么partition的数量也就是4
然而part-r-00003文件中是空的

combiner函数
public static class MyCombiner extender Reducer<>{

}
main(){
    //设置可插拔的Combiner
    job.setCombinerClass(MyCombiner.class);
}

实际上Combiner就是在map shuffle阶段执行一次reducer

mapreduce参数调优
mapreduce.map.cpu.vcores
每个Map Task需要的虚拟CPU个数
mapreduce.reduce.cpu.vcores
每个Reduce Task需要的虚拟CPU个数
mapreduce.job.reduces:
默认值:1
说明:默认启动的reduce数。通过该参数可以手动修改reduce的个数。
mapreduce.task.io.sort.factor:
默认值:10
说明:Reduce Task中合并小文件时,一次合并的文件数据,
每次合并的时候选择最小的前10进行合并。
mapreduce.task.io.sort.mb:
默认值:100
说明: Map Task缓冲区所占内存大小。
mapreduce.reduce.shuffle.parallelcopies:
默认值:5
说明:reduce shuffle阶段并行传输数据的数量。集群大可以增大为10或更大。
mapreduce.map.output.compress:
默认值:false
说明: map输出是否进行压缩,如果压缩就会多耗cpu,但是减少传输时间,
如果不压缩,就需要较多的传输带宽。配合 mapreduce.map.output.compress.codec使用,默认是 org.apache.hadoop.io.compress.DefaultCodec,
可以根据需要设定数据压缩方式。
mapreduce.reduce.shuffle.merge.percent:
默认值: 0.66
说明:reduce归并接收map的输出数据可占用的内存配置百分比。

RPC远程过程调用
hadoop各进程之间的通信就是建立在RPC通信的基础上构建的。

http://blog.csdn.net/thomas0yang/article/details/41211259

========================================================================
分布式系统搭建
集群规划:构建3台服务器
PC1 PC2 PC3
HDFS NameNode SecondaryNameNode
DataNode DataNode DataNode
Yarn ResourceManager
NodeManager NodeManager NodeManager

第一步:准备3台服务器
创建3个虚拟机,建议大家直接安装,
或者克隆,或者直接拷贝文件
(这样的话需要修改MAC地址,以及部分配置文件)
vi /etc/sysconfig/network-scripts/ifcfg-eth0
vi /etc/udev/rules.d/70-persistent-net.rules

第二步:准备系统环境
1. 设置主机名(三台PC)
$ vi /etc/sysconfig/network
HOSTNAME=hadoop.ibeifeng.com.cn01

  1. 设置hosts文件(三台PC)
    192.168.230.101 101
    192.168.230.102 102
    192.168.230.103 103

    在 windows系统上也要配置hosts文件
    192.168.230.101 101
    192.168.230.102 102
    192.168.230.103 103

  2. 关闭防火墙
    /# service iptables stop
    /# chkconfig iptables off

  3. 关闭selinux
    /# vi /etc/sysconfig/selinux
    SELINUX=disabled
    /# reboot 重启电脑

  4. 配置静态IP和DNS [root用户] [三台服务器]
    /# vi /etc/sysconfig/network-scripts/ifcfg-eth0
    配置IP地址、DNS地址(网管地址)

  5. 创建普通用户(三台PC)
    /# useradd nicole
    /# passwd nicole 设置密码
    注意:三台PC要使用同一个用户

  6. 可选操作(修改启动级别)
    /# vi /etc/inittab
    id:5:initdefault: #代表重启进入图形化界面
    id:3:initdefault: #代表进入cli界面

  7. 卸载系统自带的JDK
    rpm -qa | grep java  #查询系统是否自带jdk rpm -e java(软件名) –nodeps #卸载

第三步:配置NTP时间服务器
1)配置第一台PC的时间服务器
2)让其他的PC来同步PC1的时间

在第一台PC上进行设置:
查看目前系统使用的时区
$ date -R
Sun, 16 Oct 2016 23:35:08 -0700
如果得到的结果不是+0800,那么就需要修改时区
删除目前系统使用的时区文件
# rm -f /etc/localtime 
创建软链接文件/etc/localtime指向/usr/share/zoneinfo/Asia/Shanghai
# ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# date -R       查看,此时时区已经是+0800
调整当前时间,与当前时间同步
# ntpdate cn.pool.ntp.org
    使用ntpdate命令之前可以检查此软件的安装情况
    # rpm -qa | grep ntp
        ntpdate-4.2.4p8-3.el6.centos.x86_64
        fontpackages-filesystem-1.41-1.1.el6.noarch
        ntp-4.2.4p8-3.el6.centos.x86_64
    如果没有安装这个软件,可以使用yum安装
    # yum -y install ntp

修改ntp的配置文件
# vi /etc/ntp.conf

修改1:去掉下面这行的#,将网段改为自己的网段:192.168.234.0
    restrict 192.168.234.0 mask 255.255.255.0 nomodify notrap

修改2:注释掉以下几行内容
    #server 0.centos.pool.ntp.org
    #server 1.centos.pool.ntp.org
    #server 2.centos.pool.ntp.org

修改3:去掉如下两行前的#,如没有需要 自己添加
    server  127.127.1.0     # local clock
    fudge   127.127.1.0 stratum 10  

启动NTP服务
# service ntpd start
在启动电脑的时候自动启动
# chkconfig ntpd on

到另外两台PC(PC2 PC3)关闭ntpd进程
# service ntpd stop
# chkconfig ntpd off

同步第一台PC的时间(PC2 PC3)
格式:ntpdate 开启ntp服务的主机名
# ntpdate hadoop.ibeifeng.com.cn01

设置计划任务,每十分钟同步一次时间(PC2 PC3)
# crontab -e
/10 * * * /usr/sbin/ntpdate hadoop101

第四步:SSH免密码登陆
在第一台主机上,生成公钥
ssh-keygen -t rsa

然后将公钥发送给其他主机
ssh-copy-id 其他主机名
    此时,在其他的主机的私钥中就保存了加密的主机的公钥

完成之后既可以ssh直接登陆其他主机了
ssh 其他主机名

PC1-----PC1  PC2   PC3  设置ssh
# ssh-keygen
# ssh-copy-id hadoop.ibeifeng.com.cn01
# ssh-copy-id hadoop.ibeifeng.com.cn02
# ssh-copy-id hadoop.ibeifeng.com.cn03
PC2-----PC1  PC2   PC3  设置ssh
# ssh-keygen
# ssh-copy-id hadoop.ibeifeng.com.cn01
# ssh-copy-id hadoop.ibeifeng.com.cn02
# ssh-copy-id hadoop.ibeifeng.com.cn03
PC3-----PC1  PC2   PC3  设置ssh
# ssh-keygen
# ssh-copy-id hadoop.ibeifeng.com.cn01
# ssh-copy-id hadoop.ibeifeng.com.cn02
# ssh-copy-id hadoop.ibeifeng.com.cn03

第五步:安装jdk
在第一台主机上安装jdk
使用scp命令将jdk发送到另外两台主机
scprjdk1.7.067/hadoop.ibeifeng.com.cn02:/opt/modules/ scp -r jdk1.7.0_67/ hadoop.ibeifeng.com.cn03:/opt/modules/

配置环境变量
vi /etc/profile
## JAVA HOME
JAVA_HOME=/opt/modules/jdk1.7.0_67
export PATH=$PATH:$JAVA_HOME/bin

# source /etc/profile

第六步:安装hadoop
1.在PC1上安装hadoop
tarzxvfhadoop2.5.0.tar.gzC/opt/modules/ rm -rf doc/

2.修改环境配置文件
hadoop-env.sh  yarn-env.sh  mapred-env.sh
export JAVA_HOME=/opt/modules/jdk1.7.0_67

3.修改配置文件
core-site.xml


    fs.defaultFS
    hdfs://hadoop.ibeifeng.com.cn01:8020



    hadoop.tmp.dir
    /opt/modules/hadoop-2.5.0/tmp
 

hdfs-site.xml
    

    dfs.replication
    3



    dfs.namenode.secondary.http-address
    hadoop.ibeifeng.com.cn03:50090



    dfs.namenode.http-address
    hadoop.ibeifeng.com.cn01:50070



    dfs.permissions.enabled
    false



mapred-site.xml


    mapreduce.framework.name
    yarn
 


    mapreduce.jobhistory.address
    hadoop.ibeifeng.com.cn01:10020



    mapreduce.jobhistory.webapp.address
    hadoop.ibeifeng.com.cn01:19888



yarn-site.xml


    yarn.resourcemanager.hostname
    hadoop.ibeifeng.com.cn02



    yarn.nodemanager.aux-services
    mapreduce_shuffle




    yarn.log-aggregation-enable
    true




    yarn.log-aggregation.retain-seconds
    86400



slaves
hadoop.ibeifeng.com.cn01
hadoop.ibeifeng.com.cn02
hadoop.ibeifeng.com.cn03

4.将hadoop文件夹发给另外两台主机
$ scp -r hadoop-2.5.0/ 192.168.234.102:/opt/modules/
$ scp -r hadoop-2.5.0/ 192.168.234.103:/opt/modules/

5.格式化
在第一台主机上格式化namenode
$ ./hdfs namenode -format

6.启动hdfs
在第一台主机上启动hdfs
$ ./start-dfs.sh
在第二台主机上启动yarn
$ ./start-yarn.sh

jps

PC1:
3150 NameNode
3237 DataNode
3693 Jps
3591 NodeManager
3487 JobHistoryServer

PC2:
5070 Jps
4828 DataNode
4949 ResourceManager
5040 NodeManager

PC3:
4856 SecondaryNameNode
5086 Jps
4983 NodeManager
4804 DataNode

web页面查看
hdfs:http://hadoop.ibeifeng.com.cn01:50070/
yarn:http://hadoop.ibeifeng.com.cn02:8088/cluster

你可能感兴趣的:(大数据,mapreduce,hadoop,分布式,架构,伪分布式)