Hadoop总结
本文说的Hadoop主要是分析2X,Hadoop可以分成HDFS、YARN、MapReduce
Hadoop官网:http://hadoop.apache.org
既然是个分布式计算框架,首先要有一个分布式存储软件HDFS,那么既然存储有了,自然需要一个分布式的计算框架--MapReduce,自然而然还需要一个合理分配资源的一个软件,于是就出现了Yarn,那么我们总体介绍下Hadoop的三大核心组件:
一.HDFS:分布式存储软件:在大数据中用于存储数据
二.MapReduce:分布式计算软件:在大数据中用于计算,Spark、Flink都属于分布式计算框架
三.Yarn:由于在大数据之中,需要处理很大量的数据,为了更合理的利用硬件资源,Yarn起到资源调度的作用
Hadoop全程使用RPC协议进行通信
RPC(Remote Procedure Call Protocol)远程过程调用协议。
通俗的描述是:客户端在不知道调用细节的情况下,调用存在于远程计算上的某个过程或函数,就像调用本地应用程序中的一样。
RPC博客:https://www.cnblogs.com/alexzhang92/p/10526347.html
本文依次介绍Hadoop的三大组件
一.HDFS:主从架构
(1)HDFS主要有三个进程:
1.NN(NameNode):第一名称节点 主要是用来存储元数据信息,其中包括文件的用户、权限,以及block块的信息以及block块的存储信息等信息
2.DN(DataNode) 数据节点 我个人理解是由NN指派给DN一些任务,然后DN进行操作,主要是就是帮NN干活的
3.SNN(SecondaryNameNode) 第二名称节点 主要做的是checkpoint操作,可以理解为冷备份
(2)HDFS主要是用来存储数据,那么我们先来介绍一下HDFS的读写流程:
HDFS的读流程:
流程:
1.HDFS client 会先向分布式文件系统发起Open请求,然后分布式文件系统会向nn发起读取此文件请求,nn会检查文件是否存在、此用户是否有权限读取这个文件,如果nn检查不合格,则返回报错信息,否则返回FSDataInputSteam对象和此文件的block信息
2.HDFS会向FSDataInputSteam发起read请求,首先读取文件的第一块数据,会先向最近的一个副本读取数据,如果数据损坏,则记录block的损坏信息,下次不会再读取整个block,然后会向第一块的第二个副本读取数据,读取完第一块数据,则会读取后面块的数据
3.读取完所有数据,client则会调用FSDataInputSteam对象的close方法,关闭流
HDFS写文件流程:
流程:
1.首先HDFS客户端会发起写文件请求到分布式文件系统,然后分布式文件系统会向nn发起写文件的请求,nn检查需要写入的文件是否存在、发起写文件请求的用户是否有权限,如果nn检查不合格,则返回报错信息,否则会返回一个FSDataOutputStream对象,并创建一个文件,不关联任何block
2.HDFS client调用FSDataOutputStream对象的write方法,FSDataOutputStream会先把文件节流,分成几个文件,这个取决于设置的block的大小
3.首先先写入先写入第一份文件,把第一份文件传输给第一个dn写入,第一份副本写完,再传输给第二个dn,第二份副本写完,再传输给第三个dn,等第三份副本写完,第三份副本会检核自己写入是否OK,如果OK会给第二份副本返回一个ack packet确认包,第二个dn收到第三个dn的ack packet确认包并检核第二份副本写入是否OK,如果OK,则给第一个dn返回一个ack packet确认包,第一个dn收到第二个dn的ack packet确认包并检核自己写入是否OK,如果OK,则给FSDataOutputStream对象返回一个ack packet确认包,标志第一份文件的三个副本已经写完了,剩下的还是这样写入
4.当文件全部写入成功,HDFS client则会调用close方法,关闭流
5.并调用FSDataOutputStream的complete方法告诉nn已经写入完成,并把副本信息维护在nn上面
(3)HDFS块信息
HDFS存储是分块存储的,块大小是由dfs.blocksize这个参数来决定的,1X默认的是64M,2X默认的是128M,如果一个块存储不到默认的大小,也会把它当成一个块来存储
这个就会引申到小文件问题,如果在HDFS上面存储了过多的小文件,那么就意味着会产生很多块,也会产生大量的块信息,需要把这些块信息记录在NN上面,这样会导致NN压力过大
解决方案:
1.写一个服务专门处理小文件合并问题
2.写一个脚本把小文件合并在一起
3.在存储之前就把文件合并到默认块大小的百分之90,然后再把文件存储到HDFS上面
HDFS的副本放置个数是由dfs.replication这个参数配置的,dfs.replication默认值是3,在生产环境下默认三个就可以了。
三个副本的存放位置:
1.如果上传文件的节点存在dn,第一份副本则存放在本节点上面,如果上传文件的节点不存在dn,则第一份副本选择一个磁盘和cpu状态良好的机器上传
2.第二份副本存放在和第一份副本不同机架的节点上面
3.第三份副本存放在和第二份副本同一机架的不同节点上面
(四)HDFS数据平衡问题
1.多台机器的磁盘存储分布不均匀?
解决方案: 1.1 不加新机器,原机器的磁盘分布不均匀:
[hadoop@xkhadoop002 ~]$ hdfs dfsadmin -setBalancerBandwidth 52428800
Balancer bandwidth is set to 52428800
[hadoop@xkhadoop ~]$
[hadoop@xkhadoop sbin]$ ./start-balancer.sh
等价
[hadoop@xkhadoop sbin]$ hdfs balancer
Apache Hadoop集群环境: shell脚本每晚业务低谷时调度
CDH集群环境: 忽略
1.2 加新机器,原机器的磁盘比如450G(500G),现在的新机器磁盘规格是5T
在业务低谷时,先将多台新机器加入到HDFS,做DN;
然后选一台的DN下架掉,等待hdfs自我修复块,恢复3份(网络和io最高的,也是最有风险性的)
2.一台机器的多个磁盘分布不均匀?
2.1.无论加不加磁盘,且多块磁盘的分布不均匀
官网:https://hadoop.apache.org/docs/r3.0.0-alpha2/hadoop-project-dist/hadoop-hdfs/HDFSDiskbalancer.html
Hadoop3X新特性,CDH5.12以后版本有这个功能
hdfs diskbalancer -plan node1.mycluster.com
hdfs diskbalancer -execute /system/diskbalancer/nodename.plan.json
(五)HDFS安全模式
1.先手动进入安全模式
[hadoop@xkhadoop ~]$ hdfs dfsadmin -safemode enter
19/12/06 21:05:02 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Safe mode is ON
2.测试安全模式下,是否可以读写
[hadoop@xkhadoop data]$ hadoop fs -get /data/xk.log
19/12/06 21:07:41 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
[hadoop@xkhadoop data]$ ll
总用量 4
-rw-r--r--. 1 hadoop hadoop 3 12月 6 21:07 xk.log
可以读取数据
[hadoop@xkhadoop data]$ hadoop fs -rm /data/xk.log
19/12/06 21:08:20 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
rm: Cannot delete /data/xk.log. Name node is in safe mode.
无法删除数据
[hadoop@xkhadoop data]$ echo "111" > demo.log
[hadoop@xkhadoop data]$ ll
总用量 8
-rw-rw-r--. 1 hadoop hadoop 4 12月 6 21:09 demo.log
-rw-r--r--. 1 hadoop hadoop 3 12月 6 21:07 xk.log
[hadoop@xkhadoop data]$ hadoop fs -put /data
19/12/06 21:09:12 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
put: `.': No such file or directory
无法写入数据
3.手动关闭安全模式
[hadoop@xkhadoop data]$ hdfs dfsadmin -safemode leave
19/12/06 21:10:14 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Safe mode is OFF
(六)CheckPoint原理
checkpoint,是由snn来做,nn里面存储着fsimage(上次checkpoint传输过来的镜像文件)、editlog(nn实时维护元数据信息的log日志)
1.nn把实时的元数据信息都维护在editlog里面,checkponit是由snn发起的,nn首先会创建一个新的editlog文件,然后把editlog切割之后元数据的log信息维护在新的editlog文件里面,然后把旧的editlog和最新的fsimage文件传输到snn机器上面
2.由snn来把editlog和最新的fsimage这两个文件合并到一起
3.snn会把最新的fsimage文件发送给nn
整个流程,我理解就是做了一个冷备份,为了防止nn挂掉,元数据丢失,才会有checkponit操作,checkponit的时间是由dfs.namenode.checkpoint.period这个参数控制的,默认是3600s,即一个小时,由于checkponit对网络消耗过大,会影响业务的正常运行,不建议修改这个参数
(七)HDFS HA
所谓HA值得就是高可用,即7✖24小时不间断服务,HDFS整体架构,面临一个很严重的问题,那如果NN进程挂了或者NN的那个机器宕机了怎么办?这就是单点故障(SPOF),有一个进程或者一个机器的问题,会导致整个HDFS阻塞,以及丢失一部分数据。
1.HA工作原理:
配置两台或者多台NN,同时只会有一台NN在使用,处于Active的状态,其他NN则闲置在一边,处于StandBy的状态,当在使用的那台NN挂了或者那台NN的机器宕机了,首先把坏了的那台NN的状态改成StandBy,后面通过ZK(ZoopKeeper)选举的机制,从StandBy的NN中选举出来最适合作为NN的机器,然后把那台机器StandBy状态改成Active,而且所有的元数据信息全部存储在多个NN共同使用的区域。
2.HA部署
(1)首先需要部署ZK集群
(2)需要启用HDFS的HA模式
参考文献:https://blog.csdn.net/weixin_37838429/article/details/81710045
二.MapReduce
MR:是一个计算程序,那既然是计算程序,是需要有输入和输出,那么就需要和存储数据的软件(如HDFS)进行交互。
MR1.X:主要是负责计算与资源调度
MR2.X:专门负责计算,把资源调度的功能转移到YARN上面
MR1进程:
JobTracker
TaskTracker: map task 、reduce task
MR不需要部署,只需要把计算程序提交到YARN上面,然后由YARN进行统一的资源分配,然后进行MR程序运行
(1).MR提交流程
本文主要说的是MR ON YARN
RM:
applications Manager 应用程序管理器
resource scheduler 资源memory+cpu调度器
1.首先client端向Yarn提交一个MR的应用程序,rm会给该job分配一个container(容器,类似一个空间),运行该job的 ApplicationMaster
2.ApplicationMaster会向applications Manager注册下,然后就可以通过web页面查看到这个job的进度
3.ApplicationMaster用轮询的方式通过RPC协议向RM申请和领取job运行的资源
4.ApplicationMaster拿到资源后开始运行map task 和reduce task,各个task通过RPC向ApplicationMaster报告自己的状态,ApplicationMaster可以掌握各个task的状态
5.job运行结束后,ApplicationMaster向applications Manager注销并关闭自己
(2).MR运行机制
map:映射
shuffle:洗牌
reduce:聚合
既然是计算框架,那肯定有数据输入端、数据输出端,首先先把数据通过input split ,切分成一个个分片,一个分片对应着一个map task任务,先把数据映射成key、value键值对,然后再通过shuffle,把相同的key洗到一起,最后通过reduce聚合操作,把相同的key聚合成一个key、value键值对,最后再把这个聚合的数据输出
shuffle主要是洗牌的作用,把map task的输出作为reduce task的输入数据
(3).shuffle原理
shuffle个人理解是发生在map之后reduce之前,所以shuffle可以分成map shuffle和reduce shuffle。
map shuffle:发生在map之后,map会映射成k,v键值对
1.分区:把数据分散到各个partition里面
2.排序:在partition内部根据key来进行排序
最终得到一个分区有序的数据,所谓分区有序指的是,数据会根据分区和key进行排序,会把相同分区的数据放在一起,每个partition里面会再进行 key的排序,然后最终把输出结果发送给reduce端的shuffle。以下是map端shuffle的具体流程图:
下面详细说下map shuffle的具体流程:
1.partition:从map端拿来数据之后,首先进行分区,每条数据上面再增加一个partition key的数据,把相同partition的数据存储在一起。由于后面有再partition内部进行sort的过程,可以做到分区有序。
那么如何做到全局有序呢?个人理解无法做到真正的全局有序,除非就设定一个reduce task,那么对于整个hadoop集群性质来说,性能很差,数据的局限性很强,肯定不适合。那么我们可以自己来设定partition的边界,用数据最大量来除以系统reduce task的个数,以他们的商来作为分界线,就可以用他们商的1倍、2倍.....numpartitions-1倍来作为他们的分界线。
2.kvbuffer:map传输过来的数据会把数据缓冲在内存的一个环形数据中,kvbuffer指的就是这个环形数据结构,从字面意思可以看出来这个数据不仅存储了数据还存储索引信息,之所以选用环形数据结构,是为了尽可能的使用内存的空间,在内存中放入更多的数据,但是数据一旦达到了kvbuffer所能存储的一个阈值,则会把多余的数据存储在磁盘当中。
kvbuffer中虽然存储了数据和索引数据,但是索引和数据有个很明显的分界线,这个分界线不是一成不变的,而是每次spill之后都会更新一下。初始的分界线是0,数据的存储方向是向上增长,而索引的增长方向却是向下增长的。
3.sort:sort启动后,会把kvbuffle里面的数据根据partition、key这两个关键词进行升序排列,但是移动的只是索引数据,真正的数据并没有做什么移动,以此来做到分区有序,即在同一个partition内部相同key的数据存储在一起
4.spill:此过程主要做的是把kvbuffer里面的数据刷到磁盘里面去,会先在机器里面寻找哪里可以放得下那么多的数据,针对kvbuffer里面数据,会创建一个spill.out的文件,然后依次把每个partition里面的数据吐到spill.out文件里面。kvbuffer里面的索引数据则会创建一个类似于spill.out.index的文件,如果内存中可以放得下,则不会创建这个文件,如果内存中放不下,则会把后续的信息放在磁盘里面。其中spill.out和spill.out.index两个文件的位置不一定在同一个目录下。
combiner:如果在代码中使用了combiner,则会在spill之前进行combiner,个人理解的combiner类似于shuffle在map shuffle阶段执行的一个reduce操作,combiner虽然可以大大增加效率,但是要是有一定的局限性,如果运算结果是需要累加的,则可以使用,大大提高中间的运算效率,否则会影响运算结果,所以在使用combiner的时候一定要慎用。
5.merge:会从本地目录里面扫描spill所产生的文件,在merge的过程中会产生file.out、file.out.Index的文件,用于最终存储数据和索引信息。
reduce shuffle:
1.复制map shuffle最终输出的文件
2.合并排序
具体流程如下:
1.copy:通过http向每个map拉取他所需要的数据
2.merge and sort:
1.内存到内存merge:copy过来的数据会先放到内存,如果这次数据数量过小,就直接把数据写入在内存里面
2.内存到磁盘merge:如果当内存缓冲区的内存使用到了一定程度,则会开启merge,会把内存中的数据merge到磁盘一个文件当中
3.磁盘到磁盘merge:reduce端的map作业全部copy完成,这时开始执行合并操作,由于map最终输出数据已经是全区有序的了,则此时sort就是一个合并的过程了
一般reduce是一边copy一边sort,最终会输出一个整体有序的数据块
参考文献:https://blog.csdn.net/u014374284/article/details/49205885
三.YARN(主从架构)
1.基本架构
YARN是一个调度平台,无论在上面跑的是什么程序,YARN负责给这个job分配物理资源,使job正常运行
YARN主要是由ResourceManager、ApplicationMaster、NodeManager、container组成
ResourceManager:
1.处理客户端请求
2.启动并监控ApplicationMaster
3.监控NodeManager
4.资源分配与调度
ApplicationMaster:
1.负责数据的切分
2.为应用程序申请资源并分配给内部的任务
3.任务的监控和容错
NodeManager:
1.容器生命周期管理
2.监控每个容器资源(CPU、内存)的使用情况
3.跟踪节点健康状态
4.以心跳的形式与ResourceManager保持通信
5.向ResourceManager汇报作业的资源使用情况和每个容器的运行状态
6.接收ApplicationMaster开启/关闭容器的请求
Container:
YARN分配资源的最小单位,只要包括CPU和内存
2.调度器
首先先介绍下YARN的调度器有哪些:FIFO Scheduler、Capacity Scheduler、Fair Scheduler
1.FIFO Scheduler:先进先出调度器
如果把YARN提交的所有应用提交顺序排成一个队列,会给先进去的应用程序分配资源,这个调度器容易理解一些,只有当前面的应用程序满足当前需求之后才会把资源分配给下一个应用程序。这个调度器不适合在集群上面使用,比如凌晨一点的时候执行了一个很耗费资源的应用程序,凌晨两点的时候执行了一个占用资源很小的应用程序,但是也需要等第一个应用程序跑完之后才会开启第二个应用程序。生产上面不建议使用,不适合共享集群。
2.Capacity Scheduler:计算调度器
会专门设置一个队列来跑占用资源比较小的应用程序,如果当面没有小型的应用程序提交,该队列还是会继续保留。则会使跑一个大型应用程序所用的时间要比FIFO Scheduler要长。apache版本的yarn的默认调度器,由yarn.resourcemanager.scheduler.monitor.policies这个参数控制,这个参数默认是:org.apache.hadoop.yarn.server.resourcemanager.monitor.capacity.ProportionalCapacityPreemptionPolicy。集群资源使用率比较低。
3.Fair Scheduler:公平调度器
Fair Scheduler设计的初衷就是为了合理的利用集群资源,这个调度器并不会预先占用一些资源,而是通过动态调度来实现资源分配的,假如我一点执行了一个三个小时的job,两点的时候执行了一个小的job,首先会查看第一个job里面是否有已经跑完并释放资源的Container,如果要是存在则在这个释放资源的Container里面跑第二个job,这个调度器再跑小任务的时候存在一定的延迟,因为并没有一个专门的队列再跑这些小任务,而是需要上个job里面的 Container跑完释放资源之后,才可以跑第二个job,可以合理的利用集群资源。cdh默认调度器。
3.YARN调优参数
container调优:
上文已经介绍过了container是一个类似于容器的概念,里面包含CPU和内存这两个硬件资源
container个数:containers = min (2*CORES, 1.8*DISKS, (Total available RAM) / MIN_CONTAINER_SIZE)
说明:
CORES为机器CPU核数
DISKS为机器上挂载的磁盘个数
Total available RAM为机器总内存
MIN_CONTAINER_SIZE是指container最小的容量大小,这需要根据具体情况去设置,可以参考下面的表格:
每台机子可用的RAM | container最小值 |
---|---|
小于4GB | 256MB |
4GB到8GB之间 | 512MB |
8GB到24GB之间 | 1024MB |
大于24GB | 2048MB |
每个container的平均使用内存大小计算方式为:
RAM-per-container = max(MIN_CONTAINER_SIZE, (Total Available RAM) / containers))
通过上面的计算,YARN以及MAPREDUCE可以这样配置:
配置文件 | 配置设置 | 默认值 | 计算值 |
---|---|---|---|
yarn-site.xml | yarn.nodemanager.resource.memory-mb | 8192 MB | = containers * RAM-per-container |
yarn-site.xml | yarn.scheduler.minimum-allocation-mb | 1024MB | = RAM-per-container |
yarn-site.xml | yarn.scheduler.maximum-allocation-mb | 8192 MB | = containers * RAM-per-container |
yarn-site.xml (check) | yarn.app.mapreduce.am.resource.mb | 1536 MB | = 2 * RAM-per-container |
yarn-site.xml (check) | yarn.app.mapreduce.am.command-opts | -Xmx1024m | = 0.8 * 2 * RAM-per-container |
mapred-site.xml | mapreduce.map.memory.mb | 1024 MB | = RAM-per-container |
mapred-site.xml | mapreduce.reduce.memory.mb | 1024 MB | = 2 * RAM-per-container |
mapred-site.xml | mapreduce.map.java.opts | = 0.8 * RAM-per-container | |
mapred-site.xml | mapreduce.reduce.java.opts | = 0.8 * 2 * RAM-per-container |