简介:Hadoop是基于JAVA语言开发的Apache开源框架,以分布式文件系统 HDFS(Hadoop Distributed File System) 和 MapReduce(Google MapReduce 的开源实现) 为核心的 Hadoop,为用户提供了系统底层透明的分布式基础构架。
Hadoop 三大核心:
HDFS: Hadoop Distributed File System 分布式存储系统
提供了高可靠性、高扩展性和高吞吐率的数据存储服务的分布式存储系统YARN: Yet Another Resource Negotiator 资源管理调度系统
负责集群资源的管理和调度Mapreduce:分布式运算框架(计算向数据移动)
具有易于编程、高容错性和高扩展性等优点。
Hadoop的特点:
扩容能力(Scalable):能可靠地(reliably)存储和处理千兆字节(PB)数据。
成本低(Economical):可以通过普通机器组成的服务器群来分发以及处理数据。这些服务器群总计可达数千个节点。
高效率(Efficient):通过分发数据,hadoop可以在数据所在的节点上并行地(parallel)处理它们,这使得处理非常的快速。
可靠性(Reliable):hadoop能自动地维护数据的多份副本,并且在任务失败后能自动地重新部署(redeploy)计算任务。
一、HDFS架构
HDFS(Hadoop Distributed File System)是建立在一组分布式服务器节点上的本地文件系统之上的分布式文件系统。HDFS采用的是经典的主-从式结构。
适合:大文件,数据流式访问一次写入多次读取
HDFS集群的角色&职责
主角色:NameNode
NameNode是Hadoop分布式文件系统的核心,架构中的主角色。它负责维护和管理文件系统的元数据,包括命名空间目录树结构、文件和块的位置信息、访问权限等信息。因此NameNode成为访问HDFS的唯一入口。(NameNode不持久化存储每个文件块中各个块所在的DataNode位置信息,这些信息会在集群启动的时候从DataNode构建,NameNode存在单点故障)
NameNode管理元数据的方式:
NameNode为了客户端查找起来非常便捷,它把数据全部放在内存当中,但是内存中数据存在丢失的情况。所以它通过定时在磁盘上备份元数据信息来保证元数据的安全。 NameNode内部通过内存和磁盘文件两种方式管理元数据。其中磁盘上的元数据文件包括Fsimage内存元数据镜像文件和edits log编辑日志。
从角色:DataNode
DataNode是Hadoop HDFS中的从角色,负责具体的数据块存储。DataNode的数据量决定了HDFS集群的整体数据存储能力。通过和NameNode配合维护着数据块。在DataNode启动的时候,会将自己注册到NameNode并汇报自己负责持有的数据块列表。当某个DataNode关闭时,不影响数据的可用性,NameNode会安排其他的DataNode管理的块进行副本备份。
主角色辅助角色:Secondary NameNode
Secondary NameNode充当NameNode的辅助节点,但是不能替代NameNode。它主要帮助NameNode进行元数据文件的合并动作。
NameNode与SecondaryNameNode 的区别与联系
区别:
NameNode负责管理整个文件系统的元数据,以及每一个路径(文件)所对应的数据块信息。
SecondaryNameNode主要用于定期合并命名空间镜像和命名空间镜像的编辑日志。
联系:
SecondaryNameNode中保存了一份和namenode一致的镜像文件(fsimage)和编辑日志(edits)。
在主namenode发生故障时(假设没有及时备份数据),可以从SecondaryNameNode恢复数据。
二、HDFS写数据流程
要梳理清楚整个文件上传的过程,需要先了解三点信息:
Pipeline 管道,这是HDFS在上传文件写数据过程中采用的一种数据传输方式。
客户端将数据写入到第一个节点的时候,第一个数据节点保存完后将其复制到第二个数据节点,第二个数据节点保存后再将其复制到第三个数据节点。
在这个pipeline中,每一台机器都持有一个副本,当这3台机器都流完的时候,3副本就完成了,这就是pipeline机制。pipeline就是线性传输,沿着一个方向充分利用每台机器的带块,在最短的时间内最小化的完成三个副本数据传输。
ACK应答响应,数据传输校验机制
ACK 即确认字符,在数据通信中,接受方发送给发送方的一种传输类控制字符,表示发来的数据已确认接受无误。在HDFS pipeline传输数据的过程中,传输的反方向会进行ACK校验,确保数据安全。两两校验成功,则数据传输成功。
默认3副本存储策略
默认副本存储策略是由BlockPlacementPolicyDefalut 类决定。具体的选择策略如下:
第一块副本:优先客户端本地,否则就近随机(看客户端本地是否有DataNode)
第二块副本:不同于第一块副本的不同机架
第三块副本:第二块副本相同机架不同机器
客户端上传文件流程:
1. HDFS客户端创建示例对象实例DistrubutedFileSystem,该对象中封装了与HDFS文件操作系统的相关方法。
2. 调用DistrubutedFileSystem对象的create方法,通过RPC请求NameNode创建文件。其中NameNode会执行各种检查判断:目标文件是否存在、父目录是否存在、客户端是否有创建文件的权限等。检查通过后,NameNode会为本次请求记下一条记录,然后返回FSDataOutputStream输出流对象给客户端用于写数据。
3. 客户端通过FSDataOutputStream输出流开始写入数据。
4. 客户端写入数据时,将数据分成一个个数据包(packet 默认 64k),内部组件DataStreamer请求NameNode挑选出适合存储副本的一组DataNode地址,默认三副本。DataStreamer将数据包流式的传输到pipeline的第一个DataNode,该DataNode存储数据包并将它传输给pipeline的第二个DataNode,以此类推。为了保证数据安全,在传输的反方向上会进行ACK校验是否传输成功。
5. 客户端完成数据写入后,在FSDataOutputStream输出流上调用close关闭。
6. DistrubutedFileSystem联系NameNode告知其文件写入完成,等待NameNode确认。因为NameNode已经知道文件由哪些块组成(DataStreamer请求分配数据块),因此仅需等待最小复制块即可返回成功。最小复制由参数dfs.namenode.replication.min指定,默认1。
三、HDFS读数据流程
HDFS的文件读取原理,主要包括以下几个步骤:
1.首先调用FileSystem对象的open方法,其实获取的是一个DistributedFileSystem的实例。
2. DistributedFileSystem通过RPC(远程过程调用)获得文件的第一批block的locations,同一 block按照重复数会返回多个locations,这些locations按照hadoop拓扑结构排序,距离客户端近的排在前面。
3. 前两步会返回一个FSDataInputStream对象,该对象会被封装成 DFSInputStream对象,DFSInputStream可以方便的管理datanode和namenode数据流。客户端调用read方法,DFSInputStream就会找出离客户端最近的datanode并连接datanode。
4. 数据从datanode源源不断的流向客户端。
5.如果第一个block块的数据读完了,就会关闭指向第一个block块的datanode连接,接着读取下一个block块。这些操作对客户端来说是透明的,从客户端的角度来看只是读一个持续不断的流。
6.如果第一批block都读完了,DFSInputStream就会去namenode拿下一批blocks的location,然后继续读,如果所有的block块都读完,这时就会关闭掉所有的流。
四、MapReduce架构
一个完整的MR程序在分布式运行时有3类:
MRAppMaster:负责整个MR程序的过程调度以及状态协调
MapTask:负责map阶段的整个数据处理流程
ReduceTask:负责reduce阶段的整个数据处理流程
一个MR程序中,只能出现一个map阶段和一个reduce阶段,或者只有map阶段。如果业务逻辑负责,只能多个mapreduce程序串行执行。
注:整个mapreduce程序中,数据都是以K-V键值对的形式转换;
MapReduce执行流程
Map阶段:
1. 把输入目录下文件按照一定的标准逐个进行逻辑切片,行成切片规划。默认大小为 block size 128M,每一个切片对应一个MapTask处理。(getSplits)
2. 对切片中的数据进行按照一定的规则进行解析返回 <key,value>对。默认按行读取数据,其中key是每一行起始位置的偏移量,value是本行的文本内容。(TextInputFormat)
3. 调用Mapper类中的map方法处理数据。每读取解析一行<key,value>,调用一次map方法。
4. Map输出数据写入到内存缓冲区,达到比例后溢写到磁盘上。溢出spill的时候会根据key进行分区且排序。
5. 对所有溢写的文件进行最终的merge合并,生成一个分区且排序的文件。
Reduce阶段:
1. ReduceTask会主动从MapTask复制拉取属于自己处理的数据。
2. 把拉取过来的数据全部进行合并,即把分散的数据合并成一个大的数据,再对合并后的数据进行分组排序,相同的一组调用一次reduce方法,最后把输出的数据写入到HDFS上。
五、MapReduce的Shuffle过程
Shuffle:Map产生输出数据开始到Reduce拉取数据作为输入之前的过程称作Shuffle。
Map端Shuffle:
Collect阶段:将MapTask的结果数据收集输出到一个默认大小为100M的环形缓冲区。
Spill阶段:当缓冲区的数据到达比例(80%)之后会进行spill溢写磁盘,溢写到磁盘之前会进行排序(快排)。(对溢写的文件也可以进行Combiner操作,前提是汇总操作)
Merge阶段:最后对所有溢写到磁盘的文件进行分区合并(归并排序),保证一个MapTask最终只会产生一个中间数据文件。
Reduce端Shuffle:
Copy阶段:ReduceTask其中Fecher线程到已经完成MapTask的节点上复制一份属于自己的数据到自己的内存中。(如果内存不够,再存储到磁盘)
Merge阶段:在ReduceTask远程复制结果数据同时,会在后台开启两个线程对内存到本地的文件进行合并操作。
Sort阶段:在对数据进行合并的同时,会进行排序操作,由于MapTask阶段已经对数据进行了剧本的排序,所以Reduce只用保证copy的整体数据有序即可。
Shuffle的弊端:Shuffle的过程中会进行频繁的写磁盘操作。
六、Yarn架构&任务提交流程
Yarn是一个通用的资源管理系统和调度平台,为上层应用提供统一的资源管理和调用,也是Hadoop的资源管理器。
资源管理系统:集群的硬件资源,和程序运行相关如:CPU,内存。
调度平台:多个程序同时申请,计算如何分配资源,调度的规则。
通用:不仅仅支持MR,理论上支持各种计算程序。
架构:
从YARN的架构图来看,它主要由ResourceManager、NodeManager、ApplicationMaster和Container等以下几个组件构成。
ResourceManager(RM)
Yarn中的主角色,具有系统中所有应用程序之间的资源分配的最终权限,即最终仲裁者。同时接受用户的作业提交,并通过NodeManager分配、管理各个节点上的资源分配。
RM做一个统筹的管理者,它通过命令控制各个NodeManager把控全局,每台机器的资源使用情况怎么样,有没有空闲资源,资源使用多少了等。比如用户提交的作业是否能够运行、有没有权限,分配资源运行还是拒绝等等所有的决定者都由RM来决定。
NodeManager(NM)
Yarn的从角色,一台机器上对应一个,负责管理本台机器的计算资源。根据RM的命令,启动Containder(对任务运行环境进行抽象,封装CPU、内存等多维度的资源以及环境变量、启动命令等任务运行相关的信息)容器、监控容器的资源使用情况,并向RM汇报资源使用情况等。任务执行完成后在根据命令把相应的容器释放掉回收资源。
ApplicationMaster(AM)
用户提交的每一个应用程序,均包含一个AM。它是应用程序中的老大,负责程序内部的各个阶段的资源申请,监督程序的执行情况。AM程序是在Yarn上运行启动的第一个进程。
七、程序提交Yarn的交互流程
当用户向Yarn中提交一个程序后,Yarn将分成两个阶段来运行这个应用程序。
阶段一:客户端申请资源启动运行本次程序的ApplicationMaster;
阶段二:由ApplicationMaster根据本次程序内部的具体情况,向RM申请资源,并监控程序执行的整个过程,直到完成。
1. 用户通过客户端向YARN中的RM提交应用程序(比如hadoop jar 提交MR程序);
2. RM为该应用程序分配第一个Container容器,并与对应的NodeManager通信,要求它在这个Container中启动这个应用程序的ApplicationMaster。
3. ApplicationMaster启动成功之后,首先向RM注册并保持通信,这样用户直接通过RM查看应用程序的运行状态,比如执行的百分之几(AM不断向RM汇报,保持通信)。
4. ApplicationMaster为本次程序内的各个task任务向RM申请资源(根据本次的MR程序情况确定要启动多少个MapTask,有多少个分片,然后开始向RM申请资源),并监控它们的运行状态。
5. 一旦ApplicationMaster 申请到资源,便与对应的NodeManager通信,通知他们启动任务。
6. NodeManager为任务设置好运行环境以后,将任务命令写入到一个脚本中,并通过脚本启动任务。
7. 各个任务通过RPC协议向AM汇报自己的状态和进度,保证AM能够随时掌握各个任务的执行状态,从而可以在任务失败的时候重启。在程序的执行过程中,用户可以通过RM随时查询对应任务的执行状态。
8. 应用程序运行完成以后,AM会向RM注销并关闭自己。
八、Hadoop的调度策略
当前的Hadoop提供的3中调度策略:
FIFO Scheduler:先进先出调度器
即先提交任务先执行,不考虑优先级和范围,适用于负载较低的小规模集群。
Capacity Scheduler:容器调度器
默认hadoop3.x使用的调度器。允许不同组织不同部分同时共享整个集群资源。Capacity可以理解为一个个的资源队列,把一个集群划分成一个个的队列,不同队列之前可以划分子队列。
优点:
层次化队列设计:可以更合理的划分资源;
容量保证:每个队列可以设置一个资源占比,保证各个队列资源独立;
安全:每个队列可以设置对应的访问权限;
弹性分配:空闲队列的资源可以被其他队列;
Fair Scheduler:公平调度器
层次化队列设计:可以更合理的划分资源;
基于用户或组的队列映射:可以根据用户提交的用户名和组来分配队列。如果指定了队列则按指定队列提交;
资源抢占:根据应用的配置,抢占和分配资源可以是友好的或者强制的。默认不启动。
Yarn默认的调度器是 Capacity Scheduler(yarn-site.xml)
九、Hadoop生态圈的组件&简要描述
1.Zookeeper:是一个开源的分布式应用程序协调服务,基于zookeeper可以实现同步服务,配置维护,命名服务。
2.Flume:一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统。
3.Hbase:是一个分布式的、面向列的开源数据库, 利用Hadoop HDFS作为其存储系统。
4.Hive:基于Hadoop的一个数据仓库工具,可以将结构化的数据档映射为一张数据库表,并提供简单的sql 查询功能,可以将sql语句转换为MapReduce任务进行运行。
5.Sqoop:将一个关系型数据库中的数据导进到Hadoop的 HDFS中,也可以将HDFS的数据导进到关系型数据库中。
十、Hadoop1.0,2.0,3.0的区别
十一、MapReduceShuffle过程的优化
1.合并小文件:
HDFS小文件影响
影响NameNode的寿命,因为文件元数据存储在NameNode的内存中
影响计算引擎的任务数量,比如每个小的文件都会生成一个Map任务
2.数据输入小文件处理
合并小文件:对小文件进行归档(Har)、自定义Inputformat将小文件存储成SequenceFile文件。
采用ConbinFileInputFormat来作为输入,解决输入端大量小文件场景
对于大量小文件Job,可以开启JVM重用
3.Map阶段
增大环形缓冲区大小。由100m扩大到200m
增大环形缓冲区溢写的比例。由80%扩大到90%
减少对溢写文件的merge次数。(10个文件,一次20个merge)
不影响实际业务的前提下,采用Combiner提前合并,减少 I/O
4.Reduce阶段
合理设置Map和Reduce数:两个都不能设置太少,也不能设置太多。太少,会导致Task等待,延长处理时间;太多,会导致 Map、Reduce任务间竞争资源,造成处理超时等错误。
设置Map、Reduce共存:调整 slowstart.completedmaps 参数,使Map运行到一定程度后,Reduce也开始运行,减少Reduce的等待时间
规避使用Reduce,因为Reduce在用于连接数据集的时候将会产生大量的网络消耗。
增加每个Reduce去Map中拿数据的并行数
集群性能可以的前提下,增大Reduce端存储数据内存的大小
十二、Hadoop序列化和反序列化及自定义bean对象实现序列化
1.序列化和反序列化
a.序列化就是把内存中的对象,转换成字节序列(或其他数据传输协议)以便于存储(持久化)和网络传输。
b.反序列化就是将收到字节序列(或其他数据传输协议)或者是硬盘的持久化数据,转换成内存中的对象。
c.Java的序列化是一个重量级序列化框架(Serializable),一个对象被序列化后,会附带很多额外的信息(各种校验信息,header,继承体系等),不便于在网络中高效传输。所以,hadoop自己开发了一套序列化机制(Writable),精简、高效。
2.自定义bean对象要想序列化传输步骤及注意事项:
a.必须实现Writable接口
b.反序列化时,需要反射调用空参构造函数,所以必须有空参构造
c.重写序列化方法
d.重写反序列化方法
e.注意反序列化的顺序和序列化的顺序完全一致
f.要想把结果显示在文件中,需要重写toString(),且用"\t"分开,方便后续用
g.如果需要将自定义的bean放在key中传输,则还需要实现comparable接口,因为mapreduce框中的shuffle过程一定会对key进行排序
十三、Hadoop估算reduce个数的策略
十四、如何设定map和reduce个数
十五、HDFS HA原理
HA是为了解决系统的单点故障问题,在HDFS中就存在一个典型的单点故障问题。HDFS的HA就是通过双namenode来防止单点问题,一旦主NameNode出现故障,可以迅速切换至备用的NameNode。两个namenode有不同的状态,状态分别是Active和Standby。(备用)Namenode作为热备份,在机器发生故障时能够快速进行故障转移,同时在日常维护的时候进行Namenode切换。
在典型的HA集群中,将两台独立的计算机配置为NameNodes。在任何时间点,其中一个NameNodes处于活动状态,另一个处于待机状态。Active NameNode负责集群中的所有客户端操作,而Standby仅作为从站,维护足够的状态以在必要时提供快速故障转移。
为了使备用节点保持与Active节点同步的状态,两个节点都与一组名为“JournalNodes”(JN)的独立守护程序进行通信。当Active节点执行任何命名空间修改时,它可以将修改的记录持久记录到大多数这些JN。备用节点能够读取JN的编辑,并且不断地观察它们对编辑日志的更改。当待机节点看到编辑时,它将它们应用于自己的命名空间。在故障切换的情况下,待机将确保它已经读取了JounalNodes的所有编辑,然后再将其自身升级到Active状态。这将确保名称空间状态在发生故障转移之前完全同步。
为了提供快速故障切换,还需要备用节点具有有关集群中块的位置的最新信息。为了实现这一点,DataNodes配置有两个NameNodes的位置,并向两者发送块位置信息和心跳。
对于HA群集的正确操作至关重要,因此一次只能有一个NameNodes处于活动状态。否则,命名空间状态将在两者之间快速分离,冒着数据丢失或其他不正确的结果。为了确保这种属性并防止所谓的“脑裂”,JournalNodes将只允许一个NameNode作为一个作者。在故障切换期间,要变为活动状态的NameNode将简单地接管写入JournalNodes的角色,这将有效地防止其他NameNode继续处于活动状态,允许新的Active安全地进行故障转移。
脑裂(split-brain),指在一个高可用(HA)系统中,当联系着的两个节点断开联系时,本来为一个整体的系统,分裂为两个独立节点,这时两个节点开始争抢共享资源,结果会导致系统混乱,数据损坏。