Hadoop

Hadoop面试题: link.

1.查看依赖包源码,出现以下错误
在这里插入图片描述
解决方法

链接: link.

入门

1.常用端口号

HDFS NameNode 内部通讯端口:8020、9000、9820
HDFS NameNode 对用户得查询端口:9870
Yarn查看任务运行情况得:8088
历史服务器:19888

2.常用配置文件

core-site.xml
hdfs-site.xml
yarn-site.xml
mapred-site.xml
workers

2.集群

2.1集群的配置

集群部署规划

  • NameNode和SecondaryNameNode 不要安装在同一台服务器上
  • ResourceManager也很消耗内存,不要和NameNode、secondaryNameNode配置在同一台机器上
  • 一个集群中,有一个ResourceManager和一个secondaryNameNode和一个NameNode
  • 一个集群中的老大是ResourceManager,一台服务器上的老大是NodeManager,一个任务的老大是mrAppMaster
  • 集群中,每台服务器上都有一个NodeManage多个Datanodes
  • 每个Datanodes上存储多个数据块
  • container容器:容器就相当于一个小电脑,在拉镜像的时候,首先拉取的是centos或者Ubuntu,然后是javase等。他和宿主机共用一套硬件,但是是分开的。不同容器之间都是独立的。使用完就释放掉,和datanode没关系,datanode是存储数据的。为什么要用容器呢?
    1.比如说某个应用程序只有在linux下才有,如果在windows下安装那么就需要配置环境,非常麻烦,这时候就可以开启一个容器,相当于一个linux系统,在windows下就可以开启容器,使用这个软件
    2.在电脑1上写的程序想共用给其他电脑,那么就需要环境+代码完全一致,这时就可以把他封装为一个容器。
    3.比如hadoop,是分布式计算框架,不同计算机之间交互。
  • cpu:包括核、高速缓存等
  • 线程:一个cpu一般会带动两个以上线程并发运行。可以理解为一个任务对应一个线程。

集群组成

项目Hadoop102Hadoop103Hadoop104
HDFSNameNode DataNodeDataNodeDataNode SecondaryNameNode
YARNNodeMamagerNodeMamager ResourceManagerNodeMamager

2.2 HDFS、YARN、Mapreduce的关系

3HDFS

定义:本质是一个文件系统,但是其不只能存储文件,还可以进行分布式计算,HDFS分布式文件系统也是一个主从架构,主节点是我们的namenode,负责管理整个集群以及维护集群的元数据信息,从节点datanode,主要负责文件数据存储
在这里插入图片描述

HDFS中包括NameNode和DataNode。
NameNode是整个文件系统目录,基于内存存储,存储的是一些文件的详细信息,比如文件名、文件大小、创建时间、文件位置等。

DataNode是文件的数据信息,也就是文件本身,但是是分割后的小文件(分块),以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和以及时间戳。

1.文件块大小

HDFS的文件在物理上是分块存储不同的块可以在不同的服务器上,由datanode实际存储,所有datanode的元数据存储在namenode中,在企业中,一般是128m。

2.HDFS得shell操作

3.HDFS得读写流程

3.1写入数据的流程

相当于两个人的对话,目的是客户端要将数据传到集群

  • 首先,HDFS客户端要先创建一个分布式的文件系统(默认是本地local),向namenode请求,告诉它我要将某某文件传送到集群中的/use/atguigu/文件下
  • namenode在接收到请求后,对其进行一个校验(不是谁想传什么就可以的),检查目录树是否可以创建文件(1)检查该客户端是否有权限写入(因为每一个文件都有所在的用户和用户组)(2)检查目录结构是否存在(如果该文件下,有这个文件,就不能再写入了)
  • namenode检查之后,可以上传文件,对客户端有一个相应,告诉他可以上传
  • 客户端接收到namenode的回应后,请求上传第一个块文件(block),并且请求namenode返回datanode的结点,因为集群上有很多结点,不是客户端想传到哪里都可以的,所以需要namenode给它返回来一个datanode,也就是上传的结点位置 往哪一个位置上传
  • 然后namenode返回给客户端dn1,dn2,dn3三个结点,告诉客户端这三个节点可以存储数据(如何选择副本存储节点,首先选择本地节点,然后是同一个机架的其他节点,然后是其他机架的节点)
  • 然后,客户端创建一个数据流(FSDataOutputFormat) 往出写数据了

重点 :如何写数据呢???采用流式发送

  • 首先与保存此文件第一个数据块最近的Datanode建立传输通道,请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将整个通信管道建立完成
  • dn1,dn2,dn3逐级应答客户端
  • 应答之后,客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存中缓存),Datanode1中,一份数据往磁盘里面写,另一份在内存中直接传给下一个节点
  • 发送的这个数据流里面,最小单位是packet(64k)
  • 首先,传输数据流的时候,首先产生一个缓冲队列,存储的是chunk是512字节,加上4个字节的校验位,当它攒到64k的时候,就会成为一个packet(线形成chunk,然后形成packet,形成一个一个的packet之后,发送给datanode)

详细流程
如果要将一个200m的文件存到HDFS集群中
链接: link.

3.2读数据的流程

  • 集群中有数据,集群中有 NameNode ,存储着元数据,有什么文件,块信息在哪,DataNode 存储的是真正的块信息。
  • 客户端向NameNode请求读取集群的数据。
  • 首先客户端创建一个对象,和NameNode进行交涉,创建DistributedFileSystem分布式系统对象进行访问
  • 向NameNode请求下载文件
  • NameNode首先判断这个对象有没有访问权限,然后检查集群上有没有这个文件,检查完毕后
  • 向分布式系统对象返回目标文件的元数据
  • 客户端开始读取数据,创建一个FSDataInputStream流对象,请求读取blk-1,选择节点最近的读取数据,同时要考虑当前节点的负载能力,读取完blk-1之后,开始请求读取blk-2。
  • 串行读取,先读取blk-1,存储之后,再读取blk-2
  • 最后关闭资源

4MapReduce框架原理

1.切片与MapTask并行度

  • MapTask是开启越多越好吗,不是,因为开启的时间会更长
  • MapTask由切片数决定,一个切片分配一个MapTask并行处理
  • 默认下,切片大小= 块大小(块是物理存储单位,一般为128m)
  • 每个文件单独切片

2.job提交流程

  • job提交的代码:waitForCompletion()
  • 然后submit(),进入提交流程
  • 进入到提交的代码中,setUseNewAPI 处理的是新旧API的兼容性问题
  • (1)然后到connet() 连接:如果和集群连接,则会有一个yarn客户端;如果和本地的客户端连接
  • 进入到connect()之后,进入到 return new Cluster(getConfiguration())
  • 初始化initialize()
  • (2)提交job信息submitter.submitJobInternal()
  • checkSpecs 检验是否给了输出参数,并且校验给出的输出路径是否存在
  • Path jobStagingArea = JobSubmissionFiles.getStagingDir(cluster, conf) 创建给集群提交数据的stag路径,生成一个临时路径
  • JobID jobId = submitClient.getNewJobID() 每提交一个任务,就会创建一个独一无二的JobID
  • copyAndConfigureFiles(job, submitJobDir):如果是集群模式,会提交jar包(把jar包拷贝给集群),如果是本地模型,则不会提交jar包
  • writeSplits(job, submitJobDir) 计算切片个数
    maps = writeNewSplits(job, jobSubmitDir) 进入到方法里
    input.getSplits(job),JobSplitWriter.createSplitFiles(jobSubmit,),在staging路径里面加上了split切片信息,真正形成了split切片文件
  • conf.setInput
  • writeConf(conf,submitJobFile) 提交xml信息,默认配置提交三样东西,split,xml,jar包(如果是集群模式)
  • status由define变成running,开始运行job

3.切片流程

FileInputFormat实现类:下面包括TextFileInputFormatCombineFileInputFormat

  • 1.每个文件单独切片
  • 2.切片大小和块大小相同
  • 3.如果想改变切片大小,把最小值调成大于32m,那么切片大小就大于32m,如果最大值调成小于32m,那么切片大小就小于32m,为什么是32m,因为本地模式的块大小默认是32m,集群模式是128m
  • 4.如果是32.1m的文件,物理上仍然在两块上,但是只有一个切片,只存一片,相除大于1.1倍,分成两片,如果小于1.1倍,分成一片处理 while(((double) bytesRemaining)/splitsize >SPLIT_SLOP)
  • isSpiltable(Job,Path),说的是文件是否支持切片,有的情况,比如压缩就不支持切片

切片过程:

  • 首先,程序要先找到存储数据的目录
  • 然后,开始遍历目录下的每一个文件
  • 遍历第一个文件
    • 获取文件大小fs.sizeOf(ss.txt)
    • 计算切片大小
    • 默认情况下,切片大小等于块大小
    • 将切片信息写入到一个切片规划文件中split文件
    • 整个切片的核心过程在getSplit()方法中完成
    • InputSplit只记录了切片的元数据信息,比如起始位置等
  • 提交切片规划文件到YARN上,YARN上的MrAppMaster就可以根据切片规划文件计算开启MapTask个数

TextInputFormat

CombineInputFormat

4.MapReduce

1. InputFormat

(1)默认得式TextInputFormat kv,key是偏移量,v是一行内容
(2)处理小文件CombineTextInputFormat 把多个文件合并到一起统一切片

2.Mapper

setup():处理初始化
mapper():用户得业务逻辑
clearup():关闭资源

3.Shuffle

一、首先分区:默认分区HashPartitioner,默认按照key得hash值 % numreducetask个数
二、排序:1)部分排序,每个输出得文件内部有序,
2)全排序:一个reduce,对所有数据大排序
3)二次排序:自定义排序范畴,实现一个writableComparable接口,重写compareTo方法

4.combiner

前提:不影响最终得业务逻辑(求和可以,平均值不行)
提前预聚合,是在map端完成的,解决数据倾斜得方法

5.reducer

用户得业务逻辑
setup():初始化
reduce:用户逻辑
clearup():关闭资源

6.outputFormat

默认是textoutputFormat

  • 首先,有一个待处理的文本
  • 客户端:Job任务提交submit前,获取待处理数据的信息,然后submit()提交之后,根据参数配置,形成一个任务分配的规划。
  • 客户端提交之后,会准备split,xml(job运行的一些参数)和jar提交给yarn
  • yarn会开启Mrappmaster:整个任务运行的老大,读取客户端的信息,最主要的就是读取split切片信息来计算出MapTask的数量( 在这之前都是job的提交流程,还没有进入到map方法
  • Mrappmaster开启对应的 MapTask,启动之后开始工作,首先读取待处理文件,使用InputFormat(使用默认的TextInputFormat),这里面有两个方法,RecorderReader(按行进行读取)和isSplitable是否切割,k是偏移量,v是一行内容。(read读取阶段
  • 读取完之后,返回给Mapper(用户自定义的逻辑运算,按照业务需求)(map阶段
  • Mapper处理之后,输出到环形缓冲区(相当于内存)一般是索引(元数据),另一半是数据。环形缓冲区默认是100m,当到达80%之后反向溢写,指的是新开一个线程把在环形缓冲区的数据溢写到磁盘上,因为还没有达到100%,所以另一个线程继续把从Mapper来的数据写到内存中。
  • 从Mapper到环形缓冲区的数据,首先就把数据标记了分区信息,在溢写的时候,对分区内部的数据进行排序(使用快排),什么时候开始排序呢?是在缓冲区数据达到80%进行溢写的时候进行排序,对索引(元数据)进行排序。(在环形缓冲区的分区排序都属于collect阶段
  • 到达80%的时候,就会将环形缓冲区的数据溢写到磁盘上,有多个溢写文件,此时的数据是分区且区内有序的。(溢写阶段
  • 然后进行merge归并排序将文件合并为一个大文件,保证每一个分区内是有序的,分区整体之间没有序,因为将来要发送到不同的reducetask上,归并之后的文件永久存在磁盘上merge阶段
  • Combiner是在reduce之前可以进行预聚合的,优化的手段,但不是所有场景都适合
  • yarn的MrappMater会观察到,所有的MapTask任务完成后,启动相应数量的ReduceTask
  • reduceTask主动从多个MapTask对应的分区拉取数据(copy阶段
  • 然后,将从不同MapTask拉取过来的数据,进行一个全局归并排序(为什么进行排序呢,因为进入到reduce方法里的是相同key的内容)(sort阶段
  • reducer一次读取一组,相同的key进入到reduce方法
  • reduce处理完之后,往出写。由核心组件OutPutFormat中默认的TextOutputFormat的RecoderWriter方法往出写,形成了对应的文件。(reduce阶段

MapTask工作机制

  • 一共分成五个阶段read、map、collect、溢写、merge
MapTask源码解析
  1. 首先进入到context.write方法
  2. 进入到collect收集器,收集器里有个参数partitioner,有个方法getpartition(),因此首先进行分区
  3. 然后再进入到collect环形缓冲区,注意一下keystart和valstart支持序列化
  4. 写出一条即一行内容,然后又回到map方法
  5. 到最后一行内容之后,进入到collect,结束之后
  6. 不进入到map方法,而是cleanup方法,跳出来,走到close()
  7. 进入到close()之后,走到collector.flush()刷写,进入到flush之后,走到sortandSpill,进入,走到sort方法,有快排的方法然后按照分区开始溢写
  8. 然后走到mergeParts进行归并,遍历所有的溢写文件,进行merge排序,归并之后,产生file.out.index文件
  9. 然后,collector.close()收集器结束

ReduceTask工作阶段

  • 一共分成三个阶段copy、sort、reduce

ReduceTask源码

  • if(isMapOrReduce())进入
  • 首先初始化

Shuffer机制

在map和reduce端都有,在Map方法之后,Reduce之前的数据处理流程
,混洗过程

  • 最先进入到getPartition方法,标记数据的分区
  • 标记完分区后,进入到环形缓冲区,缓冲区的大小是100m,左侧索引,右侧数据,当缓冲区的数据达到80%时候,进行反向溢写,即新开一个线程将数据从缓冲区存入到磁盘中,原来的线程继续将数据存到环形缓冲区
  • 在溢写之前,对分区内数据进行排序,排序方式是快排,对key的索引排序,按照字典顺序排序
  • 排序之后,第一次溢写,溢写会产生两个文件,spill.index和spill.out,combiner是可选的流程,在溢写前
  • 然后将每个分区内的文件进行归并排序,然后还可以进行combiner,combiner之后,还可以进行压缩(压缩之后传输的效率高)
  • 最后,所有的内容写到磁盘上
  • map之后,reduce将对应分区的数据拉取,首先拉取到内存中,内存不够则溢写到磁盘上,然后进行归并排序
  • 按照相同的key分组,相同key的数据进入到reduce方法中

分区

  1. 需求:要求将统计结果按照条件输出到不同文件中
  2. 默认分区partition:哈希分区,原理是根据key的hashcode对ReduceTask个数取模得到的,因此用户没法控制哪个key存储到哪个分区
  3. 用户可以自定义partitioner,首先自定义类继承partitioner,重写getPartition()方法,然后在Job驱动中,设置自定义Partition(job.setPartitionerClass(CustomPartitioner.class));自定义Partition后,要根据自定义Partitioner的逻辑设置相应数量的ReduceTask(job.setNumReduceTasks(5))
  4. 分区总结
    (1)如果ReduceTask的个数大于getPartition的结果数,则会产生几个空的输出文件
    (2)如果ReduceTask的个数小于getPartition的结果数,则会报错
    (3)如果ReduceTask的个数等于1,则不管MapTask输出几个分区文件,最终结果都会交给一个ReduceTask,最终只会产生一个文件
    (4)分区号必须从0开始,逐一累加

排序

  1. 在Map阶段,进行了两次排序,分别是快速排序和归并排序,一次是溢写到磁盘之前,对缓冲区中的数据进行一次快速排序,另一次是当所有数据处理之后,对磁盘上的所有溢写文件进行归并排序,两者都是在分区内排序,都是对key的索引进行排序。最终磁盘上存储的是,每个MapTask有一个区内排序的文件,每个MapTask一个文件
  2. 在Reduce阶段,进行了一次归并排序,首先是拉取每个MapTask中的相应分区的文件,进行一次归并排序
  3. map和reduce过程均会对数据按照key进行排序,是默认行为,必须排序
  4. 如果要进行自定义排序怎么办呢
    案例:对手机号的流量进行排序,如果将bean对象做为key传输,必须支持排序,因此需要实现WritableComparable接口(集成了Writable和Compatable接口),重写里面的CompareTo方法(序列化的时候是实现的Writable接口)

combiner组件

5 Yarn

5.1Yarn的工作机制

两个角色:job 和 ResourceManger

  • 在命令行上执行wc.jar ,main()方法里面job.waitForCompletion(),创建一个YarnRunner,在本地模式得时候是LocalRunner
  • YarnRunner向集群申请一个Application——运行一个应用
  • ResourceManager(集群得老大)让YarnRunner把运行得job资源和application_id放在指定的集群路径上

hdfs://…/.staging以及任务的application_id

  • job将job.split、job.xml、wc.jar(是在job.submit()生成的) 提交到集群给的资源路径里面

形成hdfs://…/.staging/application_id路径

  • 资源提交完毕后,向resourcemanager申请运行mrAppMaster
  • 在ResourceManager内部,会产生一个任务Task,同时,其他客户端也会产生任务,所以,ResourceManager内部有多个任务,将其放在一个任务队列
  • 空闲的NodeManager会把在ResourceManager队列里的任务领取走
  • 创建容器任何任务的执行都在容器中,每个容器中有cpu,ram。启动一个mrAPPmaster进程
  • mrAPPmaster 去集群资源的路径上读取Job.split,读取切片信息,然后向集群申请运行对应的MapTask容器,如果是两个split,开启两个maptask,开启两个容器(可能在一个节点上,也可能在两个)
  • 空闲的nodemanager领取任务,创建容器
  • MRAppmaster向两个nodemanager上发送启动脚本,运行Maptask任务,开启两个yarnchild,开始运行
  • MapTask运行结束之后,把数据按照分区存储在磁盘上,计算结束之后,MRAPPmaster知道任务执行完了
  • Mrappmaster再次向ResourceManager申请两个2个容器用来运行ReducerTask程序,因此ResourceManager中的任务队列中又有了两个任务task
  • 空闲的NodeManager领取到任务后,开启容器,运行reducetask程序,开启yarnchild,开始运行任务
  • reducetask执行完之后,整个程序运行完了,mrAppMater向ResourceManager注销自己,释放资源

5.2的调度器

  • FIFP/容量/公平
  • apache默认调度器 容量;CDH默认调度器 公平
  • 公平 /容量默认一个default队列,满足不了需求,需要创建多个队列
  • 多个调度器的命名 :中小企 hive spark flink mr; 大企业:业务模块 登录/注册/购物车/营销
  • 好处 :解耦 降低风险 11.11 6.18降级使用
  • 每个调度器的特点
    1.相同点:支持多队列,可以借调资源,支持多用户
    2.不同点:容量:优先满足先进来的任务执行;公平:进入到队列里面的任务公平享有队列资源(在一定时间内)
  • 生产环境下: 中小企业:对并发度不高,容量 ;重大企业:对并发度要求高,选择公平。

5.3开发需要重点掌握

  • 队列运行原理
  • yarn命令:查看日志,容器
  • 核心参数配置
  • 配置容量调度器和公平调度器
  • tool接口使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值