HDFS
Hadoop Distributed File Sysytem,分布式文件系统,适合一写多读。
组成架构
NameNode
Master,管理者
- 管理HDFS的名称空间
- 配置副本策略
- 管理数据块(Block)映射信息
- 处理客户端读写请求
DataNode
NameNode下达命令,DataNode负责执行
- 存储实际的数据块
- 执行数据块的读/写操作
Client
读/写请求客户端
- 文件切分。文件上传HDFS时,Client将文件切分成一个个Block(Hadoop 1.x 64M,Hadoop 2.x 128M),然后进行上传
- 与NameNode交互,获取文件的位置信息
- 与DataNode交互,读/写数据
- Client提供命令管理HDFS,比如NameNode格式化
- Client通过命令访问HDFS,比如对HDFS增删改查操作
Secondary NameNode
不是NameNode的热备,当NameNode挂掉的时候,不能马上替换NameNode提供服务
- 辅助NameNode,分担其工作量,比如定期合并Fsimage和Edits,并推送给NameNode;
- 紧急情况下,可辅助恢复NameNode
HDFS写流程
- 客户端通过Distribute FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已经存在,父目录是否已经存在
- NameNode返回是否可以上传
- 客户端请求第一个Block上传到哪几个DataNode服务器上
- NameNode返回3个DataNode节点,分别为dn1、dn2、dn3
- 客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,dn2调用dn3,通信管道完成建立
- dn1、dn2、dn3逐级应答客户端
- 客户端向dn1上传第一个Block,以Packet为单位,dn1收到一个Packet会传给dn2、dn3;dn1每传一个Packet会放入一个应答队列等待应答
- 当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器(重复3-7步)。
HDFS读流程
- 客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件所在的DataNode地址
- 挑选一台DataNode(就近随机原则)服务器,请求读取数据
- DataNode开始上传数据给客户端(从磁盘里面读取数据输入流,以Packet为单位做校验)
- 客户端以Packet为单位接收,先在本地缓存,然后写入目标文件
NameNode & SecondaryNameNode
NameNode启动
- 第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存
- 客户端对元数据进行增删改请求
- NameNode记录操作日志,更新滚动日志
- NameNode在内存中对数据进行增删改
Secondary NameNode工作
- Secondary NameNode询问NameNode是否需要CheckPoint,直接带回NameNode是否检查结果
- Secondary NameNode请求执行CheckPoint
- NameNode滚动正在写的Edits日志
- 将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode
- Secondary NameNode加载编辑日志和镜像文件到内存,并合并
- 生成镜像文件fsimage.chkpoint
- 拷贝fsimage.chkpoint到NameNode
- NameNode将fsimage.chkpoint重命名成fsimage
HDFS小文件处理
大量小文件元数据信息存在NameNode中,占用资源,影响查询效率
- 采用har归档方式,将小文件归档
- 采用CombineTextInputFormat
- 有小文件场景开启JVM重用;如果没有小文件,不要开启JVM重用,因为会一直占用使用到的task卡槽,直到任务完成才释放
MapReduce
Map:负责把一个任务分解成多个任务 Reduce:负责分解后多任务处理结果的汇总
MapeReduce工作流程
Shuffle机制
优化
Map阶段
- 增大环形缓冲区大小,由100m扩大到200m
- 增大环形缓冲区溢写比例,由80%扩大到90%
- 减小对溢写文件的merge次数(10个文件,一次20merge)
- 不影响实际业务的前提下,采用Combiner提前合并,减小I/O
Reduce阶段
- 合理设置Map和Reduce数:太少会导致Task等待,延长处理时间;太多会导致Map、Reduce任务间资源竞争,造成处理超时等错误
- 设置Map、Reduce共存:调整slowstart.completedmaps参数,使Map运行到一定程度后,Reduce也开始运行,减小Reduce等待时间
- 规避使用Reduce,因为Reduce用于连续数据集是将产生大量的网络消耗
- 增加每个Reduce去Map中拿数据的并行度
- 集群性能下,增大Reduce端存储数据内存大小
IO传输
采用数据压缩,减少网络IO。
- map输入端考虑数据量大小和切片,LZO要想支持切片必须创建索引
- map输出端考虑速度,snappy、LZO速度快
- reduce输出端看需求,如果作为下一个mr输入需要考虑切片,永久保存考虑压缩率大的gzip
其他
- NodeManager默认内存8G,根据服务器灵活调整。如128G内存,配置100G左。
yarn.nodemanager.resource.memory-mb
- 单任务默认内存8G,根据任务数据量灵活调整,如128M数据,配置1G内存。
yarn.scheduler.maximum-allocation-mb
mapreduce.map.memory.mb
:控制分配给MapTask内存上限,超过会kill掉进程。默认内存1G,当数据量大于128M是。可以增加MapTask内存,最大到4-5Gmapreduce.reduce.memory.mb
:控制ReduceTask内存上限,默认内存大小1G,如果数据量大于128M,可增加ReduceTask内存大小4-5Gmapreduce.map.java.opts
:控制MapTask对内存大小mapreduce.reduce.java.opts
:控制ReduceTask堆内存大小- 增加MapTask、ReduceTask的CPU核数
- 增加Container的CPU核数
- 在hdfs-site.xml中配置多目录
- NameNode由一个工作线程池,用来处理不同DataNode的并发心跳以及客户端并发元数据操作。
dfs.namenode.handler.count = 20 * log2(Cluster Size)
,比如集群规模为10台,此参数设置为60
Yarn
作业提交
- Client调用job.waitForCompletion方法,向集群提交MapReduce作业
- Client向RM申请一个作业id
- RM给CLient返回该job资源的提交路径和作业id
- Client提交jar包、切片信息和配置文件到指定的资源路径下
- Client提交完资源后,向RM申请运行MrAppMaster
作业初始化
- 当RM收到Client请求后,将该job添加到容量调度器中
- 某一个空闲的NM领取到Job
- 该NM创建Container,并产生MRAppMaster
- 下载Client提交的资源到本地
任务分配
- MrAppMaster向RM申请运行多个MapTask任务资源
- RM将运行MapTask任务分配给另外两个NodeManager,另两个NodeManager分别领取任务并创建容器
任务运行
- MR向两个接收任务的NodeManager发送程序启动脚本,分别启动MapTask,MapTask对数据分区排序
- MrAppMaster等待所有MapTask运行完毕后,向RM申请容器,运行ReduceTask
- ReduceTask向MapTask获取相应分区的数据
- 程序运行完毕后,MR向RM申请注销
进度和状态更新
YARN中的任务将其进度和状态返回给应用管理器,客户端每秒(通过mapreduce.client.progressmonitor.pollinterval设置)向应用管理器请求进度更新,展示给用户
作业完成
除了向应用管理器请求作业进度外,客户端每5秒都会通过调用waitForCompletion()来检查作业是否完成。
资源调度器
- FIFO:单队列,先进先出,生产环境不用
- Capacity Scheduler 容量调度器:多队列,保证先进入的任务优先执行
- Fair Sceduler 公平调度器:多队列,保证任务公平享有队列资源
Hadoop宕机
- 如果MR造成系统宕机,要控制Yarn同时运行的任务数,和每个任务申请的最大内存。调整参数
yarn.scheduler.maximum-allocation-mb
(单个任务可申请的最多物理内存量,默认8192M) - 如果写入文件过快造成NameNode宕机,则调高Kafka的存储大小,控制从Kafka到HDFS的写入速度。
Hadoop数据倾斜
- 提前在map端combine,减少传输的数据量
- 导致数据倾斜的key分布在不同的mapper
- 局部聚合 + 全局聚合,第一次MapReduce对导致了数据倾斜的key加上1到n的随机数,使原本相同的key分到多个Reducer中进行局部聚合;第二次MapReduce取消key的随机前缀,进行全局聚合
- 增加Reducer,提升并行度,
JobConf.setNumReduceTasks(int)
- 实现自定义分区,根据数据分布情况,自定义散列函数,将key均匀分配到不同的Reducer