Hadoop拾遗
一、Hadoop简介#
2003 年 Google 发表三篇论文也就是所谓的“三架马车”,分别是 《The Google File System》 《MapReduce: Simplified Data Processing on Large Clusters》 《Bigtable: A Distributed Storage System for Structured Data》,分别对应后来出现的 HDFS,MapReduce, HBase。
Hadoop是一个由Apache基金会所开发的分布式系统基础架构。Hadoop的框架最核心的设计就是:HDFS和MapReduce。HDFS为海量的数据提供了存储,而MapReduce则为海量的数据提供了计算。
二、Hadoop的进化史(针对MR)#
可以看出在2.x系列中多了一个组件yarn,后面的3.x版本(增加纠删码等高可用策略)在变动上并没有1.x到2.x的改变那么大和重要就不作过多介绍。
1、hadoop1.x#
JobTracker端:在1.x的MapReduce中JobTracker负责作业的分发、管理、调度,同时还必须和集群中的所有节点保持HeartBeat通信,了解机器的运行状态和资源情况。如果集群的数量和job的数量不断增加,那么JobTracker的任务量也会随之水涨船高,最终的结果就是导致JobTracker存在单点故障问题。
TaskTracker端:以 map/reduce task 的数目作为资源的表示过于简单,没有考虑到 cpu/ 内存的占用情况,如果两个大内存消耗的 task 被调度到了一块,很容易出现 OOM,那么就会导致作业的单点失败和作业整体时间等待过长。
2、hadoop2.x#
JobTracker端:设计思路是将JobTracker承担的两大块任务----集群资源管理和作业管理进行分离,
ResourceManager:全局的资源管理(资源管理和调度),根据功能不用将资源管理器分为调度器(Scheduler)和应用管理器(ApplicationManager)。调度器根据资源限制将资源分配给正在运行的应用。虽然被称为调度器,但是它仅仅负责资源的分而不负责监控应用程序的失败,或对失败的任务进行重启(ApplicationMaster负责)。
ApplicationMaster:作业管理,负责任务切分、任务调度、任务监控和容错等。每一个应用的 ApplicationMaster 是一个详细的框架库,它结合从 ResourceManager 获得的资源和 NodeManager 协同工作来运行和监控任务。
TaskTracker端:TaskTracker演化成节点管理器NodeManager
Node Manager:NodeManager是ResourceManager在每台机器的上代理,负责容器的管理,并监控他们的资源使用情况(cpu,内存,磁盘及网络等),以及向ResourceManager/Scheduler提供这些资源使用报告。
注意:每个 MapRduce 作业对应一个 ApplicationMaster 任务调度。
三、Hadoop优势(4高)#
高可靠性:Hadoop底层维护多个数据副本(DataNode),所以即使Hadoop某个计算元素或存储出现故障,也不会导致数据丢失。
高扩展性:在集群间分配任务数据,可方便扩展数以千计的节点。
高效性:在MapReduce的思想下,Hadoop是并行工作的,以加快任务的处理速度。
高容错性:能自动将失败的任务重新分配到其他节点。
四、Hadoop作业执行流程#
(1)作业提交#
第 1 步:client 向整个集群提交job,向 ResourceManager 申请一个jobid。
第 2 步:ResourceManager 给 client 返回该 job 资源的提交路径和作业 id。
第 3 步:client 提交 jar 包、切片信息和配置文件到指定的资源提交路径。
第 4 步:client 提交完资源后,向 ResourceManager 申请运行 MrAppMaster。
(2)作业初始化#
第 5 步:当 ResourceManager 收到 client 的请求后,将该 job 添加到容量调度器(ResourceScheduler)中。
第 6 步:调度器会将任务放在调度队列种,当执行到相应的请求时,某一个空闲的 NodeManager 领取到该 job。
第 7 步:该 NodeManager 创建 Container,并产生 MRAppmaster。
第 8 步:MRAppmaster获取hdf上提交的文件,根据切片信息创建Maptask和Ruducetask。
(3)任务分配#
第 9 步:MrAppMaster 向 ResourceManager 申请运行多个 maptask 任务资源。
第 10 步 :ResourceManager将运行 maptask 任务分配给另外两个 NodeManager,另两个 NodeManager
分别领取任务并创建容器。
(4)任务运行#
第 11 步:MrAppMaster向两个接收到任务的 NodeManager 发送程序启动脚本,这两个NodeManager 分别启动 maptask,maptask 对数据分区排序。
第 12 步:MrAppMaster 等待所有 maptask 运行完毕后,向 ResourceManager 申请容器,运行 reduce task。
第 13 步:reduce task 向 maptask 获取相应分区的数据。
第 14 步:程序运行完毕后,MrAppMaster 会向 ResourceManager 申请注销自己。
(5)进度和状态更新#
YARN 中的任务将其进度和状态(包括 counter)返回给应用管理器, 客户端每秒(通过
mapreduce.client.progressmonitor.pollinterval 设置)向应用管理器请求进度更新, 展示给用户。
(6)作业完成#
除了向应用管理器请求作业进度外, 客户端每 5 分钟都会通过调用 waitForCompletion()
来检查作业是否完成。时间间隔可以通过 mapreduce.client.completion.pollinterval 来设置。作
业完成之后, 应用管理器和 container 会清理工作状态。作业的信息会被作业历史服务器存储
五、Hadoop集群搭建#
【大数据环境搭建(三)】在Centos7上搭建Hadoop集群(完全分布式)_Feng-licong的博客-CSDN博客_hadoop集群搭建centos
常用端口:
hdfs的web管理界面:
Yarn的web管理界面:
六、集群基本操作命令#
1、启动集群#
全启动:start-all.sh
分模块启动:
(1)整体启动/停止HDFS
start-dfs.sh/stop-dfs.sh
(2)整体启动/停止YARN
start-yarn.sh/stop-yarn.sh、
分组件启动:
(1)分别启动/停止HDFS组件
hdfs --daemon start/stop namenode/datanode/secondarynamenode
(2)启动/停止YARN
yarn --daemon start/stop resourcemanager/nodemanager
2、文件增删改#
(1)从本地剪切粘贴到HDFS:
hadoop fs -moveFromLocal ./shuguo.txt /sanguo
(2)从本地文件系统中拷贝文件到HDFS路径去:
hadoop fs -copyFromLocal weiguo.txt /sanguo
hadoop fs -put ./wuguo.txt /sanguo(等同于copyFromLocal,生产环境更习惯用put)
(3)追加一个文件到已经存在的文件末尾:
hadoop fs -appendToFile liubei.txt /sanguo/shuguo.txt
(4)从HDFS拷贝到本地:
hadoop fs -copyToLocal /sanguo/shuguo.txt ./
hadoop fs -get /sanguo/shuguo.txt ./shuguo2.txt(等同于copyToLocal,生产环境更习惯用get)
3、HDFS直接操作#
(1)-ls: 显示目录信息
hadoop fs -ls /sanguo
(2)-cat:显示文件内容
hadoop fs -cat /sanguo/shuguo.txt
(3)-chgrp、-chmod、-chown:Linux文件系统中的用法一样,修改文件所属权限
hadoop fs -chmod 666 /sanguo/shuguo.txt
hadoop fs -chown root:root /sanguo/shuguo.txt
(4)-mkdir:创建路径
hadoop fs -mkdir /jinguo
(5)-cp:从HDFS的一个路径拷贝到HDFS的另一个路径
hadoop fs -cp /sanguo/shuguo.txt /jinguo
(6)-mv:在HDFS目录中移动文件
hadoop fs -mv /sanguo/wuguo.txt /jinguo
hadoop fs -mv /sanguo/weiguo.txt /jinguo
(7)-tail:显示一个文件的末尾1kb的数据
hadoop fs -tail /jinguo/shuguo.txt
(8)-rm:删除文件或文件夹
hadoop fs -rm /sanguo/shuguo.txt
(9)-rm -r:递归删除目录及目录里面内容
hadoop fs -rm -r /sanguo
(10)-du统计文件夹的大小信息
hadoop fs -du -s -h /jinguo
27 81 /jinguo
说明:27表示文件大小;81表示27*3个副本;/jinguo表示查看的目录
(11)-setrep:设置HDFS中文件的副本数量
hadoop fs -setrep 10 /jinguo/shuguo.txt
这里设置的副本数只是记录在NameNode的元数据中,是否真的会有这么多副本,还得看DataNode的数量,如果只有3台设备,最多也就3个副本,只有节点数的增加到10台时,副本数才能达到10。
4、提交job执行程序#
[root@hadoop102 hadoop-3.1.3]$ hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount /input /output
七、HDFS的API操作(JAVA)#
HDFS入门(三)-- HDFS的API操作(图文详解步骤2021)_Leokadia Rothschild的博客-CSDN博客_hdfs的api操作
八、Hadoop模块详解#
1、HDFS#
(1)HDFS组件介绍#
1.NameNode(NN):存储文件的元数据,如:文件名,文件目录结构,文件属性,以及每个文件的块列表和块所在的DataNode等
2.DataNode(DN):在本地文件系统存储文件的块数据,以及块数据的校验和。
3.Secondary NameNode(2NN):每隔一段时间对NameNode进行元数据的备份。
4.Client:就是客户端,负责文件的切分,将文件切分为大小相同的物理块(Block)分布式存储在DataNode中。与NameNode进行交互,获取文件的位置信息,与DataNode进行交互,读取或者写入文件。
HDFS是Hadoop架构中的负责完成数据的分布式存储管理的文件系统。非高可用HDFS集群工作的时候会启动三个服务,分别是NameNode 和 DataNode以及SecondaryNameNode 。其中NameNode是HDFS的中心服务,主要维护管理文件系统中的文件的元数据信息,DataNode主要负责存储文件的真实数据块信息,当然在DataNode的数据块信息中也包含一下关于当前数据块的元数据信息 例如 检验值 数据长度 时间戳等。在非高可用HDFS集群中NameNode和DataNode可以理解为是一对多的关系。二者在集群工作中也要保持通信,通常默认3秒钟会检测一下心跳。最后SecondaryNameNode的工作很单一,就是为了给NameNode的元数据印象文件和编辑日志进行合并,并自己也保留一份元数据信息 以防NameNode元数据丢失后有恢复的保障。
DataNode工作机制:
(1)一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
(2)DataNode启动后向NameNode注册,通过后,周期性(6小时)的向NameNode上报所有的块信息。
DN向NN汇报当前解读信息的时间间隔,默认6小时;
DN扫描自己节点块信息列表的时间,默认6小时
Support multiple time unit suffix(case insensitive), as described
in dfs.heartbeat.interval.
(3)心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用。
(2)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步)。
(3)HDFS读数据流程#
(1)客户端通过DistributedFileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。
(2)挑选一台DataNode(结合网络拓扑原理和就近原则,然后随机)服务器,请求读取数据。
(3)DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。
(4)客户端以Packet为单位接收,先在本地缓存,然后写入目标文件。
(4)Secondary NameNode工作机制#
首先,我们做个假设,如果存储在NameNode节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低。因此,元数据需要存放在内存中。但如果只存在内存中,一旦断电,元数据丢失,整个集群就无法工作了。因此产生在磁盘中备份元数据的FsImage。
这样又会带来新的问题,当在内存中的元数据更新时,如果同时更新FsImage,就会导致效率过低,但如果不更新,就会发生一致性问题,一旦NameNode节点断电,就会产生数据丢失。因此,引入Edits文件(只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits中。这样,一旦NameNode节点断电,可以通过FsImage和Edits的合并,合成元数据。
但是,如果长时间添加数据到Edits中,会导致该文件数据过大,效率降低,而且一旦断电,恢复元数据需要的时间过长。因此,需要定期进行FsImage和Edits的合并,如果这个操作由NameNode节点完成,又会效率过低。因此,引入一个新的节点SecondaryNamenode,专门用于FsImage和Edits的合并。
1)第一阶段:NameNode启动
(1)第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
(2)客户端对元数据进行增删改的请求。
(3)NameNode记录操作日志,更新滚动日志。
(4)NameNode在内存中对元数据进行增删改。
2)第二阶段: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。
(5)HDFS的容错机制#
HDFS 容错指的是集群部分机器宕机了,集群依然可以正常提供服务的能力。HDFS 是具有很好的容错性的分布式存储系统,它利用复制技术实现数据容错能力,数据会被复制多份并存储在集群的不同节点。这样,集群中的某些机器宕机了,数据还可以从其他正常运行的机器获取。如果有一个机器宕机了,HDFS 会在其他可用的机器创建数据的副本,来保证该数据的副本数与集群的副本因子是一致的。
HDFS 通过复制进程来保证容错机制。在文件写入 HDFS 时,HDFS 会首先把文件分割成块,并把这些数据块存储在集群不同机器上,然后在其他机器创建各个块的副本,默认情况下,HDFS 会在其他机器创建3个文件的副本。所以,HDFS 集群任意机器挂了,我们依然能从其他保存数据副本的机器上读取数据,由于这种独特的分布式存储特性,HDFS 给我们提供了更快的文件读写机制。
(6)HDFS的存储机制#
\1. HDFS开创性地设计出一套文件存储方式。即对文件切割后分别存放;
\2. HDFS将要存储的大文件进行切割,切割后存放在既定的存储块(Block)中,并通过预先设定的优化处理,模式对存储的数据进行预处理,从而攻克了大文件储存与计算的需求。
(7)HDFS的副本机制#
HDFS上的文件对应的 Block保存多个副本,且提供容错机制,副本丢失或宕机自动恢复。默认存3份副本。
第一副本:放置在上传文件的 DataNode上;如果是集群外提交,则随机挑选一台磁盘不太慢、CPU不太忙的节点
第二副本:放置在与第一个副本不同的机架的节点上
第三副本:与第二个副本相同机架的不同节点上。
如果还有更多的副本:随机放在节点中。
(8)HDFS的Block#
1、HDFS中的文件在物理上是分块存储(Block),块的大小可以通过配置参数(dfs.blocksize)来规定,默认的大小是128M。
HDFS块大小设置与磁盘的传输速度紧密相关。寻址时间为传输时间的百分之一时,为最佳的状态。一般的寻址时间约为10ms,则传输时间约为1s,而目前磁盘的传输速度普遍为100MB/s,所以将Block的大小设置为128M最为合理,当然,随着磁盘的传输速度的提升,可以适当调整Block的大小。
2、块的大小不能设置太小,也不能设置太大:
HDFS的块设置太小,寻址时间的比例增加,程序花费大量的时间用来进行寻址操作
HDFS的块设置太大,磁盘传输数据的时间明显大于定位时间(传输的块中的数据不一定全部都需要),导致程序在处理这块数据时,会变得非常慢。
总结:HDFS块的大小设置主要取决于磁盘的传输速率。
(9)HDFS的分片#
hadoop 的作业在提交过程中,需要把具体的输入进行分片。具体的分片细节由InputSplitFormat 指定。分片的规则为 FileInputFormat.class 中的getSplits()方法指定:
long splitSize = computeSplitSize(goalSi***Size, blockSize);
computeSplitSize:
Math.max(minSize, Math.min(goalSize, blockSize));
其中 goalSize 为“InputFile 大小”/“我们在配置文件中定义的 mapred.map.tasks”值,minsize 为 mapred.min.split.size,blockSize 为 64,所以,这个算式为取分片大小不大于 block,并且不小于在 mapred.min.split.size 配置中定义的最小 Size。
当某个分块分成均等的若干分片时,会有最后一个分片大小小于定义的分片大小,则该分片独立成为一个分片。
数据块:Block是HDFS物理上把数据分成一块一块。数据块是HDFS存储数据单位。
数据切片:数据切片只是在逻辑上对输入进行分片,并不会在磁盘上将其切分成片进行存储。数据切片是MapReduce程序计算输入数据的单位,一个切片会对应启动一个MapTask。
(10)HDFS的mapper和reducer的个数确定#
Mapper数量确定:数据切片只是在逻辑上对输入进行分片,并不会在磁盘上将其切分成片进行存储。数据切片是 MapReduce 程序计算输入数据的单位,一个切片会对应启动一个MapTask,所以只能通过设定分片的大小间接调整mapper的个数。
Reducer的个数可以由用户独立设置的,在默认情况下只有一个Reducer。 它的个数既可以使用命令行参数设置(mapreduce.job.reduces=number),也可以在程序中制定(job.setNumReduceTasks(number))。
(11)HDFS的高可用(HA)#
有时间再研究
2、MapReduce#
(1)常用的序列化类型#
(2)MapReduce工作流程#
map阶段:
reduce阶段:
map(分区)->collect(采集到环形缓冲区)->sort(在环形缓冲区快排)->spill(将内存中的数据溢写到环形缓冲区)->merge(归并排序)->copy(jetty网络框架将map的输出拉取到reduce端)->mergeSort(归并排序与map端类似)->reduce
压缩:
(1)map输入端主要考虑数据量大小和切片,支持切片的有Bzip2、LZO。注意:LZO要想支持切片必须创建索引;
(2)map输出端主要考虑速度,速度快的snappy、LZO;
(3)reduce输出端主要看具体需求,例如作为下一个mr输入需要考虑切片,永久保存考虑压缩率比较大的gzip。
(3)MapReduce中的三次排序#
mr在Map任务和Reduce任务的过程中,一共发生了3次排序
1)当map函数产生输出时,会首先写入内存的环形缓冲区,当达到设定的阀值,在刷写磁盘之前,后台线程会将缓冲区的数据划分成相应的分区。在每个分区中,后台线程按键进行内排序
2)在Map任务完成之前,磁盘上存在多个已经分好区,并排好序的,大小和缓冲区一样的溢写文件,这时溢写文件将被合并成一个已分区且已排序的输出文件。由于溢写文件已经经过第一次排序,所有合并文件只需要再做一次排序即可使输出文件整体有序。
3)在reduce阶段,需要将多个Map任务的输出文件copy到ReduceTask中后合并,由于经过第二次排序,所以合并文件时只需再做一次排序即可使输出文件整体有序
在这3次排序中第一次是内存缓冲区做的内排序,使用的算法使快速排序,第二次排序和第三次排序都是在文件合并阶段发生的,使用的是归并排序。
(4)环形缓冲区(如只是应用了解即可)#
环形缓冲区分为三块,空闲区、数据区、索引区。初始位置取名叫做“赤道”,就是圆环上的白线那个位置。初始状态的时候,数据和索引都为0,所有空间都是空闲状态。数据是从赤道的右边开始写入,索引(每次申请4kb)是从赤道是左边开始写,两个文件是独立的,执行期间互不干涉。
在数据和索引的大小到了mapreduce.map.sort.spill.percent参数设置的比例时(默认80%,这个是调优的参数),会有两个动作:
1、对写入的数据进行原地排序,并把排序好的数据和索引spill到磁盘上去;
2、在空闲的20%区域中,重新算一个新的赤道,然后在新赤道的右边写入数据,左边写入索引;
3、当20%写满了,但是上一次80%的数据还没写到磁盘的时候,程序就会panding一下,等80%空间腾出来之后再继续写。
如此循环往复,永不停歇,直到所有任务全部结束。整个操作都在内存,形状像一个环,所以才叫环形缓冲区。
环形缓冲区不需要重新申请新的内存,始终用的都是这个内存空间。大家知道MR是用java写的,而Java有一个最讨厌的机制就是Full GC。Full GC总是会出来捣乱,这个bug也非常隐蔽,发现了也不好处理。环形缓冲区从头到尾都在用那一个内存,不断重复利用,因此完美的规避了Full GC导致的各种问题,同时也规避了频繁申请内存引发的其他问题。
另外呢,环形缓冲区同时做了两件事情:1、排序;2、索引。在这里一次排序,将无序的数据变为有序,写磁盘的时候顺序写,读数据的时候顺序读,效率高非常多!
(5)MapReduce程序简单demo(WordCount)#
大致思路是将hdfs上的文本作为输入,MapReduce通过InputFormat会将文本进行切片处理,并将每行的首字母相对于文本文件的首地址的偏移量作为输入键值对的key,文本内容作为输入键值对的value,经过在map函数处理,输出中间结果<word,1>的形式,并在reduce函数中完成对每个单词的词频统计。整个程序代码主要包括两部分:Mapper部分和Reducer部分。
java版本
暂时无法在文档外展示此内容
python版本
暂时无法在文档外展示此内容
暂时无法在文档外展示此内容
把我们的代码放到Hadoop上运行,由于Hadoop是java编写的,运行时需要导入程序的jar包才行,正常情况下,可以用ieda自带的打包工具打包写好的java代码。然而用python编写的,怎么办呢?这个时候就需要用到Hadoop自带的工具streaming了,它可以自动帮我们将标准输入输出流串起来。且streaming.jar是Hadoop可运行的。首先cd到Hadoop-streaming-2.7.4.jar所在目录。然后运行以下指令(注意其中的程序路径需要根据自己情况修改):
$ hadoop jar hadoop-streaming-2.7.5.jar -input ./src.txt -output ./testout3 -mapper "python map.py" -reducer "python reduce.py" -file ~/test/map -file ~/test/reduce.py
(7)MapReduce的排序与合并#
1、按条件将不同的统计结果输出到不同文件需要继承Partitioner类(将不同手机号输出到不同文件)
public class ProvincePartitioner extends Partitioner<Text, FlowBean> {
@Override
public int getPartition(Text text, FlowBean flowBean, int numPartitions) {
//获取手机号前三位prePhone
String phone = text.toString();
String prePhone = phone.substring(0, 3);
//定义一个分区号变量partition,根据prePhone设置分区号
int partition;
if("136".equals(prePhone)){
partition = 0;
}else if("137".equals(prePhone)){
partition = 1;
}else if("138".equals(prePhone)){
partition = 2;
}else if("139".equals(prePhone)){
partition = 3;
}else {
partition = 4;
}
//最后返回分区号partition
return partition;
}
}
2、全局排序:bean对象做为key传输,需要实现WritableComparable接口重写compareTo方法,就可以实现排序。
@Override
public int compareTo(FlowBean bean) {
int result;
// 按照总流量大小,倒序排列
if (this.sumFlow > bean.getSumFlow()) {
result = -1;
}else if (this.sumFlow < bean.getSumFlow()) {
result = 1;
}else {
result = 0;
}
return result;
}
3、分区内排序:
4、Combiner合并:统计过程中对每一个MapTask的输出进行局部汇总,以减小网络传输量即采用Combiner功能,自定义一个Combiner继承Reducer,重写Reduce方法。
public class WordCountCombiner extends Reducer<Text, IntWritable, Text, IntWritable> {
private IntWritable outV = new IntWritable();
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable value : values) {
sum += value.get();
}
outV.set(sum);
context.write(key,outV);
}
}
(8)ReduceJoin & MapJoin#
ReduceJoin:Map端的主要工作:为来自不同表或文件的key/value对,打标签以区别不同来源的记录。然后用连接字段作为key,其余部分和新加的标志作为value,最后进行输出。
Reduce端的主要工作:在Reduce端以连接字段作为key的分组已经完成,我们只需要在每一个分组当中将那些来源于不同文件的记录(在Map阶段已经打标志)分开,最后进行合并就ok了。
将相同pid分到同一分组中,遍历集合orderBeans,替换掉每个orderBean的pid为pname,然后写出
MapJoin:在map端进行上面的Join操作
3、YARN#
(1)YARN组件介绍#
ResourceManager(RM):
1.处理客户端的请求
2.监控NodeManager
3.启动或者监控ApplicationMaster
NodeManager(NM):
1.管理单个节点上的资源
2.处理来自ResourceManager的命令
3.处理来自ApplicationManager的命令
4.资源分配和调度
ApplicationMaster(AM):
1.负责数据的切分
2.为应用程序申请资源并分配内部的任务。
3.任务的监控和容错
Container:
YARN中资源的抽象,封装了本地节点的多维度资源。如:内存、CPU、磁盘、网络等
(2)Yarn调度器和调度算法#
目前,Hadoop作业调度器主要有三种:FIFO、容量(Capacity Scheduler)和公平(Fair Scheduler)。Apache Hadoop3.1.3默认的资源调度器是Capacity Scheduler。
FIFO调度器(First In First Out):单队列,根据提交作业的先后顺序,先来先服务。
容量(Capacity Scheduler):计算每个队列中正在运行的任务数与其应该分得地资源之间地比值,选择比值最小的队列。
公平(Fair Scheduler):
(3)YARN容错机制#
ApplicationMaster容错:RM监控AM的运行状态,一旦发现它运行失败或者超时,就会重新分配资源并启动它,启动之后AM内部的状态如何恢复由自己保证,比如MRAppMaster在作业运行过程中将状态信息动态记录到HDFS上,一旦出现故障重启后,它能够从HDFS读取并恢复之前的运行状态,减少重复计算带来的开销。
NodeManager容错:NM超时没有心跳,则RM认为它死掉,会将上面的Container状态置为失败,并告诉对应的ApplicationMaster,以决定如何处理这些Container中运行的任务
Container容错:如果AM在一定时间内未启动分配到的Container,则RM会将该Container状态置为失败并回收它;如果一个Container在运行过充中,因为外界原因导致运行失败,则RM会转告对应的AM,由AM决定如何处理
RM容错:YARN将共享存储系统抽象为RMStateStore(一个Java接口),以保存恢复RM所必须的信息,RM提供了四种RMStateStore实现:
1)NullRMStateStore(不存储任何状态信息,在不启用恢复机制时,它是默认实现的)
2)MemoryRMStateStore(将状态信息保存到内存中,启用恢复机制时,它是默认实现的)
3)FileSystemRMStateStore(状态信息保存到HDFS中)
4)ZKRMStateStore(状态信息保存到ZK上)
YARN HA采用基于ZKRMStateStore的共享存储方案。
(4)YARN高可用#
九、拓展#
1、MapReduce压缩方式比较#
Gzip压缩#
■ 优点:压缩率比较高,并且压缩/解压的速度比较快,(压缩率第二,解压缩速率倒数第二)
■ 缺点:不支持对文件Split(切分)
Bzip2压缩#
■ 优点:支持对文件进行Split;具有很高的压缩率,比Gzip压缩率都高(压缩率第一,解压缩速率倒数第一)
■ 缺点:压缩/解压速度慢
Lzo压缩#
■ 优点:合理的压缩率,压缩/解压速度比较快,支持Split,是Hadoop中最流行的压缩格式。
■ 缺点:压缩率比Gzip要低一些,Hadoop本身不支持,需要单独安装
Snappy压缩#
■ 优点:高速的压缩速度和合理的压缩率
■ 缺点:不支持Split,压缩率比Gzip要低,Hadoop本省也不支持,需要单独安装。
2、调优#
(1)NameNode内存生产配置#
具体修改:hadoop-env.sh
export HDFS_NAMENODE_OPTS="-Dhadoop.security.logger=INFO,RFAS -Xmx1024m"
export HDFS_DATANODE_OPTS="-Dhadoop.security.logger=ERROR,RFAS -Xmx1024m"
(2)NameNode心跳并发配置#
NameNode有一个工作线程池,用来处理不同DataNode的并发心跳以及客户端并发的元数据操作。
对于大集群或者有大量客户端的集群来说,通常需要增大该参数。默认值是10。
(3)开启回收站配置#
开启回收站功能,可以将删除的文件在不超时的情况下,恢复原数据,起到防止误删除、备份等作用。
开启回收站功能参数说明:
(1)默认值fs.trash.interval = 0,0表示禁用回收站;其他值表示设置文件的存活时间。
(2)默认值fs.trash.checkpoint.interval = 0,检查回收站的间隔时间。如果该值为0,则该值设置和fs.trash.interval的参数值相等。
(3)要求fs.trash.checkpoint.interval <= fs.trash.interval。
启用回收站:
修改core-site.xml,配置垃圾回收时间为1分钟。
(4)HDFS—集群压测#
测试内容:向HDFS集群写10个128M的文件
[root@hadoop102 mapreduce]$ hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.1.3-tests.jar TestDFSIO -write -nrFiles 10 -fileSize 128MB
2021-02-09 10:43:16,853 INFO fs.TestDFSIO: ----- TestDFSIO ----- : write
2021-02-09 10:43:16,854 INFO fs.TestDFSIO: Date & time: Tue Feb 09 10:43:16 CST 2021
2021-02-09 10:43:16,854 INFO fs.TestDFSIO: Number of files: 10
2021-02-09 10:43:16,854 INFO fs.TestDFSIO: Total MBytes processed: 1280
2021-02-09 10:43:16,854 INFO fs.TestDFSIO: Throughput mb/sec: 1.61
2021-02-09 10:43:16,854 INFO fs.TestDFSIO: Average IO rate mb/sec: 1.9
2021-02-09 10:43:16,854 INFO fs.TestDFSIO: IO rate std deviation: 0.76
2021-02-09 10:43:16,854 INFO fs.TestDFSIO: Test exec time sec: 133.05
2021-02-09 10:43:16,854 INFO fs.TestDFSIO:
Number of files:生成mapTask数量,一般是集群中(CPU核数-1),我们测试虚拟机就按照实际的物理内存-1分配即可
Total MBytes processed:单个map处理的文件大小
Throughput mb/sec:单个mapTak的吞吐量
计算方式:处理的总文件大小/每一个mapTask写数据的时间累加
集群整体吞吐量:生成mapTask数量*单个mapTak的吞吐量
Average IO rate mb/sec::平均mapTak的吞吐量
计算方式:每个mapTask处理文件大小/每一个mapTask写数据的时间
全部相加除以task数量
IO rate std deviation:方差、反映各个mapTask处理的差值,越小越均
如:
一共参与测试的文件:10个文件 * 2个副本 = 20个
压测后的速度:1.61
实测速度:1.61M/s * 20个文件 ≈ 32M/s
三台服务器的带宽:12.5 + 12.5 + 12.5 ≈ 30m/s
所有网络资源都已经用满。
如果实测速度远远小于网络,并且实测速度不能满足工作需求,可以考虑采用固态硬盘或者增加磁盘个数。
(5)NameNode多目录配置#
NameNode的本地目录可以配置成多个,且每个目录存放内容相同,增加了可靠性
在hdfs-site.xml文件中添加如下内容
(6)添加白名单#
白名单:表示在白名单的主机IP地址可以,用来存储数据。
企业中:配置白名单,可以尽量防止黑客恶意访问攻击。
[root@hadoop102 hadoop]$ vim whitelist
在whitelist中添加如下主机名称,假如集群正常工作的节点为102 103
hadoop102
hadoop103
在hdfs-site.xml配置文件中增加dfs.hosts配置参数
(7)服役新服务器#
随着公司业务的增长,数据量越来越大,原有的数据节点的容量已经不能满足存储数据的需求,需要在原有集群基础上动态添加新的数据节点。
先要准备新的节点
服役新节点具体步骤
(1)直接启动DataNode,即可关联到集群
[root@hadoop105 hadoop-3.1.3]$ hdfs --daemon start datanode
[root@hadoop105 hadoop-3.1.3]$ yarn --daemon start nodemanager
在白名单中增加新服役的服务器
(1)在白名单whitelist中增加hadoop104、hadoop105,并重启集群
[root@hadoop102 hadoop]$ vim whitelist
修改为如下内容
hadoop102
hadoop103
hadoop104
hadoop105
(2)分发
[root@hadoop102 hadoop]$ xsync whitelist
(3)刷新NameNode
[root@hadoop102 hadoop-3.1.3]$ hdfs dfsadmin -refreshNodes
Refresh nodes successful
(8)集群负载均衡#
在企业开发中,如果经常在hadoop102和hadoop104上提交任务,且副本数为2,由于数据本地性原则,就会导致hadoop102和hadoop104数据过多,hadoop103存储的数据量小。
另一种情况,就是新服役的服务器数据量比较少,需要执行集群均衡命令。
开启数据均衡命令:
[root@hadoop105 hadoop-3.1.3]$ sbin/start-balancer.sh -threshold 10
(9)HDFS存储优化之纠删码#
纠删码原理
HDFS默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。Hadoop3.x引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。
纠删码策略
RS-3-2-1024k:使用RS编码,每3个数据单元,生成2个校验单元,共5个单元,也就是说:这5个单元中,只要有任意的3个单元存在(不管是数据单元还是校验单元,只要总数=3),就可以得到原始数据
具体步骤
(1)开启对RS-3-2-1024k策略的支持
[root@hadoop102 hadoop-3.1.3]$ hdfs ec -enablePolicy -policy RS-3-2-1024k
Erasure coding policy RS-3-2-1024k is enabled
(2)在HDFS创建目录,并设置RS-3-2-1024k策略
[root@hadoop102 hadoop-3.1.3]$ hdfs dfs -mkdir /input
[root@hadoop202 hadoop-3.1.3]$ hdfs ec -setPolicy -path /input -policy RS-3-2-1024k
(3)上传文件,并查看文件编码后的存储情况
[root@hadoop102 hadoop-3.1.3]$ hdfs dfs -put web.log /input
注:你所上传的文件需要大于2M才能看出效果。(低于2M,只有一个数据单元和两个校验单元)
(4)查看存储路径的数据单元和校验单元,并作破坏实验
(9)异构存储(冷热数据分离)#
异构存储主要解决,不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。
(10)小文件归档#
每个文件均按块存储,每个块的元数据存储在NameNode的内存中,因此HDFS存储小文件会非常低效。因为大量的小文件会耗尽NameNode中的大部分内存。但注意,存储小文件所需要的磁盘容量和数据块的大小无关。例如,一个1MB的文件设置为128MB的块存储,实际使用的是1MB的磁盘空间,而不是128MB。
HDFS存档文件或HAR文件,是一个更高效的文件存档工具,它将文件存入HDFS块,在减少NameNode内存使用的同时,允许对文件进行透明的访问。具体说来,HDFS存档文件对内还是一个一个独立文件,对NameNode而言却是一个整体,减少了NameNode的内存。
案例实操
(1)需要启动YARN进程
[root@hadoop102 hadoop-3.1.3]$ start-yarn.sh
(2)归档文件
把/input目录里面的所有文件归档成一个叫input.har的归档文件,并把归档后文件存储到/output路径下。
[root@hadoop102 hadoop-3.1.3]$ hadoop archive -archiveName input.har -p /input /output
(3)查看归档
[root@hadoop102 hadoop-3.1.3]$ hadoop fs -ls /output/input.har
[root@hadoop102 hadoop-3.1.3]$ hadoop fs -ls har:///output/input.har
(4)解归档文件
[root@hadoop102 hadoop-3.1.3]$ hadoop fs -cp har:///output/input.har/* /
(11)Hadoop-Yarn生产经验#
(1)Resourcemanager相关
yarn.resourcemanager.scheduler.client.thread-count ResourceManager处理调度器请求的线程数量
yarn.resourcemanager.scheduler.class 配置调度器
(2)Nodemanager相关
yarn.nodemanager.resource.memory-mb NodeManager使用内存数
yarn.nodemanager.resource.system-reserved-memory-mb NodeManager为系统保留多少内存,和上一个参数二者取一即可
yarn.nodemanager.resource.cpu-vcores NodeManager使用CPU核数
yarn.nodemanager.resource.count-logical-processors-as-cores 是否将虚拟核数当作CPU核数
yarn.nodemanager.resource.pcores-vcores-multiplier 虚拟核数和物理核数乘数,例如:4核8线程,该参数就应设为2
yarn.nodemanager.resource.detect-hardware-capabilities 是否让yarn自己检测硬件进行配置
yarn.nodemanager.pmem-check-enabled 是否开启物理内存检查限制container
yarn.nodemanager.vmem-check-enabled 是否开启虚拟内存检查限制container
yarn.nodemanager.vmem-pmem-ratio 虚拟内存物理内存比例
(3)Container容器相关
yarn.scheduler.minimum-allocation-mb 容器最小内存
yarn.scheduler.maximum-allocation-mb 容器最大内存
yarn.scheduler.minimum-allocation-vcores 容器最小核数
yarn.scheduler.maximum-allocation-vcores 容器最大核数
(12)Hadoop小文件解决方案#
开启uber模式,实现JVM重用(计算方向)
默认情况下,每个Task任务都需要启动一个JVM来运行,如果Task任务计算的数据量很小,我们可以让同一个Job的多个Task运行在一个JVM中,不必为每个Task都开启一个JVM。
开启uber模式,在mapred-site.xml中添加如下配置
<!-- 开启uber模式,默认关闭 -->
<property>
<name>mapreduce.job.ubertask.enable</name>
<value>true</value>
</property>
<!-- uber模式中最大的mapTask数量,可向下修改 -->
<property>
<name>mapreduce.job.ubertask.maxmaps</name>
<value>9</value>
</property>
<!-- uber模式中最大的reduce数量,可向下修改 -->
<property>
<name>mapreduce.job.ubertask.maxreduces</name>
<value>1</value>
</property>
<!-- uber模式中最大的输入数据量,默认使用dfs.blocksize 的值,可向下修改 -->
<property>
<name>mapreduce.job.ubertask.maxbytes</name>
<value></value>
</property>
(13)HDFS参数调优#
(1)修改:hadoop-env.sh
export HDFS_NAMENODE_OPTS="-Dhadoop.security.logger=INFO,RFAS -Xmx1024m"
export HDFS_DATANODE_OPTS="-Dhadoop.security.logger=ERROR,RFAS -Xmx1024m"
(2)修改hdfs-site.xml
<!-- NameNode有一个工作线程池,默认值是10 -->
<property>
<name>dfs.namenode.handler.count</name>
<value>21</value>
</property>
(3)修改core-site.xml
<!-- 配置垃圾回收时间为60分钟 -->
<property>
<name>fs.trash.interval</name>
<value>60</value>
</property>
(14)MapReduce参数调优#
修改mapred-site.xml
<!-- 环形缓冲区大小,默认100m -->
<property>
<name>mapreduce.task.io.sort.mb</name>
<value>100</value>
</property>
<!-- 环形缓冲区溢写阈值,默认0.8 -->
<property>
<name>mapreduce.map.sort.spill.percent</name>
<value>0.80</value>
</property>
<!-- merge合并次数,默认10个 -->
<property>
<name>mapreduce.task.io.sort.factor</name>
<value>10</value>
</property>
<!-- maptask内存,默认1g; maptask堆内存大小默认和该值大小一致mapreduce.map.java.opts -->
<property>
<name>mapreduce.map.memory.mb</name>
<value>-1</value>
<description>The amount of memory to request from the scheduler for each map task. If this is not specified or is non-positive, it is inferred from mapreduce.map.java.opts and mapreduce.job.heap.memory-mb.ratio. If java-opts are also not specified, we set it to 1024.
</description>
</property>
<!-- matask的CPU核数,默认1个 -->
<property>
<name>mapreduce.map.cpu.vcores</name>
<value>1</value>
</property>
<!-- matask异常重试次数,默认4次 -->
<property>
<name>mapreduce.map.maxattempts</name>
<value>4</value>
</property>
<!-- 每个Reduce去Map中拉取数据的并行数。默认值是5 -->
<property>
<name>mapreduce.reduce.shuffle.parallelcopies</name>
<value>5</value>
</property>
<!-- Buffer大小占Reduce可用内存的比例,默认值0.7 -->
<property>
<name>mapreduce.reduce.shuffle.input.buffer.percent</name>
<value>0.70</value>
</property>
<!-- Buffer中的数据达到多少比例开始写入磁盘,默认值0.66。 -->
<property>
<name>mapreduce.reduce.shuffle.merge.percent</name>
<value>0.66</value>
</property>
<!-- reducetask内存,默认1g;reducetask堆内存大小默认和该值大小一致mapreduce.reduce.java.opts -->
<property>
<name>mapreduce.reduce.memory.mb</name>
<value>-1</value>
<description>The amount of memory to request from the scheduler for each reduce task. If this is not specified or is non-positive, it is inferred
from mapreduce.reduce.java.opts and mapreduce.job.heap.memory-mb.ratio.
If java-opts are also not specified, we set it to 1024.
</description>
</property>
<!-- reducetask的CPU核数,默认1个 -->
<property>
<name>mapreduce.reduce.cpu.vcores</name>
<value>2</value>
</property>
<!-- reducetask失败重试次数,默认4次 -->
<property>
<name>mapreduce.reduce.maxattempts</name>
<value>4</value>
</property>
<!-- 当MapTask完成的比例达到该值后才会为ReduceTask申请资源。默认是0.05 -->
<property>
<name>mapreduce.job.reduce.slowstart.completedmaps</name>
<value>0.05</value>
</property>
<!-- 如果程序在规定的默认10分钟内没有读到数据,将强制超时退出 -->
<property>
<name>mapreduce.task.timeout</name>
<value>600000</value>
</property>
(15)YARN参数调优#
修改yarn-site.xml配置参数如下:
<!-- 选择调度器,默认容量 -->
<property>
<description>The class to use as the resource scheduler.</description>
<name>yarn.resourcemanager.scheduler.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler</value>
</property>
<!-- ResourceManager处理调度器请求的线程数量,默认50;如果提交的任务数大于50,可以增加该值,但是不能超过3台 * 4线程 = 12线程(去除其他应用程序实际不能超过8) -->
<property>
<description>Number of threads to handle scheduler interface.</description>
<name>yarn.resourcemanager.scheduler.client.thread-count</name>
<value>8</value>
</property>
<!-- 是否让yarn自动检测硬件进行配置,默认是false,如果该节点有很多其他应用程序,建议手动配置。如果该节点没有其他应用程序,可以采用自动 -->
<property>
<description>Enable auto-detection of node capabilities such as
memory and CPU.
</description>
<name>yarn.nodemanager.resource.detect-hardware-capabilities</name>
<value>false</value>
</property>
<!-- 是否将虚拟核数当作CPU核数,默认是false,采用物理CPU核数 -->
<property>
<description>Flag to determine if logical processors(such as
hyperthreads) should be counted as cores. Only applicable on Linux
when yarn.nodemanager.resource.cpu-vcores is set to -1 and
yarn.nodemanager.resource.detect-hardware-capabilities is true.
</description>
<name>yarn.nodemanager.resource.count-logical-processors-as-cores</name>
<value>false</value>
</property>
<!-- 虚拟核数和物理核数乘数,默认是1.0 -->
<property>
<description>Multiplier to determine how to convert phyiscal cores to
vcores. This value is used if yarn.nodemanager.resource.cpu-vcores
is set to -1(which implies auto-calculate vcores) and
yarn.nodemanager.resource.detect-hardware-capabilities is set to true. The number of vcores will be calculated as number of CPUs * multiplier.
</description>
<name>yarn.nodemanager.resource.pcores-vcores-multiplier</name>
<value>1.0</value>
</property>
<!-- NodeManager使用内存数,默认8G,修改为4G内存 -->
<property>
<description>Amount of physical memory, in MB, that can be allocated
for containers. If set to -1 and
yarn.nodemanager.resource.detect-hardware-capabilities is true, it is
automatically calculated(in case of Windows and Linux).
In other cases, the default is 8192MB.
</description>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>4096</value>
</property>
<!-- nodemanager的CPU核数,不按照硬件环境自动设定时默认是8个,修改为4个 -->
<property>
<description>Number of vcores that can be allocated
for containers. This is used by the RM scheduler when allocating
resources for containers. This is not used to limit the number of
CPUs used by YARN containers. If it is set to -1 and
yarn.nodemanager.resource.detect-hardware-capabilities is true, it is
automatically determined from the hardware in case of Windows and Linux.
In other cases, number of vcores is 8 by default.</description>
<name>yarn.nodemanager.resource.cpu-vcores</name>
<value>4</value>
</property>
<!-- 容器最小内存,默认1G -->
<property>
<description>The minimum allocation for every container request at the RM in MBs. Memory requests lower than this will be set to the value of this property. Additionally, a node manager that is configured to have less memory than this value will be shut down by the resource manager.
</description>
<name>yarn.scheduler.minimum-allocation-mb</name>
<value>1024</value>
</property>
<!-- 容器最大内存,默认8G,修改为2G -->
<property>
<description>The maximum allocation for every container request at the RM in MBs. Memory requests higher than this will throw an InvalidResourceRequestException.
</description>
<name>yarn.scheduler.maximum-allocation-mb</name>
<value>2048</value>
</property>
<!-- 容器最小CPU核数,默认1个 -->
<property>
<description>The minimum allocation for every container request at the RM in terms of virtual CPU cores. Requests lower than this will be set to the value of this property. Additionally, a node manager that is configured to have fewer virtual cores than this value will be shut down by the resource manager.
</description>
<name>yarn.scheduler.minimum-allocation-vcores</name>
<value>1</value>
</property>
<!-- 容器最大CPU核数,默认4个,修改为2个 -->
<property>
<description>The maximum allocation for every container request at the RM in terms of virtual CPU cores. Requests higher than this will throw an
InvalidResourceRequestException.</description>
<name>yarn.scheduler.maximum-allocation-vcores</name>
<value>2</value>
</property>
<!-- 虚拟内存检查,默认打开,修改为关闭 -->
<property>
<description>Whether virtual memory limits will be enforced for
containers.</description>
<name>yarn.nodemanager.vmem-check-enabled</name>
<value>false</value>
</property>
<!-- 虚拟内存和物理内存设置比例,默认2.1 -->
<property>
<description>Ratio between virtual memory to physical memory when setting memory limits for containers. Container allocations are expressed in terms of physical memory, and virtual memory usage is allowed to exceed this allocation by this ratio.
</description>
<name>yarn.nodemanager.vmem-pmem-ratio</name>
<value>2.1</value>
</property>
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 上周热点回顾(2.17-2.23)
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
2020-05-12 Scala_模式匹配