Hadoop总结--第一部分

HDFS中的RPC

所有的HDFS通讯协议都是建立在TCP/IP协议之上。客户端通过一个可配置的TCP端口连接到Namenode,通过ClientProtocol协议与Namenode交互。而Datanode使用DatanodeProtocol协议与Namenode交互。一个远程过程调用(RPC)模型被抽象出来封装ClientProtocol和Datanodeprotocol协议。在设计上,Namenode不会主动发起RPC,而是响应来自客户端或 Datanode 的RPC请求。

ACK

确认字符,表示发来的数据已确认接收无误。在TCP/IP协议中,如果接收方成功的接收到数据,那么会回复一个ACK数据。

HDFS写入数据流程:

客户端使用DistributedFileSystem对象调用creat()

在这里插入图片描述

来新建文件,DistributedFileSystem对NN创建一个RPC调用,在文件系统的命名空间中新建一个文件,NN执行检查确定文件不存在且客户端有新建该文件的权限。如果这些检查均通过,NN就会为创建新文件记录一条记录,否则抛出IOException异常。

DFS向客户端返回一个FSDataOutputStream对象,由此客户端可以开始写入数据,FSDataOutputStream封装了一个DFSOutputStream对象,该对象负责DN和NN之间的通信。客户端写入数据时,DFSOutputStream将其分为64K的数据包(内含516Bchunk),并写入内部队列,称为数据队列。DataStreamer负责处理数据队列,它负责挑选合适的DN节点(节点数量在create()时就已经给出了,并据此要求NN分配新数据块,这组DN组成一条管线(假设副本数量为3),DataStreamer将数据包流式传输到管线中第一个DN,该DN将其存储并发送到第二个DN,第二个DN中同理,直至三个DN都有数据包为止。

DFSOutputStream也维护着一个内部数据包队列来等待DN的收到确认回执,称为确认队列(“ACK queue”)收到管道中所有DN的确认信息后,该数据包才会从确认队列删除。

HDFS读取流程:

客户端通过调用FileSystem对象(DistributedFileSystem的实例)的open()方法来打开希望读取的文件,DFS通过使用RPC来调用NN以确定文件的起始位置,此外,这些DN根据它们与客户端的距离来排序,如果客户端本身就是一个DN,那么客户端将会从保存有对应数据块的本地DN读取数据。DFS类返回一个FSDataInputStream对象给客户端便于读取数据,FSDataInputStream类封装DFSInputStream对象,DFSIS管理DN和NN的IO,看情况决定返回一部分DN列表还是全部DN。

接着客户端对这个输入流调用read()方法,同时连接多个DN获取数据,在获取数据后写入客户端缓存内然后串行落盘,也就是并行读取数据后串行落盘。这批数据块读完后,如果有下一批,重复上述操作。

HDFS维护元数据:

NN启动:第一次启动NN格式化后,创建FSImage和Edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。(这也就是为什么HDFS启动时会先进入安全模式),客户端对元数据有改动,NN将其记录到Edits文件中,在内存中对元数据进行修改。

2NN启动:每隔一段时间去查看NN的Edits文件,每间隔一小时或者一百万条数据就把NN的编辑日志和镜像文件抓取过来进行合并,获得FSImagn.chkpoint文件,同时本地也留存一份(这就是所谓检查点机制),然后将检查点文件传送给NN,NN在执行任务间隔期间将其替换为FSImage。

DN和NN交互:

DN启动后向NN注册,发送自己节点中存储的数据块信息,且每间隔3s给NN发送一次心跳,每间隔六小时向NN汇报节点数据块信息。NN每间隔3s接收来自DN的心跳,若是10分钟30秒没有接收到某个DN的心跳,那么就判定此DN死亡。

MR全流程:

从InputFormat开始,首先需要认识到的是任务切片数量等于MapTask的数量,

切片时需要注意的是:文件夹默认不切且报错,修改配置文件后虽然还是不切文件夹,但是不报错。压缩文件有的能切有的不能切(通常使用的BZip2或者LZO都是可切的,超过128MB的大文件用BZip2或者LZO,小文件用Snappy也是可以的)。切片大小可以调整,要往大调整使用minsize,往小调整使用maxsize。如果切片之后数据块在设定的BlockSize*110%的范围内,那么单独一片既可。

若输入的小文件偏多,那么就使用CombineTextInputFormat,先进行虚拟分块,再切片,

虚拟分块需要注意的是:小于指定的块大小的文件不需要再分块,大于指定块大小但是小于2倍块大小的文件,均分成两块,大于2倍块大小的,先按块大小切一块然后再判断。

切片时要注意的是,小文件与下一个小文件合并直到达到给定的块大小。接下来进入

Read阶段:

MapTask通过InputFormat获得的RecordReder,从输入InputSplit中解析出KV键值对。

Map阶段:

将解析出的KV键值对交给用户编写map()函数处理,并产生新的KV键值对。执行结束后进入

Shuffle阶段:

Collect阶段:

数据处理完成后调用OutputCollector.collect()输出结果,在函数内部,它将会调用Partitioner生成的KV分区写入一个环形缓冲区中。

Spill阶段:

当写入的数据达到环形缓冲区80%后锁定缓冲区然后反向写入,其中的80%的部分在缓冲区中按照分区进行排序,也就是保证不同分区内按照key有序。然后将分区数据的元信息写到内容索引数据结构SpillRecord中,其中每个分区的信息包括在临时文件中的偏移量,压缩前后数据大小,若当前内存索引大小超过1MB,则将内存索引写到文件output/spillN.out.index中。

Merge阶段:

当所有数据处理完后,MapTask对所有临时文件进行一次合并确保只会生成一个数据文件,进行Merge,也就是归并排序,使得数据文件成为一个包含各个分区但是分区内有序的文件。在即将落盘前,根据需求进行Combine(效率是否高,排序后是否会对业务结果产生影响),压缩(LZO或者Snappy,这里选择压缩方式的要求是压缩解压缩速度快),然后落盘。

接下来就要执行

Copy阶段:

ReduceTask从各个MapTask上远程拷贝一片数据,并针对某一片数据,若其大小超过一定阈值,则写到磁盘上,否则直接放入内存中。

Sort阶段:

在远程拷贝数据的同时,ReduceTask启动了后台线程对内存和磁盘上的文件进行合并,防止内存使用过多或者磁盘文件过多,ReduceTask只需要对所有数据进行一次归并排序既可。然后根据键进行排序,一组相同的key对应的values调用一次reduce方法。

Reduce阶段:

reduce()函数将计算结果写到HDFS上。

OutputFormat:

自定义输出数据格式,默认是TextOutputFormat,在之后调用RecordWriter写到HDFS上。

注意: Shuffle中的缓冲区大小会影响到MapReduce程序的执行效率,原则上说,缓冲区越大,磁盘io的次数越少,执行速度就越快。

ReduceJoin:

Map端的主要工作:为来自不同表或文件的KV键值对打标签,区别不同来源的记录,然后用链接字段作为key进行连结,最后输出。

Reduce端的主要工作:在Reduce端以连接字段为key的分组已经完成,只需要根据文件记录分开,再合并既可。

ReduceJoin比较通用,对表的大小没有太多的限制。

MapJoin:

适用于一张大表和一张小表,将小表存入Cache中,和大表进行合并既可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学无止境_--_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值