Hadoop分布式下的MapReduce流程及HDFS简单使用

        上一篇文章我们已经进行了伪分布式配置,也通过几个例子,看到了如何在伪分布式下进行MapReduce操作。今天的文章主要看看在分布式下的MapReduce是如何工作的,然后通过一个小例子,看看Java操作HDFS的方式。

上图是分布式下MapReduce的执行流程,可以看到除了map和reduce之外,还有很多的步骤,这些步骤,我们或多或少的都可以通过配置或者编码的方式对其进行控制,这也是我们对MapReduce进行性能调优的手段。


  1. 输入文件被上传到HDFS之后,会被分片,默认Hadoop集群会保存每个分片的三个副本(伪分布式下我们设置为只有一个副本),如果按照上图来看,在HDFS中会分别有3个spilt1,3个spilt2和3个spilt3。这是为了通过数据冗余保证数据存储的可靠性,当数据出现问题是,可进行恢复。分片的大小默认为HDSF文件块的大小(128M),这样可以有更好的性能。


  2. Hadoop会为每一个spilt分配一个map任务,也就是说,spilt的数目决定了map任务的数目。分配过程遵循一定的原则,首先,如果保存spilt数据的节点处于空闲状态,那么就在这个节点上执行map任务;但是,如果数据存储的节点正在执行其他的任务,那么Hadoop会找数据节点同一个机架中距离最近的空闲节点执行map任务;最后,如果上面的情况都无法满足,就只好跨机架执行map任务了。总的目的就是为了尽可能减少数据的传输,优化性能。


  3. 这样,map任务就分别在各自的节点中并发运行了,这时会对map任务的输出进行排序。这里就需要注意了,由于文件分片只有文件的一部分数据,map处理后的排序是分别针对各自的处理结果进行的,也就是说,这里排序后的结果是部分排序,并不是对输入文件所有数据的排序。


    如果需要对整个文件排序,也是有方法的,一种是阻止Hadoop对文件进行分片,还有一种方式是将分片后的文件聚合后,交给一个map任务处理。


  4. 为了优化性能,map之后的结果是在内存中进行排序的,这时候没有必要将结果写入到磁盘上,但是,reduce需要从磁盘上获取数据,数据写入磁盘的操作被推后到merge阶段,各个map任务处理后的结果,被复制到reduce任务所在的节点,在merge阶段写入磁盘,进而reduce运行,输出结果。reduce任务的数量可以配置,默认为1,如果有多个reduce任务,会在各自的节点上生成结果的分区。


以上就是MapReduce在分布式情况下的运行过程,我们再来看看如何操作HDFS,上一篇文章中,我们使用命令行操作了HDFS,今天看看如何用Java代码实现。我们使用一个简单的例子,将一个字符串写入到HDFS,然后再读取出来显示到终端。

package com.yjp.hdfs;

import java.net.URI;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;

public class HDFSEcho {
	
	// yjp替换为你的用户名
	private static final URI TMP_URI = 
			URI.create("hdfs://localhost/user/yjp/temp");

	public static void main(String[] args) throws Exception {
		if (args.length != 1) {
			System.out.println("Usage: HDFSEcho string");
			System.exit(1);
		}
		
		String echoString = args[0] + "\n";
		
		// 通过URI创建FileSystem,由于是hdfs,会返回代表HDFS的实例
		Configuration conf = new Configuration();
		FileSystem fs = FileSystem.get(TMP_URI, conf);
		FSDataOutputStream out = null;
		FSDataInputStream in = null;
		
		try {
			// 写入文件
			Path path = new Path(TMP_URI);
			out = fs.create(path);
			out.writeUTF(echoString);
			IOUtils.closeStream(out);
			
			//从文件读取并输出
			in = fs.open(path);
			IOUtils.copyBytes(in, System.out, conf);
			IOUtils.closeStream(in);
			
			//删除文件
			fs.delete(path, true);
		} finally {
			IOUtils.closeStream(out);
			IOUtils.closeStream(in);
		}
	}
	
}
打包为jar文件,记得启动hadoop的后台进程,然后运行试试。

hadoop jar 你的包名.HDFSEcho "Hello HDFS!"


输出为

Hello HDFS!


这部分代码在hdfs包中。


猜你喜欢

转载自blog.csdn.net/yjp19871013/article/details/78693588
今日推荐