nn dn 2nn组成
NameNode(nn):只能有一个目录
DataNode(dn):存储多个文件数据的
2nn:是nn的助手,但不是nn的热备份
nn和2nn的区别:nn里的Edits文件写满时变成可读文件再新建新的Edits文件,而2nn不能新建新的Edits文件
由客户端通过FileSystem向NameNode询问A文件,然后NameNode开始查询元数据找到A文件在B的DataNode地址里,挑选一台(就近的,然后随机)的服务器,进行读取数据,然后DataNode开始传输数据给客户端,客户端先在本地缓存然后再写入目标文件。,
1)客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。
2)NameNode返回是否可以上传。
3)客户端请求第一个 Block上传到哪几个DataNode服务器上。
4)NameNode返回3个DataNode节点,分别为dn1、dn2、dn3。
5)客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。
6)dn1、dn2、dn3逐级应答客户端。
7)客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答。
8)当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行3-7步)。
NameNode和SecondaryNameNode工作机制
第一阶段启动NameNode
Editis:编辑日志,
Fsimage:镜像文件缓存
第一次会在NameNode里加载eidits和fismage,然后从客户端传入元数据的增删改查请求进入NameNode放入editis中,然后fismage每隔一段时间会备份editis中的数据
第二阶段启动SecondaryNameNode
CheckPoint:询问是否需要把editis中的日志保存到Fisamge中
CheckPoint发送条件:1.定时时间到 2.Editis中数据满了
启动时每隔一段时间会向NameNode发送CheckPoint命令是否需要,如果满足两个条件其中一个就要执行CheckPoint命令,然后editis1会变成可读文件再生产新的editis2编辑日志方便下次客户端执行元数据放入editis2中,这时候的editis1可读文件和fismage一同发送到SecondaryNameNode中,先把fsimage放入到内存再放editis1,生成新的Fsimage(fsimage_chkpoint),再把fsimage_chkpoint发送到NameNode中。
Nn和2nn的区别:NameNode和SecondaryNameNode区别就是在2nn中不会产生新的editis,所以不能代替nn。
NameNode如何知道有多少个DataNode是取决于DataNode启动时向NameNode申请注册,在NameNode中注册成功之后会返还给DataNode一个注册成功的信号,以后DataNode会每周期(1小时)上报所有块信息(第一次上报会在安全模式中)。
NameNode会向DataNode心跳3秒一次来判断DataNode是否挂掉,DataNode在3秒内会返回信号给NameNode,如果超过三秒没返回信号,则NameNode会等待10分钟+30秒,在这期间如果DataNode返回信号证明还存活也称超时时长,如果没信号,NameNode认定该DataNode死亡。
1)一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
2)DataNode启动后向NameNode注册,通过后,周期性(1小时)的向NameNode上报所有的块信息。
3)心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用。
4)集群运行中可以安全加入和退出一些机器。
最大的特点就是简单
就是慢
第一个阶段:
输入数据时候进行切分,把每个切分的数据分别映射到对应的Map
中,在Map中产生对应的kv值
第二个阶段:
把对应的kv值归约到Reduce中,输出结果。
用户编写的程序分成三个部分:Mapper、Reducer和Driver。
序列化:把内存中的活的二进制对象编码转换成二进制序列
反序列化(能干的事情):1.可以往磁盘上写(持久化)
2.可以通过网络发送(网络传输)
Java类型 |
Hadoop Writable类型 |
Boolean |
BooleanWritable |
Byte |
ByteWritable |
Int |
IntWritable |
Float |
FloatWritable |
Long |
LongWritable |
Double |
DoubleWritable |
String |
Text |
Map |
MapWritable |
Array |
ArrayWritable |
Java的序列化是一个重量级序列化框架,yigeduix1被序列化之后会附带很多额外的信息(各种校验信息,Header,继承体系等),不便于网络中高效传输,所以Hadoop自己开发了一套序列化机制。
Hadoop序列化特点:
具体实现bean对象序列化步骤如下7步。
(1)必须实现Writable接口
(2)反序列化时,需要反射调用空参构造函数,所以必须有空参构造
public FlowBean() { super(); } |
(3)重写序列化方法
@Override public void write(DataOutput out) throws IOException { out.writeLong(upFlow); out.writeLong(downFlow); out.writeLong(sumFlow); } |
(4)重写反序列化方法
@Override public void readFields(DataInput in) throws IOException { upFlow = in.readLong(); downFlow = in.readLong(); sumFlow = in.readLong(); } |
(5)注意反序列化的顺序和序列化的顺序完全一致
(6)要想把结果显示在文件中,需要重写toString(),可用”\t”分开,方便后续用。
(7)如果需要将自定义的bean放在key中传输,则还需要实现Comparable接口,因为MapReduce框中的Shuffle过程要求对key必须能排序。详见后面排序案例。
@Override public int compareTo(FlowBean o) { // 倒序排列,从大到小 return this.sumFlow > o.getSumFlow() ? -1 : 1; } |
文件通过Input进入inputFormat阶段把文件变成kv值传入Mapper然后通过Shuffle进行洗牌,然后洗完给Reducer执行OutputFormat阶段把kv值返还给框架,框架把这个东西变成文件,在输出。
切块:是HDFS把这个数据物理上进行切开,然后进行储存,是真正的切开
切片:是mapreduce把这个数据作为基本的划分,这个过程不是真正的切开,只是逻辑上的划分没有真把数据切开。
Job重点提交:jar包,切片信息,job配置的xml文件
1、 客户端提交job到resourcemanager(rm)
2、 rm将其放到等待队列,返回jobid和文件路径信息
3、 客户端将所需要计算的资源,上传到hdfs上(包括job信息和分片信息)的存储路径
4、 客户端给rm返回一个资源准备好的信息,job放入等待队列,告诉他可以启动job,等待rm进行调度
5、 rm在调度之前,申请一个资源nodemanager(nm),nm启动container,它接收到任务到hdfs上将资源获取到container,然后跟客户端交互已经得到需要计算的资源,客户端向其发送启动applicationmaster(am)的命令
6、 appmaster(am)启动起来后,通过解析分片信息向rm申请运算资源(maptask)
7、 rm收到信息查看nm资源情况,通过负载均衡分配所需要的机器,nm每一次心跳都会从job的描述信息查询自己所分配到的任务,接收到任务消息的机器会从hdfs上拿取计算资源,然后跟am交互,am发送启动maptgask的命令。
8、 Maptask结束后,通知am,然后释放magptask资源,am向rm发出信息,申请reducetask的资源
9、 rm分配资源,am启动reducetask
10、 reducetask收集maptask完成的数据,启动reduce逻辑。执行完成后,通知am,然后释放reducetask的资源。am通知rm。am释放资源
几个切片就要设置几个maptask,
听一下Yarn调度
调度器看一下
Setup cleanup 什么时候用 什么要求用?
任务推断执行看一下
优化听一下
切片机制:
框架默认的TextInputFormat切片机制是对任务按文件规划切片,不管文件多小,都会是一个单独的切片,都会交给一个MapTask,这样如果有大量小文件,就会产生大量的MapTask,处理效率极其低下。
1、应用场景:
CombineTextInputFormat用于小文件过多的场景,它可以将多个小文件从逻辑上规划到一个切片中,这样,多个小文件就可以交给一个MapTask处理。
2、虚拟存储切片最大值设置
CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);// 4m
注意:虚拟存储切片最大值设置最好根据实际的小文件大小情况来设置具体的值。
3、切片机制
生成切片过程包括:虚拟存储过程和切片过程二部分。
(1)虚拟存储过程:
将输入目录下所有文件大小,依次和设置的setMaxInputSplitSize值比较,如果不大于设置的最大值,逻辑上划分一个块。如果输入文件大于设置的最大值且大于两倍,那么以最大值切割一块;当剩余数据大小超过设置的最大值且不大于最大值2倍,此时将文件均分成2个虚拟存储块(防止出现太小切片)。
例如setMaxInputSplitSize值为4M,输入文件大小为8.02M,则先逻辑上分成一个4M。剩余的大小为4.02M,如果按照4M逻辑划分,就会出现0.02M的小的虚拟存储文件,所以将剩余的4.02M文件切分成(2.01M和2.01M)两个文件。
(2)切片过程:
(a)判断虚拟存储的文件大小是否大于setMaxInputSplitSize值,大于等于则单独形成一个切片。
(b)如果不大于则跟下一个虚拟存储文件进行合并,共同形成一个切片。
(c)测试举例:有4个小文件大小分别为1.7M、5.1M、3.4M以及6.8M这四个小文件,则虚拟存储之后形成6个文件块,大小分别为:
1.7M,(2.55M、2.55M),3.4M以及(3.4M、3.4M)
最终会形成3个切片,大小分别为:
(1.7+2.55)M,(2.55+3.4)M,(3.4+3.4)M
FileInputFormat实现类
常见的接口实现类包括:TextInputFormat、KeyValueTextInputFormat、NLineInputFormat、CombineTextInputFormat、和自定义InputFormat等。
上面的流程是整个MapReduce最全工作流程,但是Shuffle过程只是从第7步开始到第16步结束,具体Shuffle过程详解,如下:
1)MapTask收集我们的map()方法输出的kv对,放到内存缓冲区中
2)从内存缓冲区不断溢出本地磁盘文件,可能会溢出多个文件
3)多个溢出文件会被合并成大的溢出文件
4)在溢出过程及合并的过程中,都要调用Partitioner进行分区和针对key进行排序
5)ReduceTask根据自己的分区号,去各个MapTask机器上取相应的结果分区数据
6)ReduceTask会取到同一个分区的来自不同MapTask的结果文件,ReduceTask会将这些文件再进行合并(归并排序)
7)合并成大文件后,Shuffle的过程也就结束了,后面进入ReduceTask的逻辑运算过程(从文件中取出一个一个的键值对Group,调用用户自定义的reduce()方法)
3.注意
Shuffle中的缓冲区大小会影响到MapReduce程序的执行效率,原则上说,缓冲区越大,磁盘io的次数越少,执行速度就越快。
缓冲区的大小可以通过参数调整,参数:io.sort.mb默认100M。
第一次:在环形缓冲区进行快排,第二次在归并的时候排序,第三次在reduce输出时候进行归并排序
根据job自己手动设置,根据数据量估算自己设置分区。
多个reduce分区的时候,做汇总,第一个分区处理A-G 第二个处理H-N,第三个处理O-Z,
分区发生在环形缓冲区数据出来之前进行分区
相同的k永远进入同一个分区,假设相同的k特别多 导致reduce处理数据量差距大会产生数据倾斜的时候需要用到自定义分区
如何自定义分区:
要需求自己新建一个MyPartition去继承Partitioner<与Mapper输出类型一致>,实现方法,再用switch()
在Driver中job.setNumReduceTasks(5);//自定义分区 5个区手动新建分区按照case多少来定。
自定义Combiner:
自定义一个Combiner继承Reducer,重写Reduce方法
在Driver下写job.setCombinerClass(写reducer.com)
看情况使用
在reduce输出归并排序的时候是按顺序排好的,这时候按照k值相同的在一组不同的给分到另一组,分组这个动作涉及到比较。作用就是比较两个k相不相等。
把reuduce处理的kv值变成文件
默认的是TextOutputFormat
1.使用场景
Map Join适用于一张表十分小、一张表很大的场景。
2.优点
思考:在Reduce端处理过多的表,非常容易产生数据倾斜。怎么办?
在Map端缓存多张表,提前处理业务逻辑,这样增加Map端业务,减少Reduce端数据的压力,尽可能的减少数据倾斜。
3.具体办法:采用DistributedCache
(1)在Mapper的setup阶段,将文件读取到缓存集合中。
(2)在驱动函数中加载缓存。
// 缓存普通文件到Task运行节点。
job.addCacheFile(new URI("file://e:/cache/pd.txt"))