hadoop 2.x和hadoop 3.x的差异
Java的最小支持版本
- Hadoop 2.x - Java 7
- Hadoop 3.x - Java 8
容错性及更好的存储方案
- Hadoop 2.x - 通过版本复制提高容错性,3倍副本存储
- Hadoop 3.x - 通过擦除编码技术实现容错性,在HDFS上支持擦除编码技术(Erasure Coding,简称EC),解决副本复制和副本存储带来的空间和资源的消耗,以EC代替副本,提供和副本存储相同的容错能力,并且存储开销不大于单副本开销的50%。
数据负载均衡
一个DataNode管理多个磁盘,当数据正常写入时,多个磁盘是平均分配的,然而当添加新磁盘时
- Hadoop 2.x - 只会实现DataNode之间的数据平衡,这种机制会造成DataNode内部的数据倾斜
- Hadoop 3.x - 还会实现各个DataNode内部的数据平衡
兼容的文件系统
- Hadoop 2.x - HDFS,FTP文件系统(将所有数据存储在远端FTP服务器上),亚马逊S3,微软Azure WASB文件系统
- Hadoop 3.x - 以上及微软Azure数据湖文件系统
更高级别的HA
- Hadoop 2.x -HA的实现为一个Active NameNode 和 单个 Standby NameNode,将edits复制到三个JournalNode,该体系能够容忍一个 NameNode 或者一个JournalNode故障,解决了系统中NameNode的单点故障问题。
- Hadoop 3.x - 允许运行一个Active NameNode 和 单多个 Standby NameNode来实现高可用
扩展性
- Hadoop 2.x - 在Hadoop 2中,单个集群可以扩展到10000个节点
- Hadoop 3.x - 扩展性更好,单个集群可以扩展到大于10000个节点
MapReduce
MapReduce的过程概况
Shuffle的过程是从map方法结束到reduce方法开始之前
MapTask:
- maptask调用TextinputFormat中封装的LineRecordReader.next()方法去读取对应的切片,每次读一行。
- 并返回key(起始偏移量)和value(行内容)。
- 再调用xxMapper中的map(key,value,context)方法进行处理。
- 并返回context.write(key,value)。
- 此时OutputController.collect()会将返回的一堆(key,value)进行序列化,放到一个缓冲区里面(环形缓冲区,默认为100M)。
- 当缓冲快满的时候,会调用Spiller.spill()进行一个溢出,在溢出的过程中进行分区(key的hashcode%reducetasks)和排序(同一个区中,按key排序;运用了快速排序算法),然后生成多个溢出文件。Maptask在退出之前,将多个溢出文件合并为一个(运用了归并排序和外部排序算法)。
ReduceTask:
- reducetask会将maptask执行完后生成的合并文件中相同分区的(key,value),合并(归并排序)到一个文件中。
- 调用xxReducer.reduce(Text key,迭代器 values,cotext),一个key调用一次对应的迭代器。
- 返回了一个context.write(key,value)。
- TextOutputFormat中的RecordWriter.write(key,value)写到hdfs指定的目录中。
MapReduce中的排序
排序的作用
减小内存的使用量
MapReduce在reduce阶段需要分组,将key相同的放在一起进行规约,为了达到该目的,有两种算法:hashmap和sort ,但hashmap算法太耗内存,而sort通过外排可对任意数据量分组,只要磁盘够大就行。map端排序是为了减轻reduce端排序的压力。
提高join的效率
JOIN 操作对于有序的集合的复杂度为O(n)
,这也是排序的一个必要之处。
mapreduce中的几次排序
- 第一次:kvbuffer溢写之前会先对内存中的文件根据key和partition进行排序。方式:快排
- 第二次:所有文件都经过map方法和kvbuffer后,所有的小文件会合并成file.out文件,合并过程中会进行第二次排序,用来保证该文件有序。整个文件会根据partition分成多个块,每个块内按照key值排序。方式:归并(归并排序的方式很适合做多文件合并排序,且归并排序是具有稳定性的排序方式)。
- 第三次:reduce拉取到的文件会进行合并,此时会再次进行排序。方式:归并。
- 第四次:使用了堆排作最后的合并过程。
HDFS
HDFS中如何存储元数据
HDFS采用了内存+磁盘的形式来管理元数据。即: NameNode(内存)+FsImage文件+Edits文件,其中,FsImage文件会不断与Edits文件进行合并
FsImage文件
是namenode中关于元数据的镜像,一般称为检查点(checkpoing),这里包含了HDFS文件系统所有目录以及文件相关信息(Block数量,副本数量,权限等信息)
Edits文件
edits文件记录的就是当原FsImage被载入内存后,Client又对元数据进行了哪些增删改操作。这样,只要在原FsImage中执行edits文件记录的这些操作,就可以使得内存和磁盘汇总的元数据的一致性
SecondaryNameNode节点的作用及Fsimage与Edits的合并过程
SecondaryNanoe是HDFS架构中的一个组成部分,它是辅助NameNode将NameNode的编辑日志Edits文件合并到fsimage文件中。一般都是将SecondaryNamenode单独运行在一台机器上。
Fsimage与Edits的合并过程
- SecondaryNamenode会定期的和NameNode通信,请求其停止使用edits文件,暂时将新的写操作写到一个新的文件edit.new上来,这个操作是瞬间完成,上层写日志的函数完全感觉不到差别;
- SecondaryNamenode通过HTTP GET方式从NameNode上获取到fsimage和edits文件,并下载到本地的相应目录下;
- SecondaryNamenode将下载下来的fsimage载入到内存,然后一条一条地执行edits文件中的各项更新操作,使得内存中的fsimage保存最新;这个过程就是edits和fsimage文件合并;
- SecondaryNamenode执行完(3)操作之后,会通过post方式将新的fsimage文件发送到NameNode节点上
- NameNode将从SecondaryNamenode接收到的新的fsimage替换旧的fsimage文件,同时将edit.new替换edits文件,通过这个过程fsimage镜像文件保存较新的状态并且edits文件也不会一直变大
因此,如果NameNode中的元数据丢失,可以从辅助NameNode中恢复部分元数据信息,但不全部,因为NameNode正在写入的编辑日志尚未复制到辅助NameNode,并且这部分信息无法恢复。
NameNode在启动时会做哪些操作
首次初始化NameNode
- 格式化文件系统,以生成fsimage映像文件;
- 开始命名节点:读取fsimage文件并将文件内容加载到内存中。等待DataNade注册并发送注册报告
- 启动DataNode:向NameNode注册,发送注册报告,检查fsimage中记录的块数是否与块报告中的总块数相同。
- 操作文件系统(创建目录,上传文件,删除文件等。):此时内存中已经有文件系统改变的信息,但是磁盘中没有文件系统改变的信息,此时会将这些改变信息写入 edits 文件中,edits 文件中存储的是文件系统元数据改变的信息。
之后启动NameNode
- 当 NameNode 启动时HDFS首先将Fsimage读入内存对元数据进行恢复;
- 然后再读edits文件中的更新操作在恢复后的元数据上进行执行,使得此时的NameNode中保存的是停止前的最新状态,然后删除旧的edits (这个过程称为检査点);
- 启动DataNode,等待各个DataNode向 NameNode 汇报文件块的信息来组装 block ID 映射关系;
- DataNode 启动时会扫描本地文件系统,产生一个本地文件对应的 HDFS 文件块的列表(每个文件块会对应一个本地文件),然后作为报告发送到 NameNode(这个报告称为块状态报告);
- NameNode 在接收到每个 DataNode 的块汇报信息后,将其和所在的 DataNode 信息等保存在内存中。
HDFS容错机制
- namenode高可用:配置多个namenode,一旦active挂了,standby就会起来
- secondarynamenode机制:如果 NameNode 中的元数据丢失,是可以从 Secondary NameNode 恢复一部分元数据信息的,但不是全部,因为 NameNode 正在写的 edits 日志还没有拷贝到 Secondary NameNode,这部分恢复不了
- 副本机制:每一个block都会有2-3个备份存在其他的设备上
- 心跳机制:DataNode以固定周期 (3s) 向NameNode发送心跳,NameNode如果在一段时间内没有收到心跳,会把该节点判定为死亡