Hadoop知识点总结

517 阅读15分钟

一、HDFS部分

1、NameNode和SecondaryNameNode工作机制

image.png 第一阶段:NameNode 启动

(1)第一次启动 NameNode 格式化后,创建 Fsimage 和 Edits 文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。

(2)客户端对元数据进行增删改的请求。

(3)NameNode 记录操作日志,更新滚动日志。

(4)NameNode 在内存中对元数据进行增删改。

第二阶段:Secondary NameNode 工作

(1)Secondary NameNode 询问 NameNode 是否需要 CheckPoint。直接带回 NameNode 是否检查结果。

(2)Secondary NameNode 请求执行 CheckPoint。

(3)NameNode 滚动正在写的 Edits 日志。

(4)将滚动前的编辑日志和镜像文件拷贝到 Secondary NameNode。

(5)Secondary NameNode 加载编辑日志和镜像文件到内存,并合并。

(6)生成新的镜像文件 fsimage.chkpoint。

(7)拷贝 fsimage.chkpoint 到 NameNode。

(8)NameNode 将 fsimage.chkpoint 重新命名成 fsimage。

2、NameNode高可用原理

- 原理

在一个典型的HA集群中,每个NameNode是一台独立的服务器。在任一时刻,只有一个NameNode处 于active状态,其他的NameNode处于standby状态。其中,active状态的NameNode负责所有的客户端操作, standby状态的NameNode处于从属地位,维护着数据状态,随时准备切换。 两个NameNode为了数据同步,会通过一组称作JournalNodes的独立进程进行相互通信。当active状态 的NameNode的命名空间有任何修改时,会告知大部分的JournalNodes进程。standby状态的 NameNode有能力读取JNs中的变更信息,并且一直监控edit log的变化,把变化应用于自己的命名空 间。standby可以确保在集群出错时,命名空间状态已经完全同步。 为了确保快速切换,standby状态的NameNode有必要知道集群中所有数据块的位置。为了做到这点, 所有的datanodes必须配置两个NameNode的地址,发送数据块位置信息和心跳给他们两个。对于HA集群而言,确保同一时刻只有一个NameNode处于active状态是至关重要的。否则,两个 NameNode的数据状态就会产生分歧,可能丢失数据,或者产生错误的结果。为了保证这点,JNs必须 确保同一时刻只有一个NameNode可以向自己写数据。

- HDFS-HA 核心问题

(1)怎么保证三台 NameNode 的数据一致

a.Fsimage: 让一台 NameNode 生成数据,让其他机器 nn 同步

b.Edits: 需要引进新的模块 JournalNode 来保证 edtis 的文件的数据一致性

(2)怎么让同时只有一台 NameNode 是 active,其他所有是 standby 的

a.手动分配

b.自动分配

(3)2nn 在 HA 架构中并不存在,定期合并 fsimage 和 edtis 的活谁来干

由 standby 的 NameNode 来干

(4)如果 NameNode 真的发生了问题,怎么让其他的 NameNode 上位干活

a.手动故障转移

b.自动故障转移

  • 自动故障转移机制

image.png

- HDFS-HA 自动故障转移的集群规划 image.png

3、DataNode工作机制

image.png

(1)一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元 数据包括数据块的长度,块数据的校验和,以及时间戳。

(2)DataNode启动后向NameNode注册,通过后,周期性(1小时)地向NameNode上报所有的块信息。

(3)心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机 器,或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用。

(4)集群运行中可以安全加入和退出一些机器。

4、数据压缩

- gzip压缩

应用场景:当每个文件压缩之后在130M以内的(1个块大小内),都可以考虑用gzip压缩格式。譬如说 一天或者一个小时的日志压缩成一个gzip文件,运行mapreduce程序的时候通过多个gzip文件达到并 发。hive程序,streaming程序,和java写的mapreduce程序完全和文本处理一样,压缩之后原来的程 序不需要做任何修改。

优点:压缩率比较高,而且压缩/解压速度也比较快;hadoop本身支持,在应用中处理gzip格式的文件 就和直接处理文本一样;有hadoop native库;大部分linux系统都自带gzip命令,使用方便。

缺点:不支持split。

- snappy压缩

应用场景:当mapreduce作业的map输出的数据比较大的时候,作为map到reduce的中间数据的压缩格式;或者作为一个mapreduce作业的输出和另外一个mapreduce作业的输入。

优点:高速压缩速度和合理的压缩率;支持hadoop native库。

缺点:不支持split;压缩率比gzip要低;hadoop本身不支持,需要安装;linux系统下没有对应的命令。

- lzo压缩

应用场景:一个很大的文本文件,压缩之后还大于200M以上的可以考虑,而且单个文件越大,lzo优点 越明显。

优点:压缩/解压速度也比较快,合理的压缩率;支持split,是hadoop中最流行的压缩格式;支持 hadoop native库;可以在linux系统下安装lzop命令,使用方便。

缺点:压缩率比gzip要低一些;hadoop本身不支持,需要安装;在应用中对lzo格式的文件需要做一些 特殊处理(为了支持split需要建索引,还需要指定inputformat为lzo格式)。

- bzip2压缩

应用场景:适合对速度要求不高,但需要较高的压缩率的时候,可以作为mapreduce作业的输出格式; 或者输出之后的数据比较大,处理之后的数据需要压缩存档减少磁盘空间并且以后数据用得比较少的情 况;或者对单个很大的文本文件想压缩减少存储空间,同时又需要支持split,而且兼容之前的应用程序 (即应用程序不需要修改)的情况。

优点:支持split;具有很高的压缩率,比gzip压缩率都高;hadoop本身支持,但不支持native;在linux 系统下自带bzip2命令,使用方便。

缺点:压缩/解压速度慢。

5、HDFS存储机制之写过程

image.png

(1)客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据, 找到文件块所在的DataNode地址。 (2)挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。

(3)DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。

(4)客户端以Packet为单位接收,先在本地缓存,然后写入目标文件。

6、HDFS存储机制之读过程

image.png (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步)。

7、HDFS小文件处理

- HDFS小文件弊端

HDFS上每个文件都要在NameNode上建立一个索引,这个索引的大小约为150byte,这样当小文件比较 多的时候,就会产生很多的索引文件,一方面会大量占用NameNode的内存空间,另一方面就是索引文 件过大使得索引速度变慢。

**- HDFS小文件解决方案 **

(1) Hadoop Archive Hadoop Archive或者HAR,是一个高效地将小文件放入HDFS块中的文件存档工具,它能够将多个小文 件打包成一个HAR文件,这样在减少namenode内存使用的同时,仍然允许对文件进行透明的访问。

(2) Sequence file sequence file由一系列的二进制key/value组成,如果为key小文件名,value为文件内容,则可以将大 批小文件合并成一个大文件。

(3)CombineFileInputFormat 用于将多个文件合并出成单独的Split,另外,它会考虑数据的存储位置。

(4)开启JVM重用 原理:一个Map运行在一个JVM上,开启重用的话,该Map在JVM上运行完毕后,JVM继续运行其他 Map。(mapreduce.job.jvm.numtasks) ,对于大量小文件Job,可以减少45%运行时间。

二、MapReduce部分

1、MapReduce流程

image.png

image.png

image.png

1、MapTask通过用户编写的RecordReader,从输入InputSplit中解析出一个个 key/value。

2、将解析出的key/value交给用户编写map()函数处理,并产生一系列新的 key/value。

3、调用 OutputCollector.collect()输出结果。在该函数内部,它会将生成的key/value分区(调用 Partitioner),并写入一个默认100MB大小的环形内存缓冲区中,该环形缓冲区一半存数据一半存索引(元数据)。

4、当环形缓冲区写到80%时开始溢写到磁盘上,溢写过程中新到的数据反向写入。

5、数据分区,分区内对key的索引按字典顺序进行快速排序。如果设置了Combiner,则对每个分区中的数据进行一次聚集操作。

6、对分区内部有序的临时数据文件进行归并排序,确保一个MapTask最后只产生一个数据文件。此时可以根据设置进行第二次Combiner合并以及压缩操作,可以提高网络传输效率。

7、ReduceTask 根据自己的分区号,去各个 MapTask 机器上取相应的结果分区数据。如果数据片大小超过一定阈值,则写到磁盘上,否则直接放到内存中。

8、在远程拷贝数据的同时,ReduceTask启动两个后台线程对内存和磁盘上的文件进行归并排序合并,以防止内存使用过多或磁盘上文件过多。

9、对数据按key进行分组,保证reduce方法一次处理相同key的数据。

10、聚合运算结果由OutPutFormat组件中的RecordWriter写到HDFS上。

2、优化

- Map阶段优化

(1)增大环形缓冲区大小。由100m扩大到200m

(2)增大环形缓冲区溢写的比例。由80%扩大到90%

(3)减少对溢写文件的merge次数。(10个文件,一次20个merge)

(4)不影响实际业务的前提下,采用Combiner提前合并,减少 I/O。

- Reduce阶段优化

(1)合理设置Map和Reduce数:两个都不能设置太少,也不能设置太多。太少,会导致Task等待,延 长处理时间;太多,会导致 Map、Reduce任务间竞争资源,造成处理超时等错误。

(2)设置Map、Reduce共存:调整slowstart.completedmaps参数,使Map运行到一定程度后, Reduce也开始运行,减少Reduce的等待时间。

(3)规避使用Reduce,因为Reduce在用于连接数据集的时候将会产生大量的网络消耗。

(4)增加每个Reduce去Map中拿数据的并行数。

(5)集群性能可以的前提下,增大Reduce端存储数据内存的大小。

- IO传输

采用数据压缩的方式,减少网络IO的时间。安装Snappy和LZOP压缩编码器。

压缩:

(1)map输入端主要考虑数据量大小和切片,支持切片的有Bzip2、LZO。注意:LZO要想支持切片必须创建索引。

(2)map输出端主要考虑速度,速度快的snappy、LZO。

(3)reduce输出端主要看具体需求,例如作为下一个mr输入需要考虑切片,永久保存考虑压缩率比较大的gzip。

3、数据倾斜

1、定义

mapreduce程序执行时,reduce节点大部分执行完毕,但是有一个或者几个reduce节点运行很慢,导致整个程序的处理时间很长,这是因为某一个key的条数比其他key多很多(有时是百倍或者千倍之多),这条key所在的reduce节点所处理的数据量比其他节点就大很多,从而导致某几个节点迟迟运行不完。

2、现象

1、绝大多数task执行得都非常快,但个别task执行的极慢。 2、原本能正常执行的Spark作业,某天突然爆出OOM(内存溢出)异常。观察异常栈,是我们写的业务代码造成的。

3、解决方案

1、能在 map 阶段提前处理,最好先在 Map 阶段处理

提前在map进行combine和MapJoin,减少传输的数据量。在Mapper加上combiner相当于提前进行reduce,即把一个Mapper中的相同key进行了聚合,减少 shuffle过程中传输的数据量,以及Reducer端的计算量。 如果导致数据倾斜的key大量分布在不同的mapper的时候,这种方法就不是很有效了。

2、导致数据倾斜的key 大量分布在不同的mapper

(1)局部聚合加全局聚合。 第一次在map阶段对那些导致了数据倾斜的key 加上1到n的随机前缀,这样本来相同的key 也会被分到多个Reducer中进行局部聚合,数量就会大大降低。 第二次mapreduce,去掉key的随机前缀,进行全局聚合。思想:二次mr,第一次将key随机散列到不同reducer进行处理达到负载均衡目的。第二次再根据去掉 key的随机前缀,按原key进行reduce处理。 这个方法进行两次mapreduce,性能稍差。

(2) 增加Reducer,提升并行度:JobConf.setNumReduceTasks(int)

(3)实现自定义分区:根据数据分布情况,自定义散列函数,将key均匀分配到不同Reducer

3、增加reduce内存

这适用于唯一值非常少,极少数值有非常多的记录值(唯一值少于几千)。这种情况下,往往只能通过硬件的手段来进行调优,增加jvm内存可以显著的提高运行效率。

4、增加reduce个数

这适用于唯一值比较多,这个字段的某些值有远远多于其他值的记录数,但是它的占比也小于百分之一或千分之一。我们知道,这种情况下,最容易造成的结果就是大量相同key被partition到一个分区,从而一个reduce执行了大量的工作,而如果我们增加了reduce的个数,这种情况相对来说会减轻很多,毕竟计算的节点多了,就算工作量还是不均匀的,那也要小很多。

三、Yarn部分

1、Yarn工作机制

image.png

2、Yarn调度器

1、先进先出调度器(FIFO)

image.png

单队列,根据提交作业的先后顺序,先来先服务。优点:简单易懂; 缺点:不支持多队列,生产环境很少使用。

2、容量调度器

image.png

image.png

以队列为单位划分资源,每个队列可设定一定比例的资源最低保证和使用上限,同时,每个用户也可设定一定的资源使用上限以防止资源滥用。而当一个队列的资源有剩余时,可暂时将剩余资源共享给其他队列。

特点

(1)可为每个队列设置资源最低保证和资源使用上限,而所有提交到该队列的应用程序共享这些资源。

(2)如果一个队列中的资源有剩余,可以暂时共享给那些需要资源的队列,而一旦该队列有新的应用 程序提交,则其他队列释放的资源会归还给该队列。

(3)支持多用户共享集群和多应用程序同时运行。为防止单个应用程序、用户或队列独占集群中的资 源,可为之增加多重约束(比如单个应用程序同时运行的任务数等)。

(4)每个队列有严格的ACL列表规定它的访问用户,每个用户可指定哪些用户允许查看自己应用程序的 运行状态或者控制应用程序(比如杀死应用程序)。

3、公平调度器

image.png

公平调度器可以为所有的应用“平均公平”分配资源,当然,这种“公平”是可以配置的,称为权重,可以在分配文件中为每一个队列设置分配资源的权重,如果没有设置,默认是1(由于默认权重相同,因此在不做配置的情况下,作业(队列)之间的资源占比相同)。 公平调度器设计目标是:在时间尺度上,所有作业获得公平的资源。某一时刻一个作业应获资源和实际获取资源的差距叫“缺额”,调度器会优先为缺额大的作业分配资源。

特点:

(1)允许资源共享,即当一个APP运行时,如果其它队列没有任务执行,则可以使用其它队列(不属于该APP 的队列),当其它队列有APP需要资源时再将占用的队列释放出来.所有的APP都从资源队列中分配资源。

(2)当队列中有任务,该队列将至少获得最小资源.当队列资源使用不完时,可以给其它队列使用。

(3)当队列不能满足最小资源时,可以从其它队列抢占。