1、谈谈对HDFS的理解?HDFS这种存储适合哪些场景?
HDFS即Hadoop Distributed File System,Hadoop 分布式文件系统。它为的是解决海量数据的存储与分析的问题,它本身是源于Goole在大数据方面的论文,GFS-->HDFS;
HDFS由Client、NameNode、DataNode、Secondary NameNode组成;Client负责响应用户的各种请求比如上传、下载等;NameNode负责存储HDFS的元数据和处理用户的读写请求,比如数据块存储在DataNode的哪个地方;DataNode负责存储实际的数据块和数据的读写功能,Secondary NameNode主要是辅助NameNode,分担其工作量;定期合并fsimage和fsedits,推送给NameNode;在紧急情况下,可辅助恢复NameNode。
适合场景:
低成本:Hadoop不需要特别贵的机器,可运行于普通廉价机器,所以比较节约成本。
高容错:适合存储需要高容错性的文件存储,文件安全(HDFS高可用和高容错性体现之一就是block的副本机制和主备思想)
大数据:这里非常大指的是几百GB、TB、或者PB级别,需要高吞吐量,对数据读写延时没有要求。
高吞吐:扩展能力强:集群可以很快速拓展到很大规模,满足存放海量数据,这里一般是指PB,EB级别。
单次写入多次读取:适合一次写入、多次读取,既适合数据分析场景(适合OLAP场景)。但是数据读写延迟高,以及不支持单条update,不适合那些对数据访问毫秒级低延迟的应用。
2、HDFS小文件问题
定义
数据大小远小于默认数据块大小文件。
原因
hadoop设计之初是为了OLAP用的,后来越来越多的人,希望hadoop能朝着OLTP的方向发展,并产生了很多工具,例如spark,flink等。实时性要求越高,小文件就会越多。当然这也跟量也有关系,量越大,小文件越少,小文件问题越小。
影响
存储层面:因为元数据存储于内存当中,大量小文件占用大量内存。
计算层面:每个小文件都会起一个MapTask,1个MapTask默认内存1G。浪费资源。
解决方式
入库前:数据采集或标准入库之前,将小文件进行合并大文件再上传入库
存储:Hadoop Archive归档–>将多个小文件打包成一个HAR文件,减少对NN内存的使用
计算方面:CombineTextInputFormat用于将多个小文件在切片过程中生成一个单独的切片或者少量的切片
其他:自己写一个MR程序将产生的小文件合并成一个大文件。如果是Hive或者Spark有merge功能自动帮助我们合并。有小文件场景开启JVM重用;如果没有小文件,不要开启JVM重用,因为会一直占用使用到的Task卡槽,直到任务完成才释放。JVM重用可以使得JVM实例在同一个job中重新使用N次,N的值可以在Hadoop的mapred-site.xml文件中进行配置。通常在10-20之间
3、请讲一下常见的数据压缩格式,以及他们的特点。
- gzip压缩:压缩率比较高,而且压缩/解压速度也比较快;但是不支持split。当每个文件压缩之后在130M以内的(1个块大小内),都可以考虑用gzip压缩格式。
- lzo压缩:压缩/解压速度也比较快,合理的压缩率;支持split,是hadoop中最流行的压缩格式。一个很大的文本文件,压缩之后还大于200M以上的可以考虑,而且单个文件越大,lzo优点越越明显。
- snappy压缩:高速压缩速度和合理的压缩率;不支持split;压缩率比gzip要低。当mapreduce作业的map输出的数据比较大的时候,作为map到reduce的中间数据的压缩格式;或者作为一个mapreduce作业的输出和另外一个mapreduce作业的输入。
- bzip2压缩:支持split;具有很高的压缩率,比gzip压缩率都高;压缩/解压速度慢。适合对速度要求不高,但需要较高的压缩率的时候,可以作为mapreduce作业的输出格式。
总结
4、HDFS的写流程
- client 发起文件上传请求,通过 RPC 与 NameNode 建立通讯,NameNode 检查目标文件是否已存在,父目录是否存在,返回是否可以上传;
- client 请求第一个 block 该传输到哪些 DataNode 服务器上;
- NameNode 根据配置文件中指定的备份数量及副本放置策略进行文件分配,返回可用的 DataNode 的地址,如:A,B,C;
- client 请求3台 DataNode 中的一台A上传数据(本质上是一个 RPC 调用,建立 pipeline),A收到请求会继续调用B,然后B调用C,将整个 pipeline 建立完成,后逐级返回 client;
- client 开始往A上传第一个 block(先从磁盘读取数据放到一个本地内存缓存),以 packet 为单位(默认64K),A收到一个 packet 就会传给B,B传给C;A每传一个 packet 会放入一个应答队列等待应答。
- 数据被分割成一个个 packet 数据包在 pipeline 上依次传输,在 pipeline 反方向上,逐个发送 ack(ack 应答机制),最终由pipeline中第一个 DataNode 节点A将 pipeline ack 发送给client;
- 当一个 block 传输完成之后,client 再次请求 NameNode 上传第二个 block 到服务器