由于也是刚接触这一块,所以这里只是简单介绍一下Hadoop。
什么是Hadoop
Hadoop是一款开源、高可靠、可扩展的分布式计算框架。其核心组件有Hdfs、MapReduce、YARN以及common。生态圈如下图所示:
特点:
1.可靠性 2.扩展性 3.成本低 4.高效率
Hadoop是干什么的?
它的出现解决了两大问题:大数据存储以及大数据处理,对应即为HDFS(存储)、MapReduce(处理)。
Hadoop核心组成:
HDFS
是一个分布式文件存储系统,其特点在于异步复制,一次写入多次读取,适合高吞吐量数据需求。适合存储非常大的文件,通常指GB、TB级别,甚至可达PB。采用流式数据访问。运行与商业硬件上,并不需要配备昂贵设备,可运行于一般商业机上,硬件要求低,成本低。
■不适用场景:
低延时数据访问,数据访问延时要求在毫秒级别时不适合使用HDFS;此时采用Hbase更为适合。大量小文件,HDFS设计时就是为了存储大文件的,如果存储文件全都是较小的会影响性能。那么为什么HDFS不适合处理小文件呢? 原因有以下几点:
1. 在hdfs中采用block的形式来划分存储区域,每个block大小为128M,如果一个文件大小超过128M就会分block存储,文件如果小于block则block的大小为实际文件大小。如果我们往hdfs中放入的都是小文件势必会导致block数量增多,而在hdfs中需要将文件信息存储到nameNode中,文件、目录或分区(block)需要大约150B,如果少还好,当文件数量达到十亿级别时,nameNode将没有内存能够应付。
2. map任务数量是根据块数量来定的,如果文件很小并且很多,那么map任务每次处理的输入数据量就很小,导致map任务很多,启动jvm和初始化,浪费而且大大降低了集群效率
3. hadoop是I/O密集型集群,真正影响性能的I/O性能。如果小文件很多,会导致NN节点内存不足,但是真正影响集群变慢的原因是,因为每个小文件占用了内存,导致内存被撑爆,而每次map任务会去NN内存中寻址小文件,小文件过多,寻址时间势必会增加
4. 大量的小文件,DN向NN节点汇报效率低,对集群稳定性造成影响
■ 架构:
Client:客户端,通过命令行方式与NameNode进行交互获取文件存储位置,与DataNode交互读取或者写入文件
NameNode:master节点,只有一个,用于管理hdfs名称空间和数据块映射信息,配置副本策略,处理客户端请求。在NameNode中有两个重要概念:FSImage、EditLog。
1. FSImage:维护文件系统树以及文件树中的文件和文件夹的元数据;类似快照。
2. editLog:记录针对文件的创建、删除、重命名等这样的更新操作;
-工作原理:
NameNode运行期间的所有更新操作都会记录到editlog中,当NameNode重启时会将FSImage加载到内存中,再读取editLog逐条执行更新操作以保证image属于最新状态。image如同快照一般,当NameNode出现故障数据丢失时,可以通过image辅助还原。
-存在问题:
随着NameNode的更新操作会导致editLog越来越大,前面也说了当NameNode重启时会去读取执行editLog中的记录,并且此时NameNode会进入安全模式只支持数据操作,不支持写操作,如果editLog文件过于庞大会导致读取时间变得很长,这样也就会导致长时间处于安全模式,无法进行写操作。
-解决方案:
通过SecondaryNameNode辅助合并优化editLog大小。大概流程是:SecondaryName会定时请求NameNode让其停止使用editLog,并建立新文件editLog.new将之后到达的更新操作写入到该文件中。SecondaryNameNode获取到editLog和image,将image加载到内存中并执行editLog中的记录,使image保持最新。完成后,将image发送到NameNode中,NameNode接收到image后将旧的iamge替换,此时edit也相当于完成了替换,减小了文件大小。
可以看出通过secondaryNameNode是可以在NameNode出现故障时辅助其恢复数据,但是这种方式也是存在缺陷的,即在合并期间的更新操作是没有更新到新的image中的,此时如果出现故障,是无法完成数据恢复的。
SeconddaryNameNode:辅助NameNode,分担工作量;定期合并fsimage和fsedits,推送给NameNode;紧急情况下可辅助恢复NameNode,但并非NameNode的热备
DataNode:save节点,用于存储实际数据,向NameNode汇报存储信息,执行数据块的读写
■ 图解流程:
1. HDFS文件写入流程
1. 客户端发送请求:bin/hadoop fs -put (要放入文件的位置) (放入到Hdfs中的位置),通过RPC请求到NameNode
2. NameNode会检查HDFS中是否已经存在要创建的目录以及用户是否具有操作权限,如果验证成功则会创建记录,否则抛出IO异常
3. 前两步完成之后会返回FSDataOutputStream 对象,被封装在DFSOutputStream中,通过DFSOutputStream可以协调NameNode和 DadaNode。在客户端开始写入数据到DFSOutputStream时,会将数据进行分片操作切分为一个一个的packet,然后放入data queue中 ,同时会存在一个ack queue,也是由packet组成,当所有DataNode接收成功并响应时会将对应的packet删除掉
4. 接着通过DataStream来接收处理data queue,它会首先询问NameNode以得到最合适的存储节点DataNode,这时会涉及到一个概念 dfs.replication(复制因子),会根据复制因子确定数据副本数量,比如复制因子为3,那么NameNode就会找到最适合的3个DataNode
5.以pipeline(管道)的形式将packet写入到replicas中。客户端会将packet以流的形式依次传递存储到DataNode中,呈现流水线方式 如果在传输过程中,某个DataNode因故障瘫痪,那么会被从pipeline中移除,剩余的block会继续传输到下一个DataNode,同时NameNode 会从新分配一个DataNode以保持设定的replicas的数量
6. 当写入完成,正如第三点中所说,所有的DataNode接收完成后响应接收成功,ack queue接收到响应后将对应packet移除。此时客户端会对 数据流调用close方法关闭数据流
7. 另外只要写入了 dfs.replication.min(最小写入成功的副本数)的复本数(默认为 1),写操作 就会成功,这些块可以在集群中异步复制 ,直到达到指定目标副本数(dfs.replication 的默认值为 3),因为此时NameNode已经直到了文件数据是由哪些block组成
2.HDFS文件读取流程
1.客户端发送请求 : bin/hadoop fs -get (要获取的文件目录) ,客户端通过FileSystem实例的open方法获取到该文件对应的输入流InputStream
2. 通过RPC调用NameNode,询问获得存储文件的DataNode以及对应block的位置信息,包括该文件的副本位置,最主要的是获取到各个DataNode的地址
3. 获得输入流之后,通过read方法选择最近的DataNode建立连接并且读取数据
4. 到达block末端,关闭当前DataNode连接,继续查找下一block
5. 重复执行2-4直到数据全部读取完成
6. 客户端调用close方法,关闭DFSInputStream