MapReduce理论及实战总结

MapReduce理论


什么是MapReduce?

  • MapReduce是Google提出的 分布式并行编程模型 ,概念"Map"和"Reduce"是该模型的主要思想。它极大地方便了编程人员在不会分布式并行编程的情况下,将自己的程序运行在分布式系统上。 而Hadoop中的MapReduce是它的开源实现框架,且使用门槛相对较低。
  • Hadoop MapReduce是一个易于编写应用程序的软件框架,它以可靠、容错的方式在大型硬件集群(数千个节点)上并行处理大量数据(TB级更高等级数据集)。

为什么需要MapReduce

  • 传统并行计算框架容错性差,且使用成本高、难度高。
  • MapReduce由于是非共享内存/存储,容错性好,使用成本低、难度低。
  • (假装有第三条,不要管是否过时,X86架构发展到今天,咱们不还是得学习8086。)

MapReduce不擅长做什么

  • 实时计算,不能在极短时间内(毫秒、秒级)得到运算结果
  • 流式计算,MapReduce的输入数据是静态的
  • 有向图计算,MapReduce作业造成大量磁盘读写

MapReduce核心思想

  • MapReduce将复杂的、运行于大规模集群上的并行计算过程高度地抽象到了两个函数:Map和Reduce
  • MapReduce采用“分而治之”策略,一个存储在分布式文件系统中的大规模数据集,会被切分成许多独立的分片(split),这些分片可以被多个Map任务并行处理
  • MapReduce设计的一个理念就是“计算向数据靠拢”,而不是“数据向计算靠拢”,因为,移动数据需要大量的网络传输开销
  • MapReduce框架采用了Master/Slave架构,包括一个Master和若干个Slave。Master上运行JobTracker,Slave上运行TaskTracker架是用Java实现的,但是,MapReduce应用程序则不一定要用Java来写。
  • Map和Reduce阶段的任务各自并行运行,但是Reduce阶段的输入来自于Map阶段的输出
  • MapReduce编程模型只能包含一个Map、Reduce阶段,如果需要计算复杂分步的数据则需要使用多个MapReduce程序串行运行(这张图片来自Google MapReduce出版论文 传送门 )
  • JobTracker和TaskTracker被ResourceManager/ApplicationMaster和NodeManager替代,详细信息可参考这两篇文章:
    传送门1(英文)    传送门1(中文)

Hadoop框架中的序列化数据类型

想要把数据和对象存储到磁盘或者在网络上传输必须要用到序列化,而Java中的序列化会附带大量的额外信息不便于用作数据传输与进程间通信,所以Hadoop自行实现了结构紧凑、操作快速、可扩展且利于数据传输的序列化方案。Hadoop已经对一些基本类型做了封装,如下表

Java类型 Hadoop Writable类型
boolean BooleanWritable
byte ByteWritable
int IntWritable
float FloatWritable
long LongWritable
double DoubleWritable
String Text
map MapWritable
array ArrayWritable
null NullWritable

而我们想将自定义的对象也实现序列化功能只需要实现Writable接口并实现其方法即可

查看练习代码
非常简单的MapReduce实现,其中有几个细节需要注意:

  • Reduce方法的输入数据类型需要是Map方法的输出数据类型
  • 自定义类的序列化实现写出是什么顺序,读取也要按相应顺序
  • 自定义类的序列化需要在驱动类中指定Map方法输出数据类型类,因为 泛型限制只在编译阶段生效
  • 自定义类必须要有空构造方法,在添加了有参构造后不能忘了添加空构造,因为序列化创建会反射其空构造
     

MapReduce进程及并行机制

在上面的运行截图中可以找到两个特殊的关键字:MapTask和ReduceTask,一个完整的MapReduce程序在分布式运行时有三类进程:

  • MrAppMaster:Map-Reduce Application Master。

    • 负责整个程序的过程调度及状态协调
    • 负责资源调度、任务调度
    • 参考博客:YARN/MRv2 MRAppMaster深入剖析—整体架构
  • MapTask:负责Map阶段的数据处理,每个MapTask负责一个切片,输入通过InputFormat获得指定格式的数据(默认为TextInputFormat)
  • ReduceTask:负责Reduce阶段的数据处理,ReduceTask的数目可以手动设定避免数据倾斜

数据输入切片

和数据块(block)真实切分文件不同,数据切片(split)只是逻辑切分,告诉MapTask该读取数据的起始与结尾。
  为什么需要数据切片呢?如果Map阶段需要处理的文件过大,如10G的文本数据,还只用一个MapTask效率可想而知。此时可以将该文件切片,启动多个MapTask同时运行。但也要注意并不是切片多效率就高,如果10K的数据还切分多个切片那就是毫无意义的行为了。

  • 默认情况下,切片大小=blockSize
  • 每一个切片都会分配一个MapTask并行处理,即MapTask的数量及并行度由Job提交的切片数决定
  • 默认切片时不考虑总体数据大小,对每个文件进行切片,例:如果有一个150M的文件和10K的文件,则默认150M文件被切分成两片,10K单独一片。
  • 文件切片类FileInputFormat继承于InputFormat,可以看到其他形式数据源的切片类,顺便追踪其源码 山水的笔记:InputFormat源码追踪 :
  • 接下来介绍一下几个FileInputFormat的子类,因为是常用的:

    • TextInputFormat :默认使用它,在文件中按行读取每条记录,记录下的key为行偏移量,value为该行内容,但不管多小的文件都会形成一个切片提交给MapTask,所以在有大量小文件需要处理的时候尽量避免使用。
    • CombineTextInputFormat :可以将多个小文件按大小整合到一个切片中,这样就弥补了TextInputFormat的不足,如设置切片大小为1M,则大小总量在1M以下的小文件将被整合到一个切片。按需求及场景合理的设置切片大小即可。
    • KeyValueTextInputFormat :每行的信息都作为记录,记录的键值对是被设置的分隔符分开的字符串,默认的分隔符是制表符"\t"
    • NLineInputFormat :可以指定一个具体的行数作为切片条件,此时切片不再根据block或单个文件划分。
    • FixedLengthInputFormat :读取固定长度记录的输入文件,输入的数据不一定需要文本,可以是任何二进制数据。
    • SequenceFileInputFormat :读取序列化的对,与SequenceFileOutputFormat相对应,但是要注意相对于其他InputFormat,SequenceFileInputFormat不仅要指定文件输入格式,还要确保键值对的类型和Map端输入类型一致。

数据输出

  • 与InputFormat相对应的当然是OutputFormat,可以看到默认的依旧是纯文本形式的TextOutputFormat,与TextInputFormat对应。

Input/Output Format练习代码

Shuffle过程

此处参考文章:Shuffle过程介绍
Map方法之后,Reduce方法之前的数据经历的处理过程称之为Shuffle,Shuffle更像是洗牌的逆过程,把一组无规则的数据尽量转换成一组具有一定规则的数据。Shuffle横跨Map端和Reduce端,在Map端包括Spill过程,在Reduce端包括copy和sort过程.下图为参考各种资料和我个人的一些理解结合画出的Shuffle流程图。如有不同见解希望不吝赐教。

简单概括一下Shuffle中的操作:

  • 输出:每个Map任务不断地以键值对的形式把数据输出到在内存中构造的一个环形数据结构中。这里面不光放置了数据,还放置了一些索引数据。
  • 分区:对数据进行分组并标记其分区编号Partition
  • 排序:利用快速排序算法对缓存区内的数据进行排序,把Kvbuffer中的数据按照partition值和key两个关键字升序排序,移动的只是索引数据,排序结果是Kvmeta中数据按照partition为单位聚集在一起,同一partition内的按照key有序。
  • 溢写:Spill线程为这次Spill过程创建一个磁盘文件,根据排过序的Kvmeta中partition的把数据写入到这个文件中,一个partition对应的数据写入完之后继续写下个partition,直到把所有的partition遍历完。一个partition在文件中对应的数据也叫段(segment)。
  • 合并:Map任务如果输出数据量很大,可能会进行好几次Spill,out文件和Index文件会产生很多,分布在不同的磁盘上。最后把这些文件进行合并的过程称为merge。
  • 复制:这个步骤已经是属于Reduce端的操作,由于集群中的数据分散在各个节点,Reduce任务通过HTTP向各个Map任务拉取它所需要的数据。每个节点都会启动一个常驻的HTTP server,其中一项服务就是响应Reduce拉取Map数据。当有MapOutput的HTTP请求过来的时候,HTTP server就读取相应的Map输出文件中对应这个Reduce部分的数据通过网络流输出给Reduce。
  • 归并排序:和Map端使用的Merge过程一样。Map的输出数据已经是有序的,Merge进行一次归并排序,所谓Reduce端的sort过程就是这个合并的过程。一般Reduce是一边copy一边sort,即copy和sort两个阶段是重叠而不是完全分开的。Reduce端的Shuffle过程至此结束

###################################### 未完 ###################################

你可能感兴趣的:(hadoop)