hadoop集群搭建与测试编码

说明

本文介绍hadoop小集群的搭建.

准备

十台装有linux的计算机.
这些计算机都装有jdk, 并且准确配置jdk.
这些计算机都装了ssh, 并且都能实现相互之间无密码访问.

配置

记录各台计算机的ip, 并将其中的一台作为master机, 其他计算机一次标号为slave1, slave2, slave3…slave9.
将ip对应标号的信息添加到/etc/hosts文件中, 格式为:

ip1     master
ip2     slave1
ip3     slave2
......
ip10    slave9

同时分别修改各台计算机对应的hostname, 使其对应hosts文件中的标号.

接着是配置hadoop了, hadoop的配置文件分为四个文件, 分别是core-site.xml, hdfs-site.xml, mapred-site.xml, yarn-site.xml.
这三个文件分别对应核心配置, hdfs配置, mapreduce配置和yarn配置.

接着介绍一下需要配置的属性:

1. fs.default.name

hdfs默认的服务器地址和端口.
位置在core-site.xml.
代码:

<property>
    <name>fs.default.name</name>
    <value>hdfs://master:9000</value>
</property>

2. hadoop.tmp.dir

hadoop的临时目录存放位置. 这个属性必须设置, 不然hadoop会在/tmp/目录下创建一个目录作为临时目录, 但是当系统重启之后, /tmp/目录就会被清除, 从而启动hadoop时需要重新格式化文件系统.
同时, 要赋予启动hadoop的用户对设置目录的读写权限.
位置在core-site.xml.
代码:

<property>
   <name>hadoop.tmp.dir</name>
   <value>/opt/hadoop/tmp</value>
</property>

3. dfs.replication

文件块存储的份数, 冗余存储, 提高系统的稳定性.
位置在hdfs-site.xml
代码:

<property>
   <name>dfs.replication</name>
   <value>2</value>
</property>

4. dfs.datanode.balance.bandwidthPerSec

平衡器同步时使用的带宽, 这个值设置的高了会占用带宽影响运行效率.
位置在hdfs-site.xml
代码:

<property>
    <name>dfs.datanode.balance.bandwidthPerSec</name>
   <value>10485760</value>
</property>

5. mapreduce.framework.name

设置哪种mapreduce框架, 分为local, classic和yarn.
位置在mapred-site.xml
代码:

<property>
   <name>mapreduce.framework.name</name>
   <value>yarn</value>
</property>

6. mapreduce.jobtracker.address

jobtracker的位置, 一般设置master机的位置. ip加端口号. 不需要协议
位置在mapred-site.xml
代码:

<property>
   <name>mapreduce.jobtracker.address</name>
   <value>master:9001</value>
</property>

7. mapreduce.job.maps

制定mapper的数量
位置在mapred-site.xml
代码:

<property>
   <name>mapreduce.job.maps</name>
   <value>2</value>
</property>

8. mapreduce.job.reduces

制定reducer的数量
位置在mapred-site.xml
代码:

<property>
   <name>mapreduce.job.reduces</name>
   <value>1</value>
</property>

9. mapreduce.tasktracker.map.tasks.maximum

制定mapper的最大数量
位置在mapred-site.xml
代码:

<property>
   <name>mapreduce.tasktracker.map.tasks.maximum</name>
   <value>4</value>
</property>

10. mapreduce.tasktracker.reduce.tasks.maximum

制定reducer的最大数量
位置在mapred-site.xml
代码:

<property>
   <name>mapreduce.tasktracker.reduce.tasks.maximum</name>
   <value>2</value>
</property>

11. mapreduce.reduce.shuffle.memory.limit.percent

设置shuffle阶段内存的大小. shuffle有两种方式, 一种是在磁盘上的, 另一种是在内从中进行.当单个文件的大小大于设置的阖值时, 将在磁盘进行操作.
如果小于, 就在内存中操作. 当单个文件小于这个阖值, 而文件数又很多时, 会造成内存不够用的情况, 从而导致程序崩溃现象. 解决方案, 将这个设置设置的很小,
始终在磁盘上进行.
位置在mapred-site.xml
代码:

<property>
    <name>mapreduce.reduce.shuffle.memory.limit.percent</name>
    <value>0.001</value>
</property>

12. mapreduce.output.fileoutputformat.compress

设置输出文件是否进行压缩. 文件压缩可以减小磁盘的使用率, 当作为中间产物进行传输时, 也节省了带宽.
hadopp支持集中压缩方式, 主要是Bzip2和Gzip. Bzip2压缩文件可以被分块, 即可以由多个map进行操作, 而且这种算法压缩效率较高, 但是这种算法压缩速度较慢.
对于Gzip, 这种算法在压缩速度和压缩效率上都不错, 但是这种压缩算法压缩后的文件不支持分块, 即只能由一个map进行操作.这种方案严重影响实际效率.
对于reduce个数较少可以将中间产物设置成Gzip, 而将最终结果设置成BZip2. 即提升了传输效率, 又有利于二次利用.
位置在mapred-site.xml
代码:

<property>
    <name>mapreduce.output.fileoutputformat.compress</name>
    <value>true</value>
</property>

13. mapreduce.map.output.compress

设置map之后的产物是否进行压缩
位置在mapred-site.xml
代码:

<property>
    <name>mapreduce.map.output.compress</name>
    <value>true</value>
</property>

14. mapreduce.output.fileoutputformat.compress.codec

设置输出文件的压缩算法
位置在mapred-site.xml
代码:

<property>
    <name>mapreduce.output.fileoutputformat.compress.codec</name>
    <value>org.apache.hadoop.io.compress.BZip2Codec</value>
</property>

15. mapreduce.map.output.compress.codec

设置map阶段结果的压缩算法
位置在mapred-site.xml
代码:

<property>
    <name>mapreduce.map.output.compress.codec</name>
    <value>org.apache.hadoop.io.compress.GzipCodec</value>
</property>

将配置好的hadoop目录打包, 分别发送到各个奴隶机上, 解压,并防止在同一个目录, 同时设置, HADOOP_HOME.

测试

在master机上执行下面命令用于格式化文件系统:

hadoop namenode -format

格式化, 在master机的/opt/hadoop/目录下,执行下面的命令, 启动hadoop集群:

sbin/start-all.sh

可以使用jps命令检查一下是否正常运行, 在master机下执行jps命令, 显示的结果如下:

XXXXX NameNode
XXXXX Jps   
XXXXX SecondaryNameNode
XXXXX ResourceManager

在slave机上执行jps, 显示结果如下:

XXXXX NodeManager
XXXXX Jps
XXXXX DataNode

接着是创建用户目录:

hadoop fs -mkdir /user
hadoop fs -mkdir /user/phantom9999
hadoop fs -mkdir /user/phantom9999/logs
hadoop fs -mkdir /user/phantom9999/logs/input/
hadoop fs -mkdir /user/phantom9999/logs/output/

接着是把日志文件上传到hadoop集群中, 使用下面的命令:

hadoop fs -put ./nginx.log.bz2 /user/phantom9999/logs/input/

接着是运行程序了, 将写好的程序上传到集群上, 使用下面的命令进行运行:

hadoop jar countIP.jar input countIP

编码

下面讲述一下上面运行的代码.
这个代码统计了一下nginx日志文件中, 各个IP出现的次数, 并根据出现的次数进行排序.
其中排序操作是在map阶段, 将ip出现的次数作为键名, 将ip作为键值. 在reduce阶段,
交换两者的位置.

具体代码如下:

package com.company;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
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.jobcontrol.JobControl;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Main {

    public static class DoMapper extends Mapper<Object, Text, Text, IntWritable> {

        public static int ipLength = "255.255.255.255,".length();

        public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
            String line = value.toString();
            String[] fields = line.split("\t");
            context.write(new Text(fields[1]), new IntWritable(1));
        }
    }

    public static class DoReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
        public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
            int sum = 0;
            for (IntWritable item: values) {
                sum += item.get();
            }

            context.write(key, new IntWritable(sum));
        }
    }

    public static class SortMapper extends Mapper<Object, Text, IntWritable, Text> {

        public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
            String line = value.toString();
            String[] fields = line.split("\t");
            if (fields.length == 2) {
                context.write(new IntWritable(Integer.parseInt(fields[1])), new Text(fields[0]));
            }

        }
    }

    public static class SortReducer extends Reducer<IntWritable, Text, Text, IntWritable> {

        public void reduce(IntWritable key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
            for (Text item: values) {
                context.write(item, key);
            }
        }
    }




    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        Configuration conf = new Configuration();
        String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
        if (otherArgs.length < 2) {
            System.out.println("参数不够");
            System.exit(0);
        }

        SimpleDateFormat df = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
        String tmpDirPath = df.format(new Date());
        //tmpDirPath = "2015_09_20_21_31_46";
        Path inputPath = new Path("/user/phantom/logs/" + otherArgs[0]);
        Path outputPath = new Path("/user/phantom/logs/output/" + otherArgs[1]);
        Path middlePath = new Path("/user/phantom/logs/output/" + tmpDirPath);



        Job job = Job.getInstance(conf, "log");
        job.setJarByClass(Main.class);
        job.setMapperClass(DoMapper.class);
        job.setCombinerClass(DoReducer.class);
        job.setReducerClass(DoReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        FileInputFormat.addInputPath(job, inputPath);
        FileOutputFormat.setOutputPath(job, middlePath);
        job.waitForCompletion(true);

        Configuration conf2 = new Configuration();
        Job sortJob = Job.getInstance(conf2, "sort");
        sortJob.setJarByClass(Main.class);
        sortJob.setMapperClass(SortMapper.class);
        sortJob.setReducerClass(SortReducer.class);


        sortJob.setMapOutputKeyClass(IntWritable.class);
        sortJob.setMapOutputValueClass(Text.class);
        sortJob.setOutputKeyClass(Text.class);
        sortJob.setOutputValueClass(IntWritable.class);

        FileInputFormat.addInputPath(sortJob, middlePath);
        FileOutputFormat.setOutputPath(sortJob, outputPath);


        boolean result = sortJob.waitForCompletion(true);

        FileSystem fs = FileSystem.get(conf2);
        fs.deleteOnExit(middlePath);

        System.exit(result ? 0 : 1);
    }
}

你可能感兴趣的:(hadoop,HADOOP集群)