参考文献
参考博客链接:
Hadoop
数据倾斜
参考pdf教程: 尚硅谷大数据技术之 Hadoop(MapReduce)V2.0
Hadoop
1.什么是Hadoop
Hadoop是一个分布式系统基础架构,主要解决海量数据的存储和海量数据的分析计算问题。
2.Hadoop的优缺点
优点:
高可靠性: Hadoop底层维护多个数据副本,所以即使某个计算元素或者存储出现故障,也不会出现数据的丢失。
高扩展性: 在集群间分配任务数据,可方便扩展数以千计的节点。
高效性: 并行工作。
高容错性: 能够自动将失败的任务自动分配。
3.Hadoop运行模式
本地模式: 单机运行
伪分布模式: 也是单机运行,但是具备Hadoop集群的所有功能,一台服务器模拟一个分布式的环境。
完全分布模式: 多台服务器组成分布式的环境。
4.辨析Hadoop和Hadoop生态系统的概念
Hadoop是指Hadoop框架本身;Hadoop生态系统是指Hadoop及能够保证Hadoop正常运行的其他框架。如Zookeeper, Flume, Hive等。
5.Hadoop生态圈的组件
1)Zookeeper: 它是一个针对大型分布式系统的可靠协调系统,提供的功能包括:配置维护,名字服务,分布式同步等。
2)HBase: 它是一个分布式的,面向列的开源数据库。它是一个适合非结构化数据存储的数据库。
3)Hive: 它是一个基于Hadoop的数据仓库工具,提供简单的SQL语句,可以将SQL语句转换为MapReduce任务进行运行。可以将结构化的数据文件映射为一张表,并提供类 SQL 查询功能。
4)Flume: 它是一个高可用的,高可靠的,分布式的海量日志采集,聚合和传输的系统。
5)Sqoop: 主要用于Hadoop,Hive和MySQL之间数据的传递。
6)Spark: 开源大数据内存计算框架。
6.Hadoop1.x 和 Hadoop2.x区别
7.Hadoop集群正常工作中需要启动的进程及其作用:
NameNode: 存储文件的元数据(如文件名,文件目录结构,文件属性)
DataNode: 在本地文件系统存储文件块数据
SecondaryNameNode: 每隔一段时间对NameNode元数据备份
NodeManager: 执行任务
ResourceManager: 负责调度DataNode上的工作
HDFS
1.HDFS定义
它是一个文件系统,用于存储文件,通过目录树来定位文件;它是分布式的,有很多服务器联合起来实现其功能;适合一次写入,多次读出的场景,且不支持文件的修改。适合用来做数据分析,并不适合用来做网盘应用。
2.HDFS优缺点
优点:
1)高容错性:数据自动保存多个副本;某一个副本丢失后,可以自动恢复。
2)适合处理大数据。
3)可构建在廉价机器上,通过多副本机制,提高可靠性。
缺点:
1)不适合低延时数据访问,比如毫秒级的存储数据,是做不到的。
2)无法高效的对大量小文件进行存储。
3)不支持文件并发写入,一个文件只能有一个写,不允许多个线程同时写。
3)仅支持数据append(追加),不支持文件的随机修改。
3.HDFS组成架构
4.HDFS文件块大小
HDFS的文件在物理上是分块储存(Block),块的大小通过配置参数配置(dfs.blocksize),默认大小在Hadoop2.x版本中是128MB,老版本中是64M。
5.为什么快的大小不能设置太大,也不能设置太小?
(1)如果HDFS块的大小设置太小,则会增加寻址时间,程序一直在寻找块的开始位置;
(2)如果块的大小设置太大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需要的时间。导致程序处理非常慢。
(3)HDFS块的大小设置取决于磁盘传输速率。
6.HDFS的shell操作(开发重点)
#1.命令大全:
bin/hadoop fs
#2.启动Hadoop集群:
sbin/start-dfs.sh
sbin/start-yarn.sh
#3.输出某一命令参数
hadoop fs -help rm#4.创建文件夹
hadoop fs -mkdir bigdata
#5.上传操作#5.1 从本地剪切粘贴到HDFS上
hadoop fs -moveFromLocal
#5.2 从本地系统拷贝到HDFS上
hadoop fs -copyFromLocal
#5.3 等同于copyFromLocal
hadoop fs -put
#5.4 追加一个文件到已经存在的文件末尾
hadoop fs -appendToFile
#6.下载操作#6.1 从HDFS拷贝到本地
hadoop fs -copyToLocal
hadoop fs -get
#7.直接操作
显示目录信息 hadoop fs -ls /shu
显示文件内容 hadoop fs -cat 文件名字
修改文件属性 -chmod -chown
创建路径 -mkdir
从HDFS的一个路径拷贝到另一个路径 -cp
在HDFS中移动文件 -mv
设置文件的副本数量 -setrep
7.HDFS的写数据流程
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步)。
8.HDFS的读数据流程
1)客户端通过分布式系统模块(Distributed FileSystem)向NameNode请求下载文件,NameNode通过查询元数据,找到文件所在的DataNode地址。
2)挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
3)DataNode开始传输数据给客户端(从磁盘里面读取数据流,以Packet为单位做校验)
4)客户端以Packet为单位接收,现在本地缓存,然后写入目标文件。
9.NN 和 2NN 工作机制
1)Fsimage文件: NameNode 内存中元数据序列化后形成的文件,用于在磁盘中备份元数据。
2)Edits文件: 每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits文件中;记录客户端更新元数据信息的每一步操作(可通过 Edits 运算出元数据)。
一旦NameNode断电,就会合并Fsimage文件和Edits文件,合成元数据。引入的Secondary NameNode 专门用于合并两个文件。
第一阶段: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。
扩展问题:为什么HDFS不适合批量存储小文件?
小文件的定义:
文件大小小于或者等于30M的文件
HDFS小文件带来危害:
(1)小文件数量过多(例如图片)会占用批量占用Namenode的内存,因为每个存储在HDFS中的文件的元数据(包括目录树,位置信息,命名空间镜像fsimage,文件编辑信息edits)都会在Namenode中占用150B的内存,如果Namenode存储空间满了,就不能继续存储新文件了。
(2)如果有多小文件,会造成寻道时间>=读取文件时间(传输文件时间 = 寻道时间+读取文件时间),这与HDFS的原理相违背,HDFS的设计是为了减小寻道时间,使其远小于读取文件的时间。Hive或者Spark计算的时候会影响他们的速度,因为Spark计算时会将数据从硬盘读到内存,零碎的文件将产生较多的寻道过程。
(3)流式读取的方式,不适合多用户写入,以及任意位置写入。如果访问小文件,则必须从一个Datanode跳转到另外一个Datanode,这样大大降低了读取性能。
扩展问题:数据在DataNode中如何存储?
HDFS默认的数据存储块是64MB,现在新版本的hadoop环境(2.7.3版本后),默认的数据存储块是128MB。
一个文件如果小于128MB,则按照真实的文件大小独占一个数据存储块,存放到DataNode节点中。同时 DataNode一般默认存三份副本,以保障数据安全。 同时该文件所存放的位置也写入到NameNode的内存中,如果有Secondary NameNode高可用节点,也可同时复制一份过去。NameNode的内存数据将会存放到硬盘中,如果HDFS发生重启,将产生较长时间的元数据从硬盘读到内存的过程。
如果一个文件大于128MB,则HDFS自动将其拆分为128MB大小,存放到HDFS中,并在NameNode内存中留下其数据存放的路径。不同的数据块将存放到可能不同的DataNode中。
扩展问题:HDFS的文件存储格式有哪些?
Hadoop文件格式学习
HDFS的文件存储格式以及HDFS异构存储和存储策略
大数据存储数据,99%以上的场景都是使用的是列式存储。
MapReduce
1.什么是MapReduce?
MapReduce是一个分布式运算程序的编程框架,它的核心功能是将用户编写的业务逻辑代码和自带默认组件代码整合成一个完整的分布式运算程序,并发运行在一个Hadoop集群上。
扩展理解:
MapReduce是一种分布式计算模型,它主要用于大规模数据的处理和分析。在MapReduce模型中, Map函数和Reduce函数都是非常重要的组成部分,它们分别在数据预处理和结果合并阶段发挥重要作用。
Map函数一般用来对数据进行预处理。当MapReduce模型读取数据时, Map函数会对每个数据块进行处理。Map函数的输入是键-值对输出也是键-值对。Map函数可以将输入的键-值对映射为任意数量的键-值对输出。例如,一个典型的Map函数可以将一个文档分解为单词,并将每个单词映射为一个键-值对。在这个例子中,键是单词,值是1或者是出现次数。Map函数的处理结果会被传递给Reduce函数进行处理。
Reduce函数则用来合并Map函数输出的结果。当MapReduce模型读取完所有数据后,Reduce 函数会对合并后的数据进行处理。Reduce函数的输入是一个键和一个值构成的集合, 输出也是一个键和一个值构成的集合。Reduce 函数会对所有输入的键-值对进行分组,并对每个键的一组值进行处理。Reduce 函数的处理结果会成为MapReduce模型的输出。例如,一个典型的Reduce函数可以将相同单词的计数值相加。在这个例子中,Reduce函数的输出是一个单词及其在文档中出现的总次数。
2.MapReduce的优缺点
3.MapReduce的核心编程思想
1)MapReduce运算程序一般分成两个阶段,Map阶段和Reduce阶段。
2)Map阶段的Map Task并发实例,完全并发运行,互不相干。
3)Reduce阶段的Reduce Task并发实例互不相干,但是他们的数据依赖于上一个阶段的所有Map Task并发实例的输出。
4)MapReduce编程模型只能包含一个Map阶段和一个Reduce阶段,如果用户的业务逻辑非常复杂,那就只能多个MapReduce程序,串行运行。
4.MapReduce进程
一个完整的MapReduce程序在分布式运行时有三类实例进程:
1) MrAppMaster: 负责整个程序的过程调度及状态协调。
2) MapTask: 负责Map阶段的整个数据处理流程。
3) ReduceTask: 负责Reduce阶段的整个数据处理流程。
5.Hadoop序列化
1)序列化: 序列化就是把内存中的对象,转换成字节序列以便于存储到磁盘(持久化)和网络传输。
2)反序列化: 将收到字节序列或者是磁盘的持久化数据,转换成内存中的对象。
3)为什么要序列化:
“活的”对象只生存在内存里,关机断电就没有了,而且“活的”的对象只能在本地的进程中使用,不能被发送到网络上的另一台计算机。然而序列化可以存储“活的”对象,可以将活的对象发送到远程计算机中。
4)为什么不用Java的序列化:
Java的序列化是一个重量级序列化框架,一个对象被序列化后,会附带很多额外的信息,不便于在网络中高效传输,所以,Hadoop自己开发了一套序列化机制。
5)Hadoop序列化的特点:
紧凑: 高效使用存储空间
快速: 读写数据的额外开销小
互操作: 支持多语言的交互
6)自定义bean对象实现序列化接口步骤:
1.必须实现Writable接口;
2.反序列化时,需要反射调用空参构造函数,所以必须有空参构造;
3.重写序列化方法;
4.重写反序列化方法;
5.注意:反序列化和序列化的顺序完全一致。
6.要想把结果显示文件中,需要重写toString方法,可用”\t”分开,方便后续用
7.如果需要将自定义的bean放在key中传输,则还需要实现Comparable接口,因为MapReduce框中的Shuffle过程要求对key必须能排序。
6.MapReduce框架原理
6.1 InputFormat
1)MapTask并行度决定机制
数据块: Block是HDFS物理上把数据分成一块一块,数据块是HDFS的数据存储单位。
数据切片: 数据切片是MapReduce程序计算输入数据的单位,一个切片会对应启动一个MapTask。
2)FileInputFormat切片源码解析
3)切片大小的参数配置:
计算切片大小的公式:
Math.max(minSize,Math.min(maxSize,blockSize))
切片大小的设置:
maxSize(切片最大值):参数如果调得比blockSize小,则会让切片变小,而且就等于配置的这个参数的值。
minSize(切片最小值):参数调得比blockSize大,则会让切片变得比blockSize大。
6.2 判定一个job的Map和Reduce数量
1)map数量由处理的数据分成的block数量决定,
default_num = total_size / split_size
。
2)reduce数量由
job.setNumReduceTasks(x)
决定。
7.MapReduce工作机制
7.1 MapTask工作机制
1)Read阶段: MapTask通过用户编写的RecordReader,从输入InputSplit中解析出一个个key/value。
2)Map阶段: 该节点主要是将解析出的key/value交给用户编写map()函数处理,并产生一系列新的key/value。
3)Collect收集阶段: 在用户编写map()函数中,当数据处理完成后,一般会调用OutputCollector.collect()输出结果。**在该函数内部,它会将生成的key/value
分区
(调用Partitioner),并写入一个环形内存缓冲区内**。
4)Spill阶段: 即“溢写”,当环形缓冲区满后,MapReduce 会将数据写到本地磁盘上,生成一个临时文件。需要注意的是,将数据写入本地磁盘之前,先要对数据进行一次本地排序,并在必要时对数据进行合并、压缩等操作。
溢写阶段详情:
步骤1: 利用快速排序算法对缓存区内的数据进行排序,排序方式是,先按照分区编号Partition 进行排序,然后按照 key 进行排序。这样,经过排序后,数据以分区为单位聚集在一起,且同一分区内所有数据按照 key 有序。
步骤2: 按照分区编号由小到大依次将每个分区中的数据写入任务工作目录下的临时文件
output/spillN.out
(N 表示当前溢写次数)中。如果用户设置了 Combiner,则写入文件之前,对每个分区中的数据进行一次聚集操作。
步骤 3: 将分区数据的元信息写到内存索引数据结构 SpillRecord 中,其中每个分区的元信息包括在临时文件中的偏移量、压缩前数据大小和压缩后数据大小。如果当前内存索引大小超过 1MB,则将内存索引写到文件 output/spillN.out.index 中。
5)Combine 阶段: 当所有数据处理完成后,MapTask 对所有临时文件进行一次合并,以确保最终只会生成一个数据文件。
当所有数据处理完后,MapTask 会将所有临时文件合并成一个大文件,并保存到文件
output/file.out 中,同时生成相应的索引文件 output/file.out.index。
在进行文件合并过程中,MapTask 以分区为单位进行合并。对于某个分区,它将采用多
轮递归合并的方式。每轮合并 io.sort.factor(默认 10)个文件,并将产生的文件重新加入待合并列表中,对文件排序后,重复以上过程,直到最终得到一个大文件。
让每个 MapTask 最终只生成一个数据文件,可避免同时打开大量文件和同时读取大量
小文件产生的随机读取带来的开销。
7.2 ReduceTask 工作机制
1)Copy阶段: ReduceTask 从各个 MapTask 上远程拷贝一片数据,并针对某一片数据,如果其大小超过一定阈值,则写到磁盘上,否则直接放到内存中。
2)Merge阶段: 在远程拷贝数据的同时,ReduceTask 启动了两个后台线程对内存和磁盘上的文件进行合并,以防止内存使用过多或磁盘上文件过多。
3)Sort阶段: 按照 MapReduce 语义,用户编写 reduce()函数输入数据是按 key 进行聚集的一组数据。为了将 key 相同的数据聚在一起,Hadoop 采用了基于排序的策略。由于各个 MapTask 已经实现对自己的处理结果进行了局部排序,因此,ReduceTask 只需对所有数据进行一次归并排序即可。
4)Reduce阶段: reduce()函数将计算结果写到 HDFS 上。
7.3 设置 ReduceTask 并行度(个数)
ReduceTask 的并行度同样影响整个 Job 的执行并发度和执行效率,但与 MapTask 的并
发数由切片数决定不同,ReduceTask 数量的决定是可以直接手动设置:
// 默认值是 1,手动设置为 4
job.setNumReduceTasks(4);
8.MapReduce中的Shuffle机制
Map方法之后,Reduce方法之前的数据处理过程称之为Shuffle。
分区、排序、溢写、然后拷贝到对应Reduce机器上,可以选择增加Combiner,压缩溢写的文件。
combiner的作用:
combiner对每一个MapTask的输出进行局部汇总,以减小网络传输量。
combiner在每一个MapTask所在的节点运行;
reduce是接收全局所有map的输出结果。
9.Partition分区
1)将统计结果按照条件输出到不同分区中。
2)在没有自定义分区的情况下,数据被送到reduce端前如何分区?
根据默认的
HashPartitioner
,逻辑是根据
key
的哈希值和
numReduces
来返回一个分区号,
key.hashCode()
&
Integer.MAXVALUE % numReduces
3)自定义Partition分区步骤:
步骤1:自定义类继承Partitioner,重写getPartition()方法。
步骤2:在Job驱动中,设置自定义Partitioner。
步骤3:自定义Partitioner后,要根据自定义Partitioner的逻辑设置相应数量的ReduceTask。
10.Join多种应用
10.1 Reduce Join
10.2 Reduce Join 案例实操
10.3 Reduce Join缺点及解决方案
10.4 Map Join
1.使用场景
Map Join 适用于一张表十分小、一张表很大的场景。
2.优点
思考:在 Reduce 端处理过多的表,非常容易产生数据倾斜。怎么办?
在 Map 端缓存多张表,提前处理业务逻辑,这样增加 Map 端业务,减少 Reduce 端数据的压力,尽可能的减少数据倾斜
3.具体办法:采用 DistributedCache
(1)在 Mapper 的 setup 阶段,将文件读取到缓存集合中。
(2)在驱动函数中加载缓存。
// 缓存普通文件到 Task 运行节点。
job.addCacheFile(new URI("file://e:/cache/pd.txt"));
10.5 Map Join 案例实操
11.计数器应用
12.数据清洗(ETL)
在运行核心业务 MapReduce 程序之前,往往要先对数据进行清洗,清理掉不符合用户
要求的数据。清理的过程往往只需要运行 Mapper 程序,不需要运行 Reduce 程序。
Hadoop数据压缩
压缩的优缺点
优点:
减少磁盘I/O,减少磁盘存储空间
缺点:
增加CPU开销
压缩方式选择
压缩选择时应考虑:压缩/解压速度,压缩率,压缩后是否支持切片。
Gzip:压缩率高,不支持切片,压缩/解压速度一般。
Bzip2:压缩率高,支持切片,压缩/解压速度较慢。
Lzo:压缩/解压速度快,支持切片,压缩率一般。
Snappy:压缩和解压速度快,不支持切片,压缩速度一般。
Hadoop企业优化
1.MapReduce跑的慢的原因
MapReduce程序效率的瓶颈在于两点:
1 计算机性能
CPU、内存、磁盘健康、网络
2 I/O 操作优化
(1) 数据倾斜
(2) Map和Reduce数设置不合理
(3) Map运行时间太长,导致Reduce等待过久
(4) 小文件过多
(5) 大量的不可分块的超大文件
(6) Spill次数过多
(7) Merge次数过多等。
2.MapReduce 优化方法
MapReduce 优化方法主要从六个方面考虑:数据输入、Map 阶段、Reduce 阶段、IO 传
输、数据倾斜问题和常用的调优参数。
2.1 数据输入
(1)合并小文件: 在执行MR任务前将小文件进行合并,大量的小文件会产生大量的Map任务,增大Map任务装载次数,而任务的装载比较耗时,从而导致MR运行较慢。
(2)采用Combine TextInputFormat来作为输入,解决输入端大量小文件场景。
2.2 Map阶段
(1)减少溢写(Spill) 次数: 通过调整
io.sort.mb
及
sort.spill.percent
参数值,增大触发Spill的内存上限,减少Spill次数,从而减少磁盘IO。
(2)减少合并(Merge) 次数: 通过调整
io.sort.factor
参数, 增大Merge的文件数目,减少Merge的次数,从而缩短MR处理时间。
(3)在Map之后,不影响业务逻辑前提下,先进行Combine处理,减少I/O。
2.3 Reduce阶段
(1)合理设置Map和Reduce数: 两个都不能设置太少,也不能设置太多。太少,会导致Task等待,延长处理时间;太多,会导致Map、Reduce任务间竞争资源,造成处理超时等错误。
(2)设置Map、Reduce共存: 调整slowstart.completedmaps参数,使Map运行到一定程度后,Reduce也开始运行,减少Reduce的等待时间。
(3)规避使用Reduce: 因为Reduce在用于连接数据集的时候将会产生大量的网络消耗。
(4)合理设置Reduce端的Buffer: 默认情况下,数据达到一个阈值的时候,Buffer中的数据就会写入磁盘,然后Reduce会从磁盘中获得所有的数据。也就是说,Buffer和Reduce是没有直接关联的,中间多次写磁盘->读磁盘的过程,既然有这个弊端,那么就可以通过参数来配置,使得Buffer中的一部分数据可以直接输送到Reduce,从而减少IO开销:
**
mapreduce. reduce.input. buffer.percent
,默认为0.0。当值大于0的时候,会保留指定比例的内存读Buffer中的数据直接拿给Reduce使用。这样一来, 设置Buffer需要内存,读取数据需要内存,Reduce计算也要内存,所以要根据作业的运行情况进行调整。**
2.4 IO传输
(1)采用数据压缩的方式,减少网络IO的的时间。安装Snappy和LZO压缩编码器。
(2)使用SequenceFile二进制文件。
2.5 数据倾斜问题
2.5.1 数据倾斜的概念
数据倾斜这四个字经常会在学习MapReduce中遇到。所谓数据分区,就是数据分区分布因为数据本身或者分区方法的原因变得极为不一致,大量的数据被划分到了同一个区。由于Reducer Task每次处理一个区的数据,这导致Reducer Task处理有着大量数据的分区时任务繁重,而其他区分到的任务过于轻松,从而导致整体的任务效率大幅降低。
“一个人累死,其他人闲死”。
2.5.2 数据倾斜现象
(1)数据频率倾斜——某一个区域的数据量要远远大于其他区域。
比如:数据的key非常少,极少数的key中记录了非常多的记录值。这属于相同key分到同一个分区导致分区数据过多。
(2)数据大小倾斜——部分记录的大小远远大于平均值。
比如:数据的key比较多,但有某些key的记录值远远多于其他key,在分区的时候将有着大量记录值的key分到了同一个区。这属于不同key因为分区方法分到同一个区导致分区数据过多。
2.5.3 数据倾斜导致的结果
(1)大部分的Task运行速度很快,但是小部分Task运行速度很慢;
(2)原本能正常执行的Spark作业,某天突然爆出OOM(内存溢出)异常。 观察异常栈,是我们写的业务代码造成的。
2.5.4 减少数据倾斜的方法
方法1: 抽样和范围分区
可以通过对原始数据进行抽样得到的结果集来预设分区边界值。
方法2: 自定义分区
基于输出键的背景知识进行自定义分区。例如,如果Map输出键的单词来源于一本书。且其中某几个专业词汇较多。那么就可以自定义分区将这些专业词汇发送给固定的一部分Reduce实例。 而将其他的都发送给剩余的Reduce实例。
方法3: Combine
使用Combine可以大量地减小数据倾斜。在可能的情况下,Combine的目的就是聚合并精简数据。 Map阶段会将环形缓冲区的数据排序并溢写,在溢写之前,使用combiner将相同key数据进行合并(如累加)。这减轻了数据倾斜的现象,减轻了map端向reduce端发送的数据量(减轻了网络带宽),也减轻了map端和reduce端中间的shuffle阶段的数据拉取数量(本地化磁盘IO速率),推荐使用这种方法。
方法4: 采用Map Join,尽量避免Reduce Join
比如当一个大表Join小表的时候,可以将小表直接读到内存中,进行Map Join,省去了Shuffle阶段。
方法5: 通过加随机前缀重新设计key
聚合类型出现数据倾斜主要是使用group by、distinct造成的。
针对聚合类的数据倾斜,可以通过加随机前缀重新设计key。比如,我们可以在map阶段随机加上一个固定长度的随机数,使得分区的时候不会像之前那样分到同一个节点,完成一次局部聚合。在这之后将前缀去除,重新进行一次全局聚合即可。
--水果字段名为categoryselectcount(substr(x.category,1,2))from(select concat(category,'_',cast(round(10*rand())+1as string))from table1
groupby concat(category,'_',cast(round(10*rand())+1as string))) x --1阶段聚合groupby substr(x.category,1,2);--2阶段聚合
3.HDFS 小文件优化方法
3.1 HDFS 小文件弊端
HDFS 上每个文件都要在 NameNode 上建立一个索引,这个索引的大小约为 150byte,
这样当小文件比较多的时候,就会产生很多的索引文件,一方面会大量占用 NameNode 的内存空间,另一方面就是索引文件过大使得索引速度变慢。
3.2 HDFS 小文件解决方案
小文件的优化无非以下几种方式:
(1)在数据采集的时候,就将小文件或小批数据合成大文件再上传 HDFS。
(2)在业务处理之前,在 HDFS 上使用 MapReduce 程序对小文件进行合并。
(3)在 MapReduce 处理时,可采用 CombineTextInputFormat 提高效率。
(4)开启JVM重用
Yarn
1.什么是Yarn?
Yarn是一个资源调度平台,负责为运算程序提供服务器运算资源,相当于一个分布式的操作系统平台。
2.Yarn基本架构
YARN 主要由 ResourceManager、NodeManager、ApplicationMaster 和 Container 等组件构成,如下图:
1)ResourceManager:
处理客户请求;
监控NodeManager;
启动或者监控ApplicationMaster;
资源的分配与调度。
2)NodeManager:
管理单个节点上的资源;
处理来自ResourceManager的命令;
处理来自ApplicationMaster的命令。
3)ApplicationMaster:
负责数据的切分
为应用程序申请资源并分配给内部的任务;
任务的监控与容错。
4)Container:
Container是YARN中的资源抽象,它封装了某个节点上的多维度资源,如内存、CPU、 磁盘、网络等。
3.Yarn的调度器及调度算法
目前,Hadoop 作业调度器主要有三种:FIFO、Capacity Scheduler 和 Fair Scheduler。
Hadoop2.7.2 默认的资源调度器是 Capacity Scheduler。
(1)先进先出调度器(FIFO):单队列,根据提交作业的先后顺序,先来先服务
(2)容量调度器(Capacity Scheduler)默认:
支持多个队列,每个队列可配置一定的资源量,每个队列采用FIFO调度策略;
管理员为每个队列设置资源最低保证和资源使用上限;
如果一个队列中的资源有剩余,可以暂时共享给那些需要资源的队列,而一旦该队列有新的应用程序提交,则其他队列借调的资源会归还给该队列;
资源分配算法:
队列资源分配:从root开始,优先选择资源占用率最低的队列分配资源;
作业分配资源:默认按照提交作业的优先级和提交时间顺序分配资源;
容器资源分配:按照容器的优先级分配资源;
如果优先级相同,按照数据本地性原则:
任务和数据在同一节点上;
任务和数据在同一机架上;
任务和数据不在同一节点也不在同一机架上。
(3)公平调度器(Fair Scheduler): 支持多队列多用户,同队列所有任务共享资源,在时间尺度上获得公平的资源
比如有三个队列:qa,qb,qc,每个队列的job按照优先级分配资源,优先级越高分配的资源越多,但是每个job都会分配到资源以确保公平,
在资源有限的情况下,每个job理想情况下获得的计算资源与实际获得的计算资源存在一种差距,这个差距叫做缺额,
在同一个队列中,job的资源缺额越大,越先获得资源有限执行。作业是按照缺额的高低来先后执行的,而且可以看到上图中有多个作业同时运行。
版权归原作者 化身孤岛的鲸o 所有, 如有侵权,请联系我们删除。