hadoop及其生态圈回顾大杂烩

hdfs写流程

图片来源于尚硅谷

  1. 由命令向客户端发送要存储数据的信息,客户端想要处理这个命令肯定是要又一个具体的客户端对象,遂创建一个dfs(distributed file system)类型的客户端,随后它向namenode发送请求,想要上传文件到/user/atguigu
  2. namenode收到请求后检查目录树是否可以创建文件,这个检查分两点,第一点检查权限(用户是否拥有对应的文件或目录的写权限),第二点是检查目录结构,看这个目录是否存在,不存在或没有写权限就回应不能上传文件,对应目录存在并且有相应的写权限,响应客户端可以上传文件。
  3. 客户端收到可以上传文件的相应,就请求上传第一个文件块(大小在0-128M),希望namenode返回准备存储的具体位置就是具体的存储节点datanode。
  4. namenode收到请求上传文件块,开始选择存储节点,这个选择有三方面因素,第一点是考虑负载均衡,避免某些节点负载过高导致系统性能下降;第二点是可靠性,选择可靠性较高的节点(某些节点可能存在某些原因经常挂掉);第三点是机架感知,优先选择本地节点,其次选择其他机架的一个节点,再选择其他机架的另一个节点,这其实是考虑到传输效率和可靠性做出的方案.存储节点选择完,向客户端发送最终方案。
  5. 客户端收到方案,hdfs client创建具体的数据流fsdataoutpurstream来写数据,由它向存储节点传递数据,客户端首先向一个副本节点发送请求建立block传输通道,第一个副本节点收到请求,由它向下一个原先方案的存储节点发送请求简历通道,如此如此,直到最后一个方案存储节点与上一个存储节点的通道建好
  6. 客户端收到第一个存储节点的应答成功,客户端开始创建一个缓冲队列,这缓冲队列里的最小单位是chunk(512byte+4byte的校验位),攒够64k时候形成一个packet(64k),这是传输数据的最小单位,然后创建一个ack队列来备份这一个packet,防止传输出错,可以将他再发送出去,提高可靠性和效率,由fsdataoutputstream开始传输数据packet
  7. 之后等待每发一份packet,都在本地备份好并且后一个存储节点也发送成功回应后会向上一个存储节点发送成功请求,如此如此,直到第一个存储节点向客户端发送应答成功,才将ack队列里的那份备份删除
  8. 看图中感觉每一个datanode是串联,实际并不是,每一个datanode中有一个bytebuffer,一边将收到的数据packet备份在本地,一边又向下一个datanode发送数据packet,实际是并行执行的。

hdfs读流程

  1. 由命令触发读数据,客户端创建dfs类型的hdfs client向namenode发送下载文件请求

  2. namenode收到请求判断对象是否有权限下载文件,以及验证这个文件是否存在,如果满足就返回目标文件的元数据

  3. 客户端开始创建fsdatainputStream流读数据,并向有目标文件块的最近存储节点发送读数据请求,这中间还要考虑最近的存储节点的负载情况,如果有很多流正在读就选择下一个有文件块1的存储节点

  4. 文件块1的存储节点开始向客户端传输数据

  5. 等到文件块1完成传输才能开始下一文件块的读取流程


fsimage

fsimage是文件系统元数据的镜像文件,其中包括文件系统的所有目录和文件inode及相关属性的序列化信息。

fsimage是内存中的元数据在硬盘上的checkpoint,它是一种序列化的格式,并不能够在硬盘上直接修改。

editslog

editslog是Hadoop分布式文件系统中的日志文件,主要记录的是在namenode启动后,所有对目录结构的增删改操作。

editslog文件并不会实时同步更新到fsimage中,实际上是发生在namenode启动的过程中。加载fsimage文件和edits文件到内存,然后在内存将fsimage和edits文件进行合并,再将合并后的文件写入到fsimage,最后清空原先edits中的数据,使用一个空的edits文件进行正常操作。

两者的存放地址是namenode和secondary name node安装的节点的$HADOOP_HOME/data/dfs/name/current中

如果增删改操作非常多,editslog文件很大,那每次namenode启动的过程就会非常缓慢,这个时候2nn(secondary name node)就闪亮登场,定期将两者合并

图片来源尚硅谷

2nn协助nn来管理editslog和fsimage的合并,以此来减少下次由于editslog记录数过多导致的namenode启动慢问题

  • 2nn里有一项功能叫checkpoint,由他来将editslog和fsimage合并
  • checkpoint的触发条件时定时时间和观察edits中的数据是否满了,每次一到设定的定时时间就会向nn询问是否需要checkpoint,如果edits中的数据达到某个值,2nn也会向nn请求执行checkpoint
  • 如果需要执行checkpoint,会将原先的editslog:edits_inprgress_001更名为edits_001,并产生一个新的editslog:edits_inprogress_002继续负责接下来的记录工作,将edits_001传输到2nn;fsimage也拷贝一份到2nn,在2nn中将两者加载到内存中合并,计算完成生成新的fsimage:fsimage.chkpoint再传回nn,并重命名成fsimage,覆盖原先的fsimage


 mapreduce流程

  1. 准备计算的待处理文件传给客户端
  2. 客户端submit()前,根据参数配置将原始数据进行切片
  3. 客户端准备三样东西job.split(切片信息),wc.jar(本地模式不需要,集群模式需要jar包来完成一些工作),job.xml(job运行的相关参数)向yarn的resource manager提交
  4. resource manager接受这三样东西后,开启一个mrappmaster(整个任务运行的老大)来读取这客户端提交的三样东西,尤其主要读取job.split,根据job.split开启相应数量的maptask
  5. maptask开启后,用inputformat读取文件,默认是textinputformat,inputformat有一个方法是recorderReader,textinputFormat的recorderReader是lineRecorderReader(按行读取),将读取的数据包装成map类型,key是偏移量,value是对应一行的内容,textInputFormat读完数据将结果给mapper,这里面是用户自己编写的业务逻辑,运算结束后将结果发送给outputCollector(环形缓冲区) 
  6. 唤醒缓冲区就是一个内存,这个内存的特点可以抽象为:在左边存放索引(描述数据的元数据),在右边存放数据.实实在在的数据有key,有value,索引有index(对应map处理后数据的编号),partition(也是map处理的标记),keystart(记录真实数据的key在哪),valstart(记录真实数据的value在哪).
  7. 环形缓冲的默认大小是100M,到达80%的时候进行反向溢写,为什么反向溢写呢?假设我们到100%的时候才溢写,那么我们就必须等待这个溢写工作完成一部分有空间了才能进行将map的结果写到环形缓冲区,这就成了串行,这个效率是非常低下的;但80%反向溢写的话,我们的数据就有足够的时间去溢写文件到硬盘,而且从map中出来的结果也能往环形缓冲区写,这样两个线程同步工作,效率就高起来了.80%反向溢写可能会产生一个现象,就是map出来的结果太快,会不会将原有的数据覆盖掉?答案是不会,hadoop在设计时就控制了这一现象,如果发现反向溢写速度过快,就暂停反向溢写,等待原数据的溢写完成再让反向溢写继续
  8. 当数据从map处理后到环形缓冲区时就会按分区划分,并且对数据进行快排,但并不是从map里出来一条就排一条,而是等到环型缓冲区内存占用到80%前进行排序.这里的快排不是针对kv来排的,因为此时的kv,是在环形缓冲区右边,在类似集合或数组的容器中,让他们进行移位并不方便,而移位这个操作又能对应前面索引里的ketstart和valstart这种指针,可以更改ketstart和valstart记录的地址来达到移位的效果
  9. 等待环型缓冲区里的数据全部溢写出来,此时溢写出来的n个文件有分区效果且分区内有序,但此时有多个溢写文件,我们就将这些溢写文件都合并起来形成一个文件,这个文件是存放在磁盘上的,由于此时已经是排好序的,所以对于排好序的数据再排序使用归并排序最好,我们做到分区内有序即可,分区间有序无序不重要,因为后面一个reduce task拉取数据只管拿一个分区,不管拿第几个分区
  10. 这里有个可选过程combiner,可以提前将数据聚合,以此来减少数据的大量传输,这是一个优化手段,不适合全部的场景
  11. 同样的每个maptask都会经历这样的过程
  12. MrappMaster会观察每个maptask的任务进展,等到所有MapTask任务完成后(不绝对,我们可以设置maptask完成几个后开展reducetask),启动相应数量的ReduceTask,并告知ReduceTask处理数据范围(数据分区)
  13. 对应分区的reducetask会主动拉取每个maptask对应分区的数据并进行merge归并,虽然每个maptask归并排序后的数据在分区内是有序的,但是实际会有多个maptask,reduce task拉取这多个map task的数据之间就不一定是有序的,就需要再次排序,这样再次合并文件归并排序后再传入reducer的reduce方法就方便了,就能做到一次读取一组
  14. reducer操作完成后就能使用核心组件outPutFormat往外写了,默认类型是TextOutPutFormat,OutPutFormat有recordWriter方法来实际写文件

yarn工作流程

  1. xxx.jar在命令行上被调用,main方法的最后一行是job.waitForCompletion(),在这个方法里就会创建一个yarnrunner,本地模式的时候是localrunner
  2. yarnrunner向resourceManager申请一个application
  3. resourceManager接收申请后,检查完有足够资源给yarnrunner返回application资源提交路径以及application_id
  4. 提交job运行所需资源,job.submit()后生成三样文件,job.split(切片信息),job.xml(参数),wc.jar(jar包):job.split未来可以控制开启多少个maptask;job.xml可以控制任务按设置的参数执行,wc.jar就是程序代码.
  5. 资源提交完毕,向resourceManager申请运行mrAppMaster
  6. resourceManager接收到申请,在resouceManager内部产生一个任务,由于客户端实际数量会很多,会产生很多任务,所以将这些任务就都放到任务队列里,默认是一个容量调度器
  7. 此时一个空闲的nodemanager就会将领取一个task任务,领走任务后nodemanager首先创建一个容器container,这个容器里有网络资源,磁盘io,cpu等等资源,container容器里会启动一个mrAppmaster进程
  8. mrAppmaster进程会去application资源提交路径上下载job资源(job.split)到本地,拿到对应的切片信息后,mrAppmaster会向resourceManager申请运行MapTask容器
  9. 假设这个申请是要开启两个maptask,此时另外空闲的两个nodeManager就会领取任务,开启两个container容器,并获得相应资源(只是举例,一个nodeManger可以开启多个container容器)
  10. 由mrAppmaster发送启动命令(程序启动脚本),到对应container容器启动maptask,这时候就会开启两个进程yarnchild,maptask执行好后就会将相应结果持久化到磁盘
  11. mrAppmaster监控得知maptask执行好了就会再向resourceManager申请2个容器,运行reduceTask程序,对应的就会有两个nodeManager(举例说明,一个nodeManager可以开启多个container)开启两个container并运行reduceTask,同样的这时候就会有两个进程yarnchild,准备好了后reduce会向map获取相应分区的数据并开始执行任务
  12. 待任务执行完成后,mrAppmaster会向resouceManager发送提示程序运行完毕,让resourceManager释放相应容器的资源

定个小目标,背八股文,发现疑难杂症理清记录,大概在晚11点左右更新完文章

接下来需要回顾的有关hadoop生态圈,重点会放在项目回顾上(回顾数据仓库建模流程文章中)

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值