Hadoop
HDFS
组成
HDFS主要有两个要素组成,NameNode和DataNode
-
NameNode
-
元数据节点,类似于数据的目录,在响应请求的时候,会现在NameNode中查找数据存放在哪个DataNode中,类似与一本书的目录
- 管理HDFS的名称空间
- 配置副本策略
- 管理数据块(Block)映射信息
- 处理客户端读写请求
-
-
DataNode
-
数据节点,真正存放数据的地方
- 存储实际的数据块
-
HDFS的文件是按块进行存储的,Block,块的大小可以根据参数设定dfs.blocksize,默认情况下,在Hadoop1.x是64M,在Hadoop2.x、3.x是128M。
块的大小不能设置过大也不能设置过小,设置过小会增加寻址时间,设置太大,从磁盘传输数据的时间会明显大于定位到这个块开始位置的时间。正常来说,块大小的设置要按照磁盘的读取速率进行选择。
查找到目标文件的时间我们称之为寻址时间,寻址时间为传输时间的1%时,我们认为效果最佳
HDFS API
使用shell操作HDFS时候,可以有两种命令选择,hadoop fs\hdfs dfs,然后在后面加上相应的命令即可
- hadoop fs
- hdfs dfs
读写流程
-
读流程
- 1、客户端通过 DistributedFileSystem 向 NameNode 请求下载文件,NameNode 通过查询元数据,找到文件块所在的 DataNode 地址
- 2、挑选一台 DataNode(就近原则,然后随机)服务器,请求读取数据
- 3、DataNode 开始传输数据给客户端(从磁盘里面读取数据输入流,以 Packet 为单位来做校验)
- 4、客户端以 Packet 为单位接收,先在本地缓存,然后写入目标文件
-
写流程
- 1、客户端向NameNode提出请求写入数据
- 2、NameNode返回是否可以上传
- 3、客户端请求第一个 Block 上传到哪几个 DataNode 服务器上
- 4、NameNode 返回 3 个 DataNode 节点,分别为 dn1、dn2、dn3
- 5、客户端通过 FSDataOutputStream 模块请求 dn1 上传数据,dn1 收到请求会继续调用dn2,然后 dn2 调用 dn3,将这个通信管道建立完成
- 6、dn1、dn2、dn3 逐级应答客户端
- 7、客户端开始往 dn1 上传第一个 Block(先从磁盘读取数据放到一个本地内存缓存),以 Packet 为单位,dn1 收到一个 Packet 就会传给 dn2,dn2 传给 dn3;dn1 每传一个 packet会放入一个应答队列等待应答
- 8、当一个 Block 传输完成之后,客户端再次请求 NameNode 上传第二个 Block 的服务器。(重复执行 3-7 步)
DataNode 工作机制
- 1、一个数据块在 DataNode 上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳
- 2、DataNode 启动后向 NameNode 注册,通过后,周期性(6 小时)的向 NameNode 上报所有的块信息
- 3、心跳是每 3 秒一次,心跳返回结果带有 NameNode 给该 DataNode 的命令如复制块数据到另一台机器,或删除某个数据块。如果超过 10 分钟没有收到某个 DataNode 的心跳,则认为该节点不可用。
掉线时限参数设置
- 1、DataNode进程死亡或者网络故障造成DataNode无法与NameNode通信
- 2、NameNode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。
- 3、HDFS默认的超时时长为10分钟+30秒。
HDFS小文件处理
- 小文件的危害
- 存储层面:会占用存储空间
- 计算方面:每一个小文件都会起一个MapTask,会占用大量的计算资源
- 解决:
- 采用har归档方式
- 采用ConbineTextInputFormat
- 有小文件场景开启JVM重用;如果没有小文件,不要开启JVM重用,因为会一直占用使用到的task卡槽,知道任务完成才能释放。JVM重用可以使得JVM实例在同一个job中重新使用N次,N的值可以在Hadoop的mapred-site.xml文件中进行配置,通常在10-20之间
MapReduce
Map
- 会对每一个<K,v>调用一次map方法
- 继承Mapper父类,重写map方法
- 输出形式为<K,v>
Reduce
- 继承Reducer父类,重写reduce方法
- 相同key的<k,v>调用一次reduce方法
- 输出形式为<k,v>
driver
- 提交的是一个job
序列化和反序列化
-
自定义的bean类要实现Writable接口
-
重写write序列化方法
- out.writeLong(upFlow);
-
重写readFields反序列化方法
- upFlow = in.readLong();
分区
-
继承Partitioner类,重写getPartition方法
-
在job驱动中,设置自定义的partition
- job.setPartitionerClass(CustomPartitioner.class);
-
自定义Partition后,要根据自定义Partitioner的逻辑设置相应数量的ReduceTask
- job.setNumReduceTasks(5);
排序
- mapTask和reduceTask均会按照key进行排序,默认排序使用的是字典排序,快速排序
- 对于MapTask,它会将处理的结果暂时放到环形缓冲区中,当环形缓冲区使用率达到一定阈值后,再对缓冲区中的数据进行一次快速排序,并将这些有序数据溢写到磁盘上,而当数据处理完毕后,它会对磁盘上所有文件进行归并排序。
- ReduceTask统一对内存和磁盘上的所有数据进行一次归并排序
- bean对象实现WritableComparable 接口重写 compareTo 方法
OutputFormat
-
输出到不同的存储中,比如mysql、HBase等
-
继承FileOutputFormat
- 在getRecodeWrite中,返回一个RecordWriter对象
-
可以自定义一个类继承RecordWriter类,重写write方法,在write方法中编写输出代码,该类的构造器要从传入一个job参数
- private FSDataOutputStream mainOut;
输出路径为FSDataOutputStream类型 - job为TaskAttemptContext job类型
- private FSDataOutputStream mainOut;
内核解析
-
Map Task
-
Read
- MapTask 通过 InputFormat 获得的 RecordReader,从输入 InputSplit 中解析出一个个的<k,v>
-
Map
- 该节点主要是将解析出的 key/value 交给用户编写 map()函数处理,并产生一系列新的 key/value
-
Collect
- 在用户编写 map()函数中,当数据处理完成后,一般会调用OutputCollector.collect()输出结果
-
Spill溢写阶段
- 利用快速排序算法对缓存区内的数据进行排序
- 按照分区编号由小到大依次将每个分区中的数据写入任务工作目录下的临时文件 output/spillN.out
- 将分区数据的元信息写到内存索引数据结构 SpillRecord 中,其中每个分区的元信息包括在临时文件中的偏移量、压缩前数据大小和压缩后数据大小
-
Merge
- 当所有数据处理完成后,MapTask 对所有临时文件进行一次合并,以确保最终只会生成一个数据文件
-
-
Reduce Task
-
Copy
- ReduceTask 从各个 MapTask 上远程拷贝一片数据,并针对某一片数据,如果其大小超过一定值,则写到磁盘上,否则直接放到内存中。
-
Sort
- ReduceTask 启动了两个后台线程对内存和磁盘上的文件进行合并,以防止内存使用过多或磁盘上文件过多
-
Reduce
- reduce()函数将计算结果写到 HDFS 上
-
并行度决定机制
- // 默认值是 1,手动设置为 4
job.setNumReduceTasks(4); - ReduceTask=0,表示没有Reduce阶段,输出文件个数和Map个数一致
- ReduceTask默认值就是1,所以输出文件个数为一个
- // 默认值是 1,手动设置为 4
-
ETL
- Extract-Transform-Load 的缩写
- 抽取(Extract)、转换(Transform)、加载(Load)
- 清理的过程往往只需要运行 Mapper 程序,不需要运行 Reduce 程序
- //将Reduce Task设置为0
job.setNumReduceTasks(0)
YARN
构成组件
-
ResourceManager
- 处理客户端的请求
- 监控NodeManager
- 启动或监控ApplicationMaster
- 资源的分配与调度
-
NodeManager
- 管理单个节点上的资源
- 处理来自ResourceManager的命令
- 处理来自ApplicationMaster的命令
-
ApplicationMaster
- 为应用程序申请资源并分配给内部的任务
- 任务的监控与容错
-
Container
- 是YARN中的资源抽象,它封装了某个节点上的多维度资源,如内存、cpu、磁盘、网络等
工作流程
-
YARN----MR
- 由客户端向ResourceManager发起申请Application
- 提交job运行需要的资源
- 资源提交完毕,申请运行mr任务
- 将用户的请求初始化为一个Task
- 领取到Task任务之后,创建Container容器
- 下载job资源到本地
- 申请运行mr Task容器
- 领取到任务,创建mr Task容器
- 向RM申请2个容器,运行Reduce Task程序,map和reduce程序工作
- 程序运行完毕,MR会向RM注销自己
-
YARN----HDFS
- 客户端发送读文件请求到ResourceManager
- ResourceManager将请求转接到NodeManager
- NodeManager返回文件存在的NameNode
- NameNode找到文件的具体存放的DataNode
YARN调度器
-
FIFO:first in firse out先进先出
-
容量调度器:Capacity Scheduler
-
队列资源分配
- 优先选择资源占用最低的
-
作业资源分配
- 按照作业提交的优先级和时间
-
容器资源分配
- 按照容器的优先级
- 优先级相同,按照本地策略
-
-
公平调度器:Fair Scheduler
- 优先选择对资源的缺额比例大的
- 所谓“缺额”,即是实际分配的资源和应获得资源的差额