该文章为lagou学习记录笔记,里面的资源和内容来自lagou,作为大数据菜鸡,如果内容部分有错误还请各位大佬指出并纠正,谢谢
大数据技术解决的主要是海量数据的存储和计算
大数据的定义:是指无法在一定时间内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式。
大数据的特点:5v(volumn–大量、velocity–高速、variety–多样、veracity真实、value低价值)
Hadoop=HDFS(分布式文件系统)+MapReduce(分布式计算框架)+Yarn(资源协调框架)+Common模块
是分布式存储服务;HDFS 通过统一的命名空间目录树来定位文件; 另外,它是分布式的,由很多服务器联合起来实现 其功能,集群中的服务器有各自的角色(分布式本质是拆分,各司其职);
NameNode(nn):hdfs集群的管理,Master节点:
1.维护管理HDFS的名称空间(NameSpace);
2.维护副本策略;
3.记录文本块(block)的映射信息;
4.负责处理客户端读写请求。
DataNode:执行NameNode下达的命令,为Slave节点:
1.保存实际的数据块,
2.负责数据块的读写。
Client:客户端
1.上传文件到HDFS的时候,Client负责将文件切分成Block,然后进行上传
2.请求NameNode交互,获取文件的位置信息
3.读取或写入文件,与DataNode交互
4.Client可以使用一些命令来管理HDFS或者访问HDFS
1.客户端通过分布式文件系统(Distributed FileSystem)模块向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。
2.挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
3.DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。
4.客户端以Packet为单位接收,先在本地缓存,然后写入目标文件。
1.客户端通过分布式文件系统(Distributed FileSystem)模块向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会放入一个确认队列等待确认。
NameNode如何管理和存储元数据?
计算机中存储数据两种:内存或者是磁盘
元数据存储磁盘:存储磁盘无法面对客户端对元数据信息的任意的快速低延迟的响应,但是安全性高
元数据存储内存:元数据存放内存,可以高效的查询以及快速响应客户端的查询请求,数据保存在内 存,如果断点,内存中的数据全部丢失。
解决方案:内存+磁盘;NameNode内存+FsImage的文件(磁盘)
新问题:磁盘和内存中元数据如何划分?
两个数据一模一样,还是两个数据合并到一起才是一份完整的数据呢?
一模一样:client如果对元数据进行增删改操作,需要保证两个数据的一致性。FsImage文件操作起来 效率也不高。
两个合并=完整数据:NameNode引入了一个edits文件(日志文件:只能追加写入)edits文件记录的 是client的增删改操作,
不再选择让NameNode把数据dump出来形成FsImage文件(这种操作是比较消耗资源)。
Fsimage文件:是namenode中关于元数据的镜像,一般称为检查点,这里包含了HDFS文件系统 所有目录以及文件相关信息(Block数量,副本数量,权限等信息)
Edits文件 :存储了客户端对HDFS文件系统所有的更新操作记录,Client对HDFS文件系统所有的 更新操作都会被记录到Edits文件中(不包括查询操作) **seen_txid:**该文件是保存了一个数字,数字对应着最后一个Edits文件名的数字 VERSION:该文件记录namenode的一些版本号信息,比如:CusterId,namespaceID等
如果元数据出现丢失损坏如何恢复呢?
HDFS文件限额配置:HDFS文件的限额配置允许我们以文件大小或者文件个数来限制我们在某个目录下上传的文件数量或者文件内容总量,以便达到我们类似百度网盘网盘等限制每个用户允许上传的最大的文件的量。
1.数量限制
hdfs dfsadmin -setQuota 2 /user/root/test #给该文件夹下面设置最多上传两个文件,上传文件,大小只能上传一个文件
hdfs dfsadmin -clrQuota /user/root/test #清除文件数量限制
2.空间大小限额
hdfs dfsadmin -setSpaceQuota 4k /user/root/test # 限制空间大小4KB
#上传超过4Kb的文件大小上去提示文件超过限额
hdfs dfs -put /export/softwares/xxx.tar.gz /user/root/test
hdfs dfsadmin -clrSpaceQuota /user/root/test #清除空间限额
#查看hdfs文件限额数量
hdfs dfs -count -q -h /user/root/test
安全模式是HDFS所处的一种特殊状态,在这种状态下,文件系统只接受读数据请求,而不接受删除、修改等变更请求。在NameNode主节点启动时,HDFS首先进入安全模式,DataNode在 启动的时候会向NameNode汇报可用的block等状态,当整个系统达到安全标准时,HDFS自动离开安全模式。如果HDFS出于安全模式下,则文件block不能进行任何的副本复制操作,因此达到 最小的副本数量要求是基于DataNode启动时的状态来判定的,启动时不会再做任何复制(从而达 到最小副本数量要求),HDFS集群刚启动的时候,默认30S钟的时间是出于安全期的,只有过了 30S之后,集群脱离了安全期,然后才可以对集群进行操作。
hdfs dfsadmin -safemode
主要来解决HDFS集群存在大量小文件的问题
由于大量小文件会占用NameNode的内存,因此对于HDFS来说存储大量小文件造成NameNode 内存资源的浪费。
Hadoop存档文件HAR文件,是一个更高效的文件存档工具,HAR文件是由一组文件通过archive 工具创建而来,在减少了NameNode的内存使用的同时,可以对文件进行透明的访问,通俗来说 就是HAR文件对NameNode来说是一个文件减少了内存的浪费,对于实际操作处理文件依然是一 个一个独立的文件。
#把/user/lagou/test目录里面的所有文件归档成一个叫test.har的归档文件,并把归档后文件存储到/user/lagou/output路径下。
bin/hadoop archive -archiveName test.har –p /user/root/test /user/root/output
#查看归档
hadoop fs -lsr /user/root/output/test.har
#解归档文件
hadoop fs -cp har:/// user/root/output/test.har/* /user/root
MapReduce的思想核心是分 而治之,充分利用了并行处理的优势。
MapReduce任务过程是分为两个处理阶段:
经过查看分析官方WordCount案例源码我们发现一个统计单词数量的MapReduce程序的代码由三个部 分组成, Mapper类
Reducer类 运行作业的代码(Driver)Mapper类继承了org.apache.hadoop.mapreduce.Mapper类重写了其中的map方法,Reducer类继承
了org.apache.hadoop.mapreduce.Reducer类重写了其中的reduce方法。
重写的Map方法作用:map方法其中的逻辑就是用户希望mr程序map阶段如何处理的逻辑;
重写的Reduce方法作用:reduce方法其中的逻辑是用户希望mr程序reduce阶段如何处理的逻辑;
详细步骤:
1.读取数据组件InputFormat(默认是TextInputFormat)会通过getSplits方法对输入目录中文件进行逻辑切片规划得到splits,有多少个split就对应启动多少个MapTask。
2.将输入文件切分为splits之后,由RecordReader对象(默认LineRecordReader)进行读取,以\n作为分隔符,读取一行数据,返回
3.读取split返回
4.map逻辑完之后,将map的每条结果通过context.write进行collect数据收集。在collect中,会先对其进行分区处理,默认使用HashPartitioner。
MapReduce提供Partitioner接口,它的作用就是根据key或value及reduce的数量来决定当前的这对
输出数据最终应该交由哪个reduce task处理。默认对key hash后再以reduce task数量取模。默认的
取模方式只是为了平均reduce的处理能力,如果用户自己对Partitioner有需求,可以订制并设置到 job上。
5.接下来会将数据写入内存中,内存中的区域叫做环形缓冲区,缓冲区的作用是批量收集map结果,减少磁盘IO的影响,key/value对以及partition的结果都会被写入到缓冲区中。其中key/value值写入前都会被序列化成字节数组。
环形缓冲区其实是一个数组,数组中存放着key、value的序列化数据和key、value的元数据信 息,包括partition、key的起始位置、value的起始位置以及value的长度。环形结构是一个抽象概 念。
缓冲区是有大小限制,默认是100MB。当map task的输出结果很多时,就可能会撑爆内存,所以 需要在一定条件下将缓冲区中的数据临时写入磁盘,然后重新利用这块缓冲区。这个从内存往磁盘 写数据的过程被称为Spill,中文可译为溢写。这个溢写是由单独线程来完成,不影响往缓冲区写 map结果的线程。溢写线程启动时不应该阻止map的结果输出,所以整个缓冲区有个溢写的比例 spill.percent。这个比例默认是0.8,也就是当缓冲区的数据已经达到阈值(buffer size * spill percent = 100MB * 0.8 = 80MB),溢写线程启动,锁定这80MB的内存,执行溢写过程。Map task的输出结果还可以往剩下的20MB内存中写,互不影响。
6.当溢写线程启动后,需要对这80MB空间内的key做排序。—这是一个默认行为
7.合并溢写文件:每次溢写会在磁盘上生成一个临时文件(在写前会判断是否有combiner),如果map的输出结果真的很大,有多次溢写发生,磁盘上会有相应的产生多个临时文件。当整个数据处理结束后,就开始对磁盘中的临时文件进行merge合并,因为最终的文件只有一个,写入磁盘,并且为这个文件提供了一个索引文件,以来记录每个reduce对应数据的偏移量。
------到这里结束maptask的过程
官方参考地址
https://hadoop.apache.org/docs/r2.9.2/hadoop-mapreduce-client/hadoop-mapreduce- client-core/mapred-default.xml
关于MapTask并行度
1.mapTask的并行度决定map阶段的任务处理并发度,从而影响到整个job的处理速度。
2.MapTask并行度决定机制
数据块:Block是HDFS物理上把数据分成一块一块。 (128M)
切片:数据切片只是在逻辑上对输入进行分片,并不会在磁盘上将其切分成片进行存储。默认为128M
2.MapTask并行度并不是越多越好:如果一个文件仅仅比128M大一点点也被当成一个split来对待,而不是多个split。
MR框架在并行运算的同时也会消耗更多资源,并行度越高资源消耗也越高,假设129M文件分为两个分片,一个是128M,一个是1M; 对于1M的切片的Maptask来说,太浪费资源。
map阶段处理后的数据如何传入到reduce阶段的一个流程。
从分区溢写开始,会按照key进行分区默认的分区规则是hashcode值%numreduceTasks来进行的,每个分区会对内进行排序,这里使用的是quicksort,之后在合并溢写文件时会使用分区合并同时进行归并排序。
reduce分为copy、sort、reduce三个阶段,前面两个阶段为重点。
copy阶段包含一个 eventFetcher来获取已完成的map列表,由Fetcher线程去copy数据,在此过程中会启动两个merge线程,分别为inMemoryMerger和onDiskMerger,分别将内存中的数据merge到磁盘和将磁盘中的数据 进行merge。待数据copy完成之后,copy阶段就完成了,开始进行sort阶段,sort阶段主要是执行 finalMerge操作,纯粹的sort阶段,完成之后就是reduce阶段,调用用户定义的reduce函数进行处理。
详细步骤:
1.copy阶段,简单的拉取数据。Reduce进程启动一些数据copy线程(Fetcher),通过HTTP方式请求maptask获取属于自己的文件。
2.Merge阶段。这里的merge如map端的merge动作,只是数组中存放的是不同map端copy来的数值。Copy过来的数据会先放入内存缓冲区中,这里的缓冲区大小要比map端的更为灵活。其中merge 有三种形式:内存到内存;内存到磁盘;磁盘到磁盘。默认情况下第一种形式不启用。当内存中的数据量到达一定阈值,就启动内存到磁盘的merge。与map 端类似,这也是溢写的过程,这个过程中如果你设置有Combiner,也是会启用的,然后在磁盘中生成了众多的溢写文件。第二种 merge方式一直在运行,直到没有map端的数据时才结束,然后启动第三种磁盘到磁盘的merge 方式生成最终的文件。
3.合并排序(此处使用的是归并排序)。把分散的数据合并成一个大的数据后,再对合并后的数据进行排序。
4.对排序后按照相同的key分组的数据的key/value调用一次reduce的方法,key相同的对其value进行reduce方法,每次调用会产生0个或者多个key/value对,最后把这些输出的key/value对写入到HDFS文件中。
ReduceTask并行度
ReduceTask的并行度也会影响整个job的执行并法度和执行效率,与Maptask不同,ReduceTask数量可以直接手动设置:
//默认值是1,手动设置为5
job.setNumReduceTasks(5);
注:
1.reduceTask=0,表示没有reduceTask阶段,输出文件数和MapTask数量一致;
2.ReduceTask默认值为1,输出文件数据为1;
3.如果数据分布不均匀,可能在Reduce阶段产生倾斜;
数据倾斜的定义:是大量相同的key被partition分配到一个分区里。也有可能就是某些作业所在的NodeManager有问题或者container有问题,导致作业执行缓慢。
出现的现象:绝大多数的task执行得非常快,但是个别task执行的极慢。还会出现失败。
通用解决方案是:对key增加随机数。
那如何解决数据倾斜的问题呢?
默认的是hash算法进行分区,我们可以尝试自定义分区,修改分区实现逻辑,结合业务特点,使得每个分区数据基本平衡可以尝试修改分区的键,让其符合hash分区,并且使得最后的分区平衡,比如在key前加随机数n-key。
抽取导致倾斜的key对应的数据单独处理。 如果不是数据倾斜带来的问题,而是节点服务有问题造成某些map和reduce执行缓慢呢?
使用推测执行找个其他的节点重启一样的任务竞争,谁快谁为准。推测执行时以空间换时间的优化。 会带来集群资源的浪费,会给集群增加压力。
ResourceManager(rm):处理客户端请求、启动/监控ApplicationMaster、监控NodeManager、资源分配与调度;
NodeManager:单个节点上的资源管理、处理来自ResourceManager的命令、处理来自ApplicationMaster命令;
ApplicationMaster(am):数据切分、为应用程序申请资源,并分配给内部任务、任务监控与容错;
Container:对任务运行环境的抽象,封装了CPU、内存等多维资源以及环境变量、启动命令等任务运行相关的信息。
作业提交过程之YARN
作业提交
1.Client调用job.waitForCompletion方法,向整个集群提交MR作业。
2.Client向ResourceManager申请一个作业id。
3.ResourceManager给Client返回该job资源的提交路径和作业id。
4.Client提交jar包、切片信息和配置文件到指定的资源提交路径。
5.Client提交完资源后,向RM申请运行MrAppMaster。
作业初始化
6.当RM收到Client请求后,将该job添加到容量调度器中。
7.某一个空闲的NM领取该job。
8.该NM创建Container,并产生MRAppMaster。
9.下载Client提交的资源到本地。
任务分配
10.MrAppMaster向RM申请运行多个MapTask任务资源。
11.RM将运行MapTask任务分配给另外两个NodeManager,另外两个NodeManager分别领取任务并创建容器。
任务运行
12.MR向两个接收到任务的NodeManager发送程序启动脚本,这两个NodeManager分别启动MapTask,MapTask对数据分区排序。
13.MrAppMaster等待所有MapTask运行完毕后,向RM申请容器,运行ReduceTask。
14.ReduceTask向MapTask获取相应分区的数据。
15.程序运行完毕后,MR会向RM申请注销自己。
进度和状态更新
YARN中的任务将其进度和状态返回给应用管理器,客户端每秒(通过mapreduce.client.progressmonitor.pollinterval设置)向应用管理器请求进度更新,展示给用户。
作业完成
除了向应用管理器请求作业进度外,客户端每5秒都会通过调用waitForCompletion()来检查作业是否完成。时间间隔可以通过mapreduce.client.completion.pollinterval来设置。作业完成之后, 应用管理器和Container会清理工作状态。作业的信息会被作业历史服务器存储以备之后用户核查。
主要有三种:FIFO、Capacity Scheduler和Fair Scheduler。hadoop2.9.2默认的资源调度器是Capacity Scheduler。
1.FIFO(先进先出-调度器)
按照任务到达时间排序,先来先服务
缺点:任务的优先级只简单的按照时间来排序,没有考虑更多条件。
2.容量调度器(Capacity Scheduler默认的调度器)
该调度器允许多个组织共享整个集群,每个组织可以获得集群的一部分的计算能力。通过为每个组织分配专门的队列,然后再为每个队列分配一定的集群资源,这样整个集群就可以通过设置多个队列的方式给多个组织提供服务。队列内还可以进行垂直划分,在一个队列内部,资源的调度是采用的是先进先出(FIFO)策略。
3.Fair Scheduler(公平调度器,CDH版本的Hadoop默认使用的调度器)
该调度器会为所有的应用分配公平的资源(可以通过参数来定义公平)。也可以在多个队列间工作。
会遇见的问题:在于数据的多线程安全以及每个操作效率。
对于多线程安全:
NameNode在写edits log时几个原则:
写入数据到edits_log必须保证每条edits都有一个全局顺序递增的transactionId(简称为txid),
这样才可以标识出来一条一条的edits的先后顺序。
如果要保证每条edits的txid都是递增的,就必须得加同步锁。也就是每个线程修改了元数据,要写 一条edits
的时候,都必须按顺序排队获取锁后,才能生成一个递增的txid,代表这次要写的edits 的序号。
产生的问题:
如果每次都是在一个加锁的代码块里,生成txid,然后写磁盘文件edits log,这种既有同步锁又有写磁 盘操作非常耗时。
HDFS优化解决方案 问题产生的原因主要是在于,写edits时串行化排队生成自增txid + 写磁盘操作费时。
HDFS的解决方案
- 串行化:使用分段锁 2. 写磁盘:使用双缓冲 分段加锁机制 首先各个线程依次第一次获取锁,生成顺序递增的txid,然后将edits写入内存双缓冲的区域1,接着就
立马第一次释放锁了。趁着这个空隙,后面的线程就可以再次立马第一次获取锁,然后立即写自己的 edits到内存缓冲。
双缓冲机制
程序中将会开辟两份一模一样的内存空间,一个为bufCurrent,产生的数据会直接写入到这个
bufCurrent,而另一个叫bufReady,在bufCurrent数据写入(达到一定标准)后,两片内存就会
exchange(交换)。直接交换双缓冲的区域1和区域2。保证接收客户端写入数据请求的都是操作内存 而不是同步写磁盘。
在Hadoop3.x中,不再允许使用jdk1.7,要求jdk1.8以上版本。Hadoop3.x以后将会调整方案架构, 将Mapreduce 基于内存+io+磁盘,共同处理数据。
Hadoop 3.x中引入了一些重要的功能和优化,包括HDFS 可擦除编码、多Namenode支持、MR Native Task优化、YARN基于cgroup的内存和磁盘IO隔离、YARN container resizing等。
官方文件参考地址:http://hadoop.apache.org/docs/r3.0.1
Hadoop3.x中最大改变的是HDFS,HDFS通过最近black块计算,根据最近计算原则,本地black块,加
入到内存,先计算,通过IO,共享内存计算区域,最后快速形成计算结果。
- HDFS支持数据的擦除编码,这使得HDFS在不降低可靠性的前提下,节省一半存储空间。(http s://issues.apache.org/jira/browse/HDFS-7285)
- 多NameNode支持,即支持一个集群中,一个active、多个standby namenode部署方式。注: 多ResourceManager特性在hadoop 2.0中已经支持。(https://issues.apache.org/jira/browse/ HDFS-6440)
关于这两个特性的官方文档地址:
http://hadoop.apache.org/docs/r3.0.1/hadoop-project-dist/hadoop-hdfs/HDFSErasureCoding.html
http://hadoop.apache.org/docs/r3.0.1/hadoop-project-dist/hadoop-hdfs/HDFSHighAvailabilityWithQJM.html
yarn改进
- 基于cgroup的内存隔离和IO Disk隔离(https://issues.apache.org/jira/browse/YARN-2619)
- 用curator实现RM leader选举(https://issues.apache.org/jira/browse/YARN-4438)
- containerresizing(https://issues.apache.org/jira/browse/YARN-1197)
- Timelineserver next generation (https://issues.apache.org/jira/browse/YARN-2928)
官方文档地址
http://hadoop.apache.org/docs/r3.0.1/hadoop-yarn/hadoop-yarn-
site/TimelineServiceV2.html
1.shuffle过程中会按照key进行分区排序,排序在多个阶段都会发生,你觉得为什么要进行排序?不排序不可以吗?(百度)
考虑到reduce阶段执行reduce方法的时候需要找到key相同的value组成一个集合调用一次reduce方法。如果没有排序找到相同key的数据需要每次全局扫描一遍,这个复杂度太高!
2.HDFS上传一个300M的文件到hdfs,hdfs设置的block大小是128M,上传成功之后会有几块?上传过程中多个block之间是穿着上传还是并行上传?
会切分成3个block,串行上传。
(问:为什么不并行?/并行上传是否会比串行上传更节省时间?)
带宽有限。带宽如果不变,变成并行效率也是
有限的。上传下载文件瓶颈是在网络IO(带宽),带宽不提升,效率不会有明显改善。
需要能写快排,mergesort代码