hadoop生态圈面试精华之HDFS部分

Posted 大数据小理

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hadoop生态圈面试精华之HDFS部分相关的知识,希望对你有一定的参考价值。

hadoop生态圈面试精华之HDFS部分

HDFS文件写入和读取流程
也可回答:1)读写原理(流程);2)上传下载流程;3)Hadoop中文件put和get的详细过程;4)讲讲
(介绍下)HDFS;5)介绍一下HDFS存数据原理
问过的一些公司:阿里×3,阿里社招,腾讯x2,字节x2,百度,拼多多x2,浩鲸云,小米,流利说,顺 丰,网易云音乐×2,有赞×2,祖龙娱乐,360×2,商汤科技,招银网络,深信服,多益,大华,快手, 电信云计算,转转,美团x5,shopee×2:回答越详细越好,猿辅导×2,科大讯飞,恒生电子,搜狐,京 东,头条,富途,大华(2021.07),远景智能(2021.08),Shopee(2021.08),携程(2021.09),字节(2021.08),四方伟业(2021.08),海康(2021.09),米哈游(2021.09),欢聚(2021.09),虎牙(2021.09)
参考答案:
HDFS存储机制,包括HDFS的写入数据过程和读取数据过程两部分

HDFS写数据过程

  1. 客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。
  2. NameNode返回是否可以上传。
  3. 客户端请求第一个 block上传到哪几个datanode服务器上。4)NameNode返回3个datanode节点,分别为dn1、dn2、dn3。
  4. 客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。
  5. dn1、dn2、dn3逐级应答客户端。
  6. 客户端开始往dn1上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位, dn1收到一个packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答。
  7. 当一个block传输完成之后,客户端再次请求NameNode上传第二个block的服务器。(重复执行3-7
    步)。
    HDFS读数据过程

**
**
可回答:1)HDFS组件;2)HDFS的架构,它们分别具备什么功能?3)HDFS三个进程作用;4)
SeconderyNameNode的作用
问过的一些公司:京东,美团,电信云计算,猿辅导,网易,作业帮,触宝(2021.07),京东(2021.07), 远景智能(2021.08),字节(2021.08),恒生(2021.09)
参考答案:

架构主要由四个部分组成,分别为 HDFS Client 、 NameNode 、 DataNode 和
NameNode 。下面我们分别介绍这四个组成部分。
Secondary

  1. Client :就是客户端

  2. 文件切分。文件上传HDFS的时候,Client将文件切分成一个一个的Block,然后进行存储;

  3. 与NameNode交互,获取文件的位置信息;

  4. 与DataNode交互,读取或者写入数据;

  5. Client提供一些命令来管理HDFS,比如启动或者关闭HDFS;

  6. Client可以通过一些命令来访问HDFS;

  7. NameNode :就是Master,它是一个主管、管理者

  8. 管理HDFS的名称空间;

  9. 管理数据块(Block)映射信息;

  10. 配置副本策略;

  11. 处理客户端读写请求。

  12. DataNode :就是Slave。NameNode下达命令,DataNode执行实际的操作

  13. 存储实际的数据块;

  14. 执行数据块的读/写操作。

  15. Secondary NameNode :并非NameNode的热备。当NameNode挂掉的时候,它并不能马上替换
    NameNode并提供服务

  16. 辅助NameNode,分担其工作量;

  17. 定期合并Fsimage和Edits,并推送给NameNode;

  18. 在紧急情况下,可辅助恢复NameNode。
    HDFS架构另一种图

介绍下HDFS,说下HDFS优缺点,以及使用场景
可回答:1)对HDFS的了解;2)详细说一下HDFS(可结合上一题和下一题说)
问过的一些公司:小米,七牛云×2,美团x2,百度(2021.08),海康(2021.09),网易有道(2021.10) 参考答案:
HDFS是一个文件系统,用于存储文件,通过目录树来定位文件。其次,它是分布式的,由很多服务器联 合起来实现其功能,集群中的服务器有各自的角色。
优点

  1. 高容错性
    数据自动保存多个副本。它通过增加副本的形式,提高容错性。
    某一个副本丢失以后,它可以自动恢复。
  2. 适合处理大数据
    数据规模:能够处理数据规模达到GB、TB、甚至PB级别的数据; 文件规模:能够处理百万规模以上的文件数量,数量相当之大。
  3. 可构建在廉价机器上,通过多副本机制,提高可靠性。
    缺点
  4. 不适合低延时数据访问,比如毫秒级的存储数据,是做不到的。
    2.无法高效的对大量小文件进行存储
    存储大量小文件的话,它会占用NameNode大量的内存来存储文件目录和块信息。这样是不可取的,因 为NameNode的内存总是有限的;
    小文件存储的寻址时间会超过读取时间,它违反了HDFS的设计目标。
    3.不支持并发写入、文件随机修改
    一个文件只能有一个写,不允许多个线程同时写;
    仅支持数据append(追加),不支持文件的随机修改。

HDFS作用
问过的一些公司:美团参考答案:
HDFS在Hadoop中的作用是为海量的数据提供了存储,能提供高吞吐量的数据访问,HDFS有高容错性的 特点,并且设计用来部署在低廉的硬件上;而且它提供高吞吐量来访问应用程序的数据,适合那些有着 超大数据集的应用程序。
对外部客户机而言,HDFS就像一个传统的分级文件系统。可以创建、删除、移动或重命名文件,等等。 但是HDFS的架构是基于一组特定的节点构建的,这是由它自身的特点决定的。这些节点包括NameNode(仅一个,HA两个),它在HDFS内部提供元数据服务;DataNode,它为HDFS提供存储块。

HDFS的容错机制
问过的一些公司:腾讯,一点资讯参考答案:
HDFS可以通过廉价机器搭建大规模集群,获得海量数据的分布式存储能力。对于廉价机器而言,出现网 络故障、节点失效、数据损坏现象的频率并不低,所以在故障之后如何进行数据恢复和容错处理是至关 重要的,HDFS提供了完善的容错机制,使得它成为一个高度容错性和高吞吐量的海量数据存储解决方 案。
故障检测机制
故障的类型主要有以下三种,针对这三种故障类型,HDFS提供了不同的故障检测机制:

针对 DataNode失效 问题
每个DataNode以固定的周期向NameNode 发送心跳信号,通过这种方法告诉 NameNode 它们在正常工作。如果在一定的时间内 NameNode 没有收到 DataNode 心跳,就认为该 DataNode 宕机了。
针对 网络故障 而导致无法收发数据的问题
HDFS提供了ACK的机制,在发送端发送数据后,如果没有收到ACK并且经过多次重试后仍然如此,则认 为网络故障;

针对 数据损坏(脏数据) 问题
在传输数据的时候,同时会发送总和检验码,当数据存储到硬盘时,总和检验码也会被存储。 所有的DataNode 都会定期向NameNode 发送数据块的存储状况。
在发送数据块报告前,会先检查总和校验码是否正确,如果数据存在错误就不发送该数据块的信 息。

HDFS的存储机制
可回答:1)HDFS数据存储;2)HDFS存放
问过的一些公司:字节x2,美团,重庆富民银行(2021.09)
回答技巧:可以从介绍HDFS、HDFS的一些概念、读写过程、优缺点进行回答 参考答案:
HDFS(Hadoop Distributed File System)是Hadoop分布式计算中的数据存储系统,是基于流数据模式访问和处理超大文件的需求而开发的。
HDFS的基础概念
Block
HDFS中的存储单元是每个数据块block,HDFS默认的最基本的存储单位是64M的数据块。和普通的文件 系统相同的是,HDFS中的文件也是被分成64M一块的数据块存储的。不同的是,在HDFS中,如果一个文 件大小小于一个数据块的大小,它是不需要占用整个数据块的存储空间的。
NameNode
元数据节点。该节点用来管理文件系统中的命名空间,是master。其将所有的为了见和文件夹的元数据 保存在一个文件系统树中,这些信息在硬盘上保存为了:命名空间镜像(namespace image)以及修改日志(edit log),后面还会讲到。此外,NameNode还保存了一个文件包括哪些数据块,分布在哪些数据节点上。然而,这些信息不存放在硬盘上,而是在系统启动的时候从数据节点收集而成的。

DataNode
数据节点。是HDFS真正存储数据的地方。客户端(client)和元数据节点(NameNode)可以向数据节 点请求写入或者读出数据块。此外,DataNode需要周期性的向元数据节点回报其存储的数据块信息。

Secondary NameNode
从元数据节点。从元数据节点并不是NameNode出现问题时候的备用节点,它的主要功能是周期性的将NameNode中的namespace image和edit log合并,以防log文件过大。此外,合并过后的namespace image文件也会在Secondary NameNode上保存一份,以防NameNode失败的时候,可以恢复。

Edit Log
修改日志。当文件系统客户端client进行------写 操作的时候,我们就要把这条记录放在修改日志中。
在记录了修改日志后,NameNode则修改内存中的数据结构。每次写操作成功之前,edit log都会同步到文件系统中。

Fsimage
命名空间镜像。它是内存中的元数据在硬盘上的checkpoint。当NameNode失败的时候,最新的checkpoint的元数据信息就会从fsimage加载到内存中,然后注意重新执行修改日志中的操作。而Secondary NameNode就是用来帮助元数据节点将内存中的元数据信息checkpoint到硬盘上的。
Checkpoint的过程如下
1)Secondary NameNode通知NameNode生成新的日志文件,以后的日志都写到新的日志文件中。2)Secondary NameNode用http get从NameNode获得fsimage文件及旧的日志文件。

  1. Secondary NameNode将fsimage文件加载到内存中,并执行日志文件中的操作,然后生成新的fsimage文件。
  2. Secondary NameNode将新的fsimage文件用http post传回NameNode。
  3. NameNode可以将旧的fsimage文件及旧的日志文件,换为新的fsimage文件和新的日志文件(第一步生 成的),然后更新fstime文件,写入此次checkpoint的时间。
    这样NameNode中的fsimage文件保存了最新的checkpoint的元数据信息,日志文件也重新开始,不会变 的很大了。
    Checkpoint的过程如下图

HDFS中文件读写过程和优缺点见前面的题目

HDFS的副本机制
可回答:1)HDFS的副本放置策略;2)写数据时如何选择DataNode节点呢?这么选择节点的依据是什 么?
问过的一些公司:多益,货拉拉(2021.07),大华(2021.07),远景智能(2021.08),虎牙(2021.09) 参考答案:
在HDFS中,一个文件会被拆分为一个或多个数据块。默认情况下,每个数据块都会有3个副本。每个副 本都会被存放在不同的机器上,而且每一个副本都有自己唯一的编号。
NameNode节点选择一个DataNode节点去存储block副本的过程就叫做副本存放,这个过程的策略其实 就是在可靠性和读写带宽间的权衡。
Hadoop3.x副本结点选择:
由上图可知,第一个副本在Client所处的节点上。如果客户端在集群外,随机选一个。 第二个副本在另一个机架的随机一个节点。
第三个副本在第二个副本所在机架的随机节点。

HDFS的常见数据格式,列式存储格式和行存储格式异同点,列式存储优点有哪些?
问过的一些公司:快手
参考答案:
1、Hadoop中的文件格式大致上分为面向行和面向列两类行式存储
一条数据保存为一行,读取一行中的任何值都需要把整行数据都读取出来(如:Sequence Files,Map File,Avro Data Files),这种方式在磁盘读取的开销比较大,这无法避免。
列式存储
整个文件被切割为若干列数据,每一列中数据保存在一起(如:Parquet,RC Files,ORC Files,Carbon Data,IndexR)。这种方式会占用更多的内存空间,需要将行数据缓存起来。
2、列存储和行存储异同点从以下几个方面说明
写入:
行存储的写入是一次完成,数据的完整性因此可以确定;
列存储需要把一行记录拆分成单列保存,写入次数明显比行存储多; 行存储在写入上占有很大的优势。
数据修改:
行存储是在指定位置写入一次,列存储是将磁盘定位到多个列上分别写入; 行存储在数据修改也是占优的。
数据读取:
行存储通常将一行数据完全读出,如果只需要其中几列数据,就会存在冗余列; 列存储每次读取的数据是集合中的一段或者全部;
由于列储存的数据是同质的,这种情况使数据解析变得容易。行存储则复杂的多,因为在一行记录 中保存了多种类型的数据,数据解析需要在多种数据类型之间频繁转换,这个操作很消耗cpu;
所以列存储的解析过程中更有利于分析大数据。
3、列存储和行存储优缺点行存储
优点:行存储的写入是一次性完成的,写入效率高,消耗的时间比列存储少,并且能够保证数据的完整 性
缺点:数据读取过程中会产生冗余数据,如果只看少量数据,此影响可以忽略;数量大可能会影响数据 的处理效率
列存储
优点:在读取过程中,不会产生冗余数据,这对数据完整性要求不高的大数据处理领域尤为重要
缺点:写入效率,保证数据完整性上都不如行存储

HDFS如何保证数据不丢失?
问过的一些公司:百度参考答案:
先得出结果

  1. 数据在写入之后进行校验和的计算,DataNode周期性的进行校验和计算,将计算结果与第一次进行 对比,若相同表示无数据丢失,若不相同表示有数据丢失,丢失后将进行数据修复;

  2. 数据读取之前对数据进行校验,与第一次的结果进行对比,若相同表示数据没有丢失,可以读取, 若不相同表示数据有所丢失,到其他副本读取数据。
    保证DataNode节点保证数据完整性的方法

  3. 当 DataNode 读取 Block 的时候,它会计算CheckSum;

  4. 如果计算后的 CheckSum,与Block 创建时值不一样,说明 Block 已经损坏;

  5. Client 读 取 其 他 DataNode 上 的 Block; 4)常见的校验算法 crc(32),md5(128),sha1(160); 5)DataNode 在其文件创建后周期验证CheckSum。
    案例分析
    第一步:写入数据

第二步:进行首次校验和,得到数值70

第三步:读取数据时,仍然会校验和,得到数据70

第四步:对比两次较校验和的值
如两次读取的值都是70,则开始读取数据
如两次读取的值不一致,说明此节点数据丢失,则去其他节点读取数据

HDFS NameNode高可用如何实现?需要哪些角色?
问过的一些公司:快手参考答案:
HDFS的高可用指的是HDFS持续对各类客户端提供读、写服务的能力,因为客户端对HDFS的读、写操作 之前都要访问NameNode服务器,客户端只有从NameNode获取元数据之后才能继续进行读、写。所以HDFS的高可用的关键在于NameNode上的元数据持续可用。我们知道2NN的功能是把NameNode的fsimage和edit log做定期融合,融合后传给NameNode,以确保备份到的元数据是最新的,这一点类似于做了一个元数据的快照。Hadoop官方提供了一种quorum journal manager来实现高可用,那么就没必要配置2NN了。在高可用配置下,edit log不再存放在名称节点,而是存放在一个共享存储的地方,这个共享存储由奇数个Journal Node组成,一般是3个节点(JN小集群), 每个Journal Node专门用于存放来自NameNode的编辑日志,编辑日志由活跃状态的NameNode写入Journal Node小集群。那么要有两个NameNode,而且二者之中只能有一个NameNode处于活跃状态(Active),另一个是待命 状态(Standby),只有Active的NameNode节点才能对外提供读写HDFS服务,也只有Active态的NameNode才能向Journal Node写入编辑日志;Standby状态的NameNode负责从Journal Node小集群中拷贝数据到本地。另外,各个DataNode也要向Active状态的NameNode报告状态(心跳信息、块信息等)。
2个NameNode与3个Journal Node构成的组保持通信,活跃的名称节点负责往Journal Node集群写入编辑日志,待命的名称节点负责观察Journal Node集群中的编辑日志,并且把日志拉取到待命节点,再加上两个NameNode各自的fsimage镜像文件,这样一来就能确保两个NameNode的元数据保持同步。一旦Active NameNode不可用,提前配置的Zookeeper会把Standby节点自动变Active状态,继续对外提供读写服务。

手动实现高可用的大概流程:

  1. 准备3台服务器分别用于运行JournalNode进程(也可部署在date node上),准备2台name node用于运行NameNode进程,Data Node数量不限
  2. 分别启动3台JN服务器上的JournalNode进程,分别在date node服务器启动DataNode进程
  3. 需要同步2台name node之间的元数据。具体做法:从第一台NameNode拷贝元数据到另一台NameNode,然后启动第一台的NameNode进程,再到另一台名称节点上做standby引导启动
  4. 把第一台名节点的edit log初始化到JournalNode节点,以供standby状态的NameNode到JournalNode
    拉取数据
  5. 启动standby状态的名称节点,这样就能同步fsimage文件
  6. 模拟故障,检验是否成功实现:手动把active状态的NameNode弄挂掉,正常的话会自动把standby状 态的NameNode转变成active.
    自动实现通过分布式协调服务者zookeeper来实现。

HDFS的文件结构?
问过的一些公司:美团,360 参考答案:
HDFS metadata以树状结构存储整个HDFS上的文件和目录,以及相应的权限、配额和副本因子
(replication factor)等。HDFS Namenode本地目录的存储结构和Datanode数据块存储目录结构,也就是hdfs-site.xml中配置的dfs.namenode.name.dir和dfs.namenode.data.dir。

NameNode
HDFS metadata主要存储两种类型的文件fsimage
记录某一永久性检查点(Checkpoint)时整个HDFS的元信息
edits

所有对HDFS的写操作都会记录在此文件中
1、文件所在位置
文件所在位置由hdfs-site.xml中的配置项dfs.namenode.name.dir配置。这些文件都存于
$dfs.namenode.name.dir/current文件夹下,在dfs.namenode.name.dir配置项中可以配置多个目录,各 个目录存储的文件结构和内容都完全一样,配置多个目录只是起到冗余备份的作用。

  1. dfs.namenode.name.dir
  2. file://$hadoop.tmp.dir/dfs/name

dfs.namenode.name.dir在hdfs-site.xml中定义的默认值为 file:// h a d o o p . t m p . d i r / d f s / n a m e ,其中 h a d o o p . t m p . d i r 是 c o r e − s i t e . x m l 中的配置项, h a d o o p . t m p . d i r 的默认值为 / t m p / h a d o o p − hadoop.tmp.dir/dfs/name,其中hadoop.tmp.dir是core-site.xml 中的配置项,hadoop.tmp.dir的默认值 为 /tmp/hadoop- hadoop.tmp.dir/dfs/name,其中hadoop.tmp.dircoresite.xml中的配置项,hadoop.tmp.dir的默认值为/tmp/hadoopuser.name 。因此文件默认都是存放在/tmp/hadoop-$user.name/dfs/name/current路径下的。

  1. hadoop.tmp.dir
  2. /tmp/hadoop-$user.name
  3. A base for other temporary directories.

具体到我的服务器,dfs.namenode.name.dir用了配置的/cloud/data/hadoop/dfs/nn,因此我的服务器上 的文件的路径就直接为:/cloud/data/hadoop/dfs/nn/current。

  1. dfs.namenode.name.dir
  2. /cloud/data/hadoop/dfs/nn/

2、文件目录结构
1 ├── current
2 │ ├── edits_0000000001362702459-0000000001363401818
3 │ ├── edits_0000000001363401819-0000000001363931603
4 │ ├── edits_0000000001363931604-0000000001364566627
5 │ ├── edits_0000000001364566628-0000000001365069009
6 │ ├── edits_0000000001365069010-0000000001365209404
7 │ ├── edits_0000000001365209405-0000000001365211445
8 │ ├── edits_0000000001365211446-0000000001365211447
9 │ ├── edits_0000000001365211448-0000000001365211451
10 │ ├── edits_0000000001365211452-0000000001365211453
11 │ ├── edits_0000000001365211454-0000000001365211625
12 │ ├── edits_0000000001365211626-0000000001365213635
13 │ ├── edits_inprogress_0000000001365213636 14 │ ├── fsimage_0000000001365431029
15 │ ├── fsimage_0000000001365431029.md5
16 │ ├── fsimage_0000000001365431090
17 │ ├── fsimage_0000000001365431090.md5

  1. │ ├── seen_txid
  2. │ └── VERSION
  3. └── in_use.lock
    3、文件目录解析
    从上面的目录树中可以发现,主要有6类文件:
    1)VERSION文件
    VERSION是java属性文件,内容大致如下:
    1 namespaceID=644097999
    2 clusterID=CID-da027b7b-4e9f-4287-be7a-03735d895bc2
    3 cTime=1603347772521
    4 storageType=NAME_NODE
    5 blockpoolID=BP-1345407316-192.168.100.148-1603347772521
    6 layoutVersion=-63
    namespaceID是文件系统唯一标识符,在文件系统首次格式化之后生成,在引入Federation特性后,可能 会有多个namespace。
    clusterID是系统生成或手动指定的集群ID,在-clusterID选项中可以使用它。cTime表示Namenode存储的创建时间。
    storageType表示这个文件存储的是什么进程的数据结构信息(如果是Datanode,则为DATA_NODE)。
    blockpoolID表示每一个Namespace对应的块池id,这个id包括了其对应的Namenode节点的ip地址。layoutVersion表示HDFS永久性数据结构的版本信息,只要数据结构变更,版本号也要递减,此时的HDFS也需要升级,否则磁盘仍旧使用旧版本的数据结构,这会导致新版本的Namenode无法使用。

2) edits_* 文 件
edits文件中存放的是客户端执行的所有更新命名空间的操作。
首先了解一下transactionId的概念。transactionId与客户端每次发起的RPC操作相关,当客户端发起一次 RPC请求对Namenode的命名空间修改后,Namenode就会在editlog中发起一个新的transaction用于记录 这次操作,每个transaction会用一个唯一的transactionId标识。
edits_*分为两类文件,一类是edits_startTransactionId-endTransactionId,另一类是edits_inprogress_startTransactionId。对于第一类文件,每个edits文件都包含了文件名中从startTransactionId开始到endTransactionId之间的所有事务。
第二类文件表示正在进行处理的editlog,所有从startTransactionId开始的新的修改操作都会记录在这个 文件中,直到HDFS重置这个日志文件,重置操作会将inprogress文件关闭,并将inprogress文件改名为正 常的editlog文件,即第一类文件,同时还会打开一个新的inprogress文件,记录正在进行的事务。
可以通过oev命令查看edits文件,基本命令格式为:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <EDITS_VERSION>-63</EDITS_VERSION>
  3. OP_START_LOG_SEGMENT

7 63949

  1. OP_END_LOG_SEGMENT

13 63950

1 hdfs oev -p 文件类型(通常为xml) -i edits文件 -o 转换后文件输出路径

3) fsimage_* 文 件
fsimage文件其实是hadoop文件系统元数据的一个永久性的检查点,其中包含hadoop文件系统中的所有 目录和文件inode的序列化信息。
fsimage_*的具体文件命名规则是这样的:fsimage_endTransactionId,它包含hadoop文件系统中endTransactionId前的完整的HDFS命名空间元数据镜像。
可以通过oiv命令查看fsimage文件,基本命令格式为:
1 hdfs oiv -p 文件类型(通常为xml) -i fsimage文件 -o 转换后文件输出路径

4) fsimage_*.md5文件
md5校验文件,用于确保fsimage文件的正确性,可以作用于磁盘异常导致文件损坏的情况。
5)seen_txid文件
这个文件中保存了一个事务id,这个事务id值只会在两种情况下更新: 上一个检查点(即合并edits和fsimage文件)时的最新事务id
编辑日志重置(即生成一个新的inprogress文件)时的最新事务id
可以发现,这个事务id并不是Namenode内存中最新的事务id。这个文件的作用在于Namenode启动时, 利用这个文件判断是否有edits文件丢失,Namenode启动时会检查seen_txid并确保内存中加载的事务id 至少超过seen_txid,否则Namenode将终止启动操作。
6) in_use.lock文件
这是一个被Namenode线程持有的锁文件,用于防止多个Namenode线程启动并且并发修改这个存储目 录。

DataNode
1、文件所在位置
文件所在位置由hdfs-site.xml中的配置项dfs.datanode.data.dir配置。这些文件都存于
$dfs.datanode.data.dir/current文件夹下,在dfs.namenode.name.dir配置项中可以配置多个目录,这里 要注意,Datanode的多个存储目录存储的数据块并不相同,并且不同的存储目录可以是异构的,这样的 设计可以提高数据块IO的吞吐率,这是与Namenode中很大不同的一个地方。

  1. dfs.datanode.data.dir

  2. file://$hadoop.tmp.dir/dfs/data

  3. 5
    dfs.datanode.data.dir在hdfs-site.xml中定义的默认值为 file:// h a d o o p . t m p . d i r / d f s / d a t a ,其中 h a d o o p . t m p . d i r 是 c o r e − s i t e . x m l 中的配置项, h a d o o p . t m p . d i r 的默认值为 / t m p / h a d o o p − hadoop.tmp.dir/dfs/data,其中hadoop.tmp.dir是core-site.xml 中的配置项,hadoop.tmp.dir的默认值 为 /tmp/hadoop- hadoop.tmp.dir/dfs/data,其中hadoop.tmp.dircoresite.xml中的配置项,hadoop.tmp.dir的默认值为/tmp/hadoopuser.name 。因此文件默认都是存放在/tmp/hadoop-$user.name/dfs/data/current 路径下的。

  4. hadoop.tmp.dir

  5. /tmp/hadoop-$user.name

  6. A base for other temporary directories.

  7. 6
    具体到服务器,dfs.datanode.data.dir配置了如下值,因此服务器上的文件的路径就包括以下8个路 径:/cloud/data*/hadoop/dfs/dn/current。

  8. dfs.datanode.data.dir
    /cloud/data1/hadoop/dfs/dn,/cloud/data2/hadoop/dfs/dn,/cloud/data3/hadoop/ dfs/dn,/cloud/data4/hadoop/dfs/dn,/cloud/data5/hadoop/dfs/dn,/cloud/data6/hadoop/d fs/dn,/cloud/data7/hadoop/dfs/dn,/cloud/data8/hadoop/dfs/dn

  9. 5
    2、文件目录结构
    以dfs.datanode.data.dir配置项配置的其中一个目录/cloud/data1/hadoop/dfs/dn为例,它的目录结构为:
    1 ├── current
    2 │ ├── BP-615261695-192.168.100.74-1602499969654

  10. │ │ ├── current

  11. │ │ │ ├── finalized 5 │ │ │ │ ├── subdir0 6 │ │ │ │ ├── subdir1 7 │ │ │ │ ├── subdir10 8 │ │ │ │ ├── subdir11 9 │ │ │ │ ├── subdir12 10 │ │ │ │ ├── subdir13 11 │ │ │ │ ├── subdir14 12 │ │ │ │ ├── subdir15 13 │ │ │ │ ├── subdir16 14 │ │ │ │ ├── subdir17 15 │ │ │ │ ├── subdir18 16 │ │ │ │ ├── subdir19 17 │ │ │ │ ├── subdir2 18 │ │ │ │ ├── subdir20 19 │ │ │ │ ├── subdir21 20 │ │ │ │ ├── subdir22 21 │ │ │ │ ├── subdir23 22 │ │ │ │ ├── subdir24 23 │ │ │ │ ├── subdir25 24 │ │ │ │ ├── subdir26 25 │ │ │ │ ├── subdir27 26 │ │ │ │ ├── subdir28 27 │ │ │ │ ├── subdir29 28 │ │ │ │ ├── subdir3 29 │ │ │ │ ├── subdir30 30 │ │ │ │ ├── subdir31 31 │ │ │ │ ├── subdir4 32 │ │ │ │ ├── subdir5 33 │ │ │ │ ├── subdir6 34 │ │ │ │ ├── subdir7 35 │ │ │ │ ├── subdir8 36 │ │ │ │ └── subdir9 37 │ │ │ ├── rbw

  12. │ │ │ └── VERSION

  13. │ │ ├── scanner.cursor 40 │ │ └── tmp
    41 │ │ ├── blk_1080824082
    42 │ │ ├── blk_1080824082_7111789.meta
    43 │ │ ├── blk_1080834049
    44 │ │ └── blk_1080834049_7120152.meta
    45 │ └── VERSION
    3
    46 └── in_use.lock 47
    由于篇幅所限,这里只展开了5层,在实际情况中,subdir0subdir31这32个文件夹每个文件夹下面还是
    subdir0subdir31这32个文件夹,这些文件夹下面才是类似于tmp文件夹下的blk_文件。
    3、文件目录解析
    1)BP- * - * - * 文件夹
    这个目录是一个块池目录,块池目录保存了一个块池在当前存储目录下存储的所有数据块,在Federation部署方式中,Datanode的一个存储目录会包含多个以BP开头的块池目录。BP后面会紧跟一个 唯一的随机块池ID。接下来的第2个 * 代表当前块池对应的Namenode的IP地址。最后一个
    代表这个块池的创建时间。
    34 外层VERSION文件

1 storageID=DS-fd6c86e2-c1ab-4541-9693-5844c2359a0f
2 clusterID=CID-a56f3601-ac4b-4c37-95fd-3b04c24a54c9

  1. cTime=0
  2. datanodeUuid=b0f4eafa-54b1-4966-acf9-3986435d5cd6
  3. storageType=DATA_NODE
  4. layoutVersion=-57 7
    :存储 id 号
    :集群 id,全局唯一
    storageID
    clusterID
    cTime :标记了 datanode 存储系统的创建时间,对于刚刚格式化的存储系统,这个属性为 0;但是在文件系统升级之后,该值会更新到新的时间戳
    :datanode 的唯一识别码
    datanodeUuid
    storageType :存储类型
    layoutVersion :是一个负整数。通常只有 HDFS 增加新特性时才会更新这个版本号
    35 内层VERSION文件

1 namespaceID=800713668 2 cTime=1602499969654
3 blockpoolID=BP-615261695-192.168.100.74-1602499969654
4 layoutVersion=-57 5
namespaceID :是 datanode 首次访问 namenode 的时候从 namenode 处获取的storageID, 对每个datanode 来说是唯一的(但对于单个 datanode 中所有存储目录来说则是相同的),namenode 可用这个属性来区分不同 datanode。(但我查看了不同datanode上的都相同)
cTime :标记了 datanode 存储系统的创建时间,对于刚刚格式化的存储系统,这个属性为 0;但是在文件系统升级之后,该值会更新到新的时间戳。
blockpoolID :一个 block pool id 标识一个 block pool,并且是跨集群的全局唯一。当一个新的Namespace 被创建的时候(format 过程的一部分)会创建并持久化一个唯一 ID。在创建过程构建全局唯一的 BlockPoolID 比人为的配置更可靠一些。NN 将 BlockPoolID 持久化到磁盘中,在后续的启动过程中, 会再次 load 并使用。(查看了发现不同datanode上的都相同,BP-1008895165-10.252.87.50- 1593312108051的命名就遵循BP-random integer-NameNode-IP address-creation time)
layoutVersion : 是一个负整数。通常只有 HDFS 增加新特性时才会更新这个版本号。
36 finalized/rbw/tmp文件夹
finalized、rbw和tmp目录都是用于存储数据块的文件夹,包括数据块文件及其对应的校验和文件。他们 的区别是存放不同状态下的数据块副本文件。我们知道Datanode上保存的数据块副本有5种状态: FINALIZED,RBW(replica being written),RUR(replica under recovery),RWR(replica waiting to be recovered),TEMPORATY(复制数据块或者进行集群数据块平衡操作时的状态)
finalized目录保存所有FINALIZED状态的副本,rbw目录保存RBW、RWR、RUR状态的副本,tmp目录保存TEMPORARY状态的副本。
如果对应到具体的过程,那么当客户端发起写请求创建一个新的副本时,这个副本会被放到rbw目录 中;当在数据块备份和集群平衡存储过程中创建一个新的副本时,这个副本就会放到tmp目录中;一旦 一个副本完成写操作并被提交,它就会被移到finalized目录中。当Datanode重启时,tmp目录中的所有 副本将会被删除,rbw目录中的副本将会被加载为RWR状态,finalized目录中的副本将会被加载为FINALIZED状态。
37 finalized特殊目录结构解析
inalized目录存储了已经完成写入操作的数据块,由于这样的数据块可能非常多,所以finalized目录会以 特定的目录结构存储这些数据块。
在我的机器上,finalized文件夹有32个子文件夹(分别为subdir0-31),每个子文件夹下又有32个子文件 夹(同样为subdir0-31),接着才是存的真正的数据块blk文件及其校验文件。你可能会发现自己的目录 下不是32个子文件夹,而是64个或者256个,不要奇怪,这是hadoop不同版本之间的差异,下面简要介 绍一下不同版本下的目录结构:
早期版本:当存储目录中的数据块超过64个时,将创建64个子目录来存储数据块。一个父目录最多 可以创建64个子目录,一个子目录最多可以存放64个数据块以及64个子目录。
2.6版本:finalized目录下拥有256个一级子目录,每个一级子目录下可以拥有256个二级子目录。
2.8.5版本:finalized目录下拥有32个一级子目录,每个一级子目录下可以拥有32个二级子目录。
以2.8.5版本为例,数据块是根据什么判断自己应放在哪个目录下的呢?答案是根据数据块的id,具体的 判断规则如下代码所示(DatanodeUtil类的idToBlockDir方法):

1 public static File idToBlockDir(File root, long blockId) 2 int d1 = (int) ((blockId >> 16) & 0x1F);

  1. int d2 = (int) ((blockId >> 8) & 0x1F);
  2. String path = DataStorage.BLOCK_SUBDIR_PREFIX + d1 + SEP +
  3. DataStorage.BLOCK_SUBDIR_PREFIX + d2;
  4. return new File(root, path); 7
    8
    一级目录由d1指定,二级目录由d2指定,d1是数据块id右移16位,再取最后5位得到的数值,可以发 现,它的范围是0-31。d2是数据块id右移8位,再取最后5位得到的数值,可以发现,它的范围也是0- 31。一级目录和二级目录都对应32个文件夹,与预期相符。
    2.6版本的判断规则与2.8.5完全一样,不同点是都是取最后8位,而不是5位,因此,2.6版本的一级目录 和二级目录对应的文件夹个数都是256个。
    38 in_use.lock文件
    这是一个被Datanode线程持有的锁文件,用于防止多个Datanode线程启动并发修改这个存储目录。
    39 scanner.cursor文件
    这个文件记录了访问文件的游标,文件具体内容如下所示:


“lastSavedMs” : 1604459692263,
“iterStartMs” : 1604314428656, “curFinalizedDir” : null, “curFinalizedSubDir” : null, “curEntry” : null,
“atEnd” : true

40 blk_文件
blk_ * 是数据块文件,其中
代表的数据是数据块id。
blk ** .meta是数据块校验文件,其中第一个 * 是数据块id,第二个 * 代表数据块的版本号。
blk的meta校验文件(保存blk的checksum信息)大小大概是blk文件大小的1/128,因为每512字节做一次 校验生成4字节校验,在机器上验证了一下大小,接近1/128。

HDFS的默认副本数?为什么是这个数量?如果想修改副本数怎么修改?
问过的一些公司:美团参考答案:
hdfs的默认副本数量是3个,配置在/etc/hadoop/conf/hdfs-site.xml中(修改也是在这)

  1. dfs.replication
  2. 3
  3. 5

关于HDFS的副本数为什么选择3,可看以下内容:
HDFS采用一种称为机架感知的策略来改进数据的可靠性、可用性和网络带宽的利用率。
在大多数情况下,HDFS的副本系数是3,HDFS的存放策略是一个副本存放在本地机架节点上,另一个副 本存放在不同一机架的节点上,第三个副本存放在在与第二个节点同一机架的不同节点上。这种策略减 少了机架间的数据传输,提高了写操作的效率。机架错误的概率远比节点错误的概率小,所以这种策略 不会对数据的可靠性和可用性造成影响。与此同时,因为数据只存在两个机架上,这种策略减少了读数 据时需要的网络传输带宽。
在这种策略下,副本并不是均匀地分布在机架上。这种策略在不损坏可靠性和读取性能的情况下,改善 了写的性能。

介绍下HDFS的Block
问过的一些公司:京东参考答案:
Block概念
磁盘有一个Block size的概念,它是磁盘读/写数据的最小单位。构建在这样的磁盘上的文件系统也是通过块来管理数据的,文件系统的块通常是磁盘块的整数倍。文件系统的块一般为几千字节(byte),磁盘 块一般为512字节(byte)。
HDFS也有Block的概念,但它的块是一个很大的单元,默认是64MB。像硬盘中的文件系统一样,在HDFS 中的文件将会按块大小进行分解,并作为独立的单元进行存储。但和硬盘中的文件系统不一样的是,存 储在块中的硬的一个比块小的文件并不会占据一个块大小盘物理空间(HDFS中一个块只存储一个文件的 内容)。
对HDFS进行块抽象有哪些好处呢?
1、一个显而易见的好处是:一个文件的大小,可以大于网络中任意一个硬盘的大小。
文件的块并不需要存储在同一个硬盘上,一个文件的快可以分布在集群中任意一个硬盘上。事实上,虽 然实际中并没有,整个集群可以只存储一个文件,该文件的块占满整个集群的硬盘空间。
2、使用抽象块而非整个文件作为存储单元,大大简化了系统的设计。
简化设计,对于故障种类繁多的分布式系统来说尤为重要。以块为单位,一方面简化存储管理,因为块 大小是固定的,所以一个硬盘放多少个块是非常容易计算的;另一方面,也消除了元数据的顾虑,因为Block仅仅是存储的一块数据,其文件的元数据,例如权限等就不需要跟数据块一起存储,可以交由另 外的其他系统来处理。
3、块更适合于数据备份,进而提供数据容错能力和系统可用性。
为了防止数据块损坏或者磁盘或者机器故障,每一个block都可以被分到少数几天独立的机器上(默认3 台)。这样,如果一个block不能用了,就从其他的一处地方,复制过来一份。

HDFS的块默认大小,64M和128M是在哪个版本更换的?怎么修改默认块大小?
问过的一些公司:祖龙娱乐参考答案:
Hadoop 2.7.2版本及之前默认64MB,Hadoop 2.7.3版本及之后默认128M
通过修改hdfs-site.xml文件中的dfs.blocksize对应的值修改block大小

  1. dfs.blocksize
    3 134217728
    4 5

HDFS的block为什么是128M?增大或减小有什么影响?
可回答:Hadoop块大小及其原因
问过的一些公司:美团,货拉拉(2021.07) 参考答案:
1、首先先来了解几个概念
寻址时间:HDFS中找到目标文件block块所花费的时间。

原理:文件块越大,寻址时间越短,但磁盘传输时间越长;文件块越小,寻址时间越长,但磁盘传输时 间越短。

2、为什么block不能设置过大,也不能设置过小
如果块设置过大,一方面从磁盘传输数据的时间会明显大于寻址时间,导致程序在处理这块数据时,变 得非常慢;另一方面,MapReduce中的map任务通常一次只处理一个块中的数据,如果块过大运行速度 也会很慢。
如果设置过小,一方面存放大量小文件会占用NameNode中大量内存来存储元数据,而NameNode的内 存是有限的,不可取;另一方面块过小,寻址时间增长,导致程序一直在找block的开始位置。因此,块 适当设置大一些,减少寻址时间,传输一个有多个块组成的文件的时间主要取决于磁盘的传输速度。
3、块大小多少合适
如果寻址时间约为10ms,而传输速率为100MB/s,为了使寻址时间仅占传输时间的1%,我们要将块大小 设置约为100MB。默认的块大小128MB。
块的大小:10ms x 100 x 100M/s = 100M,如图

如果增加文件块大小,那就需要增加磁盘的传输速率。
比如,磁盘传输速率为200MB/s时,一般设定block大小为256MB;磁盘传输速率为400MB/s时,一般设定
block大小为512MB。

HDFS HA怎么实现?是个什么架构?
可回答:1)HDFS HA的实现原理;2)Hadoop HA中各个节点是怎么布置的
问过的一些公司:腾讯(微众)x2,头条,猿辅导,京东,蘑菇街x3,快手,顺丰,大华(2021.08),四 方伟业(2021.08),美团买菜(2021.09),小红书(2021.11)
在Hadoop2.X之前,NameNode是集群中可能发生单点故障的节点,每个HDFS集群只有一个
NameNode,一旦这个节点不可用,则整个HDFS集群将处于不可用状态。
HDFS高可用(HA)方案就是为了解决上述问题而产生的,在HA HDFS集群中会同时运行两个NameNode,一个作为活动的NameNode(Active),一个作为备份的NameNode(Standby)。备份的NameNode的命名空间与活动的NameNode是实时同步的,所以当活动的NameNode发生故障而停止服务 时,备份NameNode可以立即切换为活动状态,而不影响HDFS集群服务。

在一个HA集群中,会配置两个独立的Namenode。在任意时刻,只有一个节点作为活动的节点,另一个 节点则处于备份状态。活动的Namenode负责执行所有修改命名空间以及删除备份数据块的操作,而备 份的Namenode则执行同步操作,以保持与活动节点命名空间的一致性。
为了使备份节点与活动节点的状态能够同步一致,两个节点都需要同一组独立运行的节点
(JournalNodes,JNS)通信。当Active Namenode执行了修改命名空间的操作时,它会定期将执行的操作记录在editlog中,并写入JNS的多数节点中。而Standby Namenode会一直监听JNS上editlog的变化, 如果发现editlog有改动,Standby Namenode就会读取editlog并与当前的命名空间合并。当发生了错误切换时,Standby节点会保证已经从JNS上读取了所有editlog并与命名空间合并,然后才会从Standby状态切换为Active状态。通过这种机制,保证了Active Namenode与Standby Namenode之间命名空间状态的一致性,也就是第一关系链的一致性。
为了使错误切换能够很快的执行完毕,就要保证Standby节点也保存了实时的数据快的存储信息,也就 是第二关系链。这样发生错误切换时,Standby节点就不需要等待所有的数据节点进行全量数据块汇
报,而直接可以切换到Active状态。为了实现这个机制,Datanode会同时向这两个Namenode发送心跳以 及块汇报信息。这样就实现了Active Namenode 和standby Namenode 的元数据就完全一致,一旦发生故障,就可以马上切换,也就是热备。
这里需要注意的是 Standby Namenode只会更新数据块的存储信息,并不会向namenode 发送复制或者删除数据块的指令,这些指令只能由Active namenode发送。
在HA架构中有一个非常重非要的问题,就是需要保证同一时刻只有一个处于Active状态的Namenode, 否则机会出现两个Namenode同时修改命名空间的问,也就是脑裂(Split-brain)。脑裂的HDFS集群很可 能造成数据块的丢失,以及向Datanode下发错误的指令等异常情况。
为了预防脑裂的情况,HDFS提供了三个级别的隔离机制(fencing):
共享存储隔离:同一时间只允许一个Namenode向JournalNodes写入editlog数据。 客户端隔离:同一时间只允许一个Namenode响应客户端的请求。
Datanode隔离:同一时间只允许一个Namenode向Datanode下发名字节点指令,李如删除、复制数 据块指令等等。
在HA实现中还有一个非常重要的部分就是Active Namenode和Standby Namenode之间如何共享editlog日志文件。Active Namenode会将日志文件写到共享存储上。Standby Namenode会实时的从共享存储读取edetlog文件,然后合并到Standby Namenode的命名空间中。这样一旦Active Namenode发生错误, Standby Namenode可以立即切换到Active状态。在Hadoop2.6中,提供了QJM(Quorum Journal Manager)方案来解决HA共享存储问题。

所有的HA实现方案都依赖于一个保存editlog的共享存储,这个存储必须是高可用的,并且能够被集群中 所有的Namenode同时访问。Quorum Journa是一个基于paxos算法的HA设计方案。

Quorum Journal方案中有两个重要的组件。
JournalNoe(JN) :运行在N台独立的物理机器上,它将editlog文件保存在JournalNode的本地磁盘上,同时JournalNode还对外提供RPC接口QJournalProtocol以执行远程读写editlog文件的功能。
QuorumJournalManager(QJM) :运行在NmaeNode上,(目前HA集群只有两个Namenode),通过调用RPC接口QJournalProtocol中的方法向JournalNode发送写入、排斥、同步editlog。
Quorum Journal方案依赖于这样一个概念:HDFS集群中有2N+1个JN存储editlog文件,这些editlog 文件是保存在JN的本地磁盘上的。每个JN对QJM暴露QJM接口QJournalProtocol,允许Namenode读写editlog 文件。当Namenode向共享存储写入editlog文件时,它会通过QJM向集群中所有的JN发送写editlog 文件请求,当有一半以上的JN返回写操作成功时,即认为写成功。这个原理是基于Paxos算法的。
使用Quorum Journal实现的HA方案有一下优点:
JN进程可以运行在普通的PC上,而无需配置专业的共享存储硬件。

以上是关于hadoop生态圈面试精华之HDFS部分的主要内容,如果未能解决你的问题,请参考以下文章

大数据-Hadoop生态-HDFS的读写数据流程以及机架感知

Hadoop之hdfs

Hadoop生态圈以及各组成部分的简介

hadoop和hadoop生态圈有啥区别

hadoop之 hadoop 机架感知

hadoop生态圈各个组件简介