#博学谷IT学习技术支持#
1. 企业存储系统
随着这两年产业互联网的推动和发展,越来越多的企业开始进行数字化转型,将传统的业务流程进行数字化改造。在进行数字化的过程中,需要数据来支撑企业的业务流程重塑,并以客户、产品为核心,以数据来支撑精细化运营。而数据分散在不同的系统中,要更充分的利用数据,需要将企业的大量数据集中存储,并进行业务化处理。此时,我们要想办法来解决大规模数据存储的问题。不管是使用哪种存储技术,都需要有存储硬件的支持。
1.1 硬盘
硬盘是计算机的主要存储硬件,可以用来存储大量数据。目前(2020年),市面上比较流行的硬盘多数是TB级的。
SATA硬盘
SATA即Serial ATA(串行ATA),是由Intel、IBM、Maxtor和Seagate等公司提出的硬盘接口规范。采用的是串行连接方式,很多时候会把SATA接口的硬盘称之为串口硬盘。拥有256M的磁盘缓存,转速7200rpm,每秒可达90-190MB的速度。
SATA SSD固态硬盘
采用固态电子存储芯片阵列制作的硬盘,是以闪存作为永久性存储器的存储设备。固态硬盘的读取速度可以在500Mb/s左右。
RAID磁盘阵列
单个硬盘的存储能力是有限的,如果要存储更多的数据,可以通过某种技术,将若干个硬盘连接在一起,提供能耗的存储能力。我们在服务器上插更多的磁盘来提高存储容量,而服务器上的插槽是有限的,我们无法无限地增加硬盘。所以,我们可以买RAID磁盘阵列来解决数据存储速度、容错问题。
RAID可以将多块独立的硬盘组织在一起,可以将多块硬盘连接在一起,并在性能上、容错上会有一定地提升。
1.2 文件系统
介绍
- 计算机的文件系统是一种存储和组织计算机数据的方法,它使得对其访问和查找变得容易
- 文件系统使用文件和树形目录的抽象逻辑概念代替了硬盘和光盘等物理设备使用数据块的概念,用户使用文件系统来保存数据不必关心数据实际保存在硬盘(或者光盘)的地址为多少的数据块上,只需要记住这个文件的所属目录和文件名。
- 在写入新数据之前,用户不必关心硬盘上的那个块地址没有被使用,硬盘上的存储空间管理(分配和释放)功能由文件系统自动完成,用户只需要记住数据被写入到了哪个文件中。
- 文件系统通常使用硬盘和光盘这样的存储设备,并维护文件在设备中的物理位置。但是,实际上文件系统也可能仅仅是一种访问资料的界面而已,实际的数据是通过网络协议(如NFS、SMB、9P等)提供的或者内存上,甚至可能根本没有对应的文件(如proc文件系统)。
- 严格地说,文件系统是一套实现了数据的存储、分级组织、访问和获取等操作的抽象数据类型(Abstract data type)。
重要概念
- 文件系统是一种用于向用户提供底层数据访问的机制。它将设备中的空间划分为特定大小的块(或者称为簇),一般每块512字节。数据存储在这些块中,大小被修正为占用整数个块。由文件系统软件来负责将这些块组织为文件和目录,并记录哪些块被分配给了哪个文件,以及哪些块没有被使用。
- 不过,文件系统并不一定只在特定存储设备上出现。它是数据的组织者和提供者,至于它的底层,可以是磁盘,也可以是其它动态生成数据的设备(比如网络设备)。
文件名
- 在文件系统中,文件名是用于定位存储位置。
- 大多数的文件系统对文件名的长度有限制。在一些文件系统中,文件名是大小写不敏感(如“AAA”和“aaa”指的是同一个文件);在另一些文件系统中则大小写敏感。
- 大多现今的文件系统允许文件名包含非常多的Unicode字符集的字符。然而在大多数文件系统的界面中,会限制某些特殊字符出现在文件名中。(文件系统可能会用这些特殊字符来表示一个设备、设备类型、目录前缀、或文件类型),为方便起见,一般不建议在文件名中包含特殊字符。
元数据
- 其它文件保存信息常常伴随着文件自身保存在文件系统中。
- 文件长度可能是分配给这个文件的区块数,也可能是这个文件实际的字节数。文件最后修改时间也许记录在文件的时间戳中。有的文件系统还保存文件的创建时间,最后访问时间及属性修改时间。(不过大多数早期的文件系统不记录文件的时间信息)其它信息还包括文件设备类型(如:区块数,字符集,套接口,子目录等等),文件所有者的ID,组ID,还有访问权限(如:只读,可执行等等)。
[root@node2 ~]# ll
total 32
-rw-------. 1 root root 2117 Apr 8 2020 anaconda-ks.cfg
drwxr-xr-x. 2 root root 6 Aug 30 09:33 Desktop
drwxr-xr-x. 2 root root 6 Aug 30 09:33 Documents
drwxr-xr-x. 2 root root 6 Aug 30 09:33 Downloads
-rw-r--r--. 1 root root 2165 Apr 8 2020 initial-setup-ks.cfg
drwxr-xr-x. 2 root root 6 Aug 30 09:33 Music
drwxr-xr-x. 2 root root 6 Aug 30 09:33 Pictures
-rw-r--r--. 1 root root 3158 Oct 10 22:53 profile
drwxr-xr-x. 2 root root 6 Aug 30 09:33 Public
drwxr-xr-x. 2 root root 6 Aug 30 09:33 Templates
drwxr-xr-x. 2 root root 6 Aug 30 09:33 Videos
-rw-r--r--. 1 root root 18234 Oct 10 18:04 zookeeper.out
面临海量数据存储的问题
-
成本高
- 传统存储硬件通用性差,设备投资加上后期维护、升级扩容的成本非常高。
-
性能低
- 单节点I/O性能瓶颈无法逾越,容量和性能都不易扩展,难以支撑海量数据的高并发高吞吐场景。
-
可扩展性差
- 无法实现快速部署和弹性扩展。
-
支持大数据分析、 AI
- 传统存储与Spark等大数据分析平台对接是否有难度,一套存储能否满足企业数据存储、管理和挖掘的需求。
场景案例:如何模拟实现分布式存储?
如何解决海量数据存的下问题
传统存储方式
应对文件存储服务,传统做法是在服务器上部署文件服务比如FTP。但是随着数据变多,会遇到存储瓶颈。此时,本能的操作反应是:内存不够加内存,磁盘不够加磁盘—单机纵向扩展。但是单机能够扩展的内存磁盘是有上限的,不能无限制下去。
分布式存储方式
纵向扩展有上限,自然想到横向扩展。所谓横向指的是采用多台机器存储,一台不够就多台一起存储,不够就加机器。
理论上,可以横向无限制下去。因此海量数据如何存储的下的问题解决方式就是采用多台机器存储—即分布式存储。
如何解决数据查询便捷问题
当文件被分布式存储在多台机器之后,后续获取文件的时候如何能快速找到文件位于哪台机器上呢。一台一台查询过来也不靠谱。因此可以借助于元数据记录来解决这个问题。把文件和其存储的机器的位置信息记录下来,类似于图书馆查阅图书系统,这样就可以快速定位文件存储在哪一台机器上了。
如何解决大文件传输效率慢问题
大数据使用场景下,GB、TP级别的大文件是常见的。当单个文件过大的时候,如何提高传输效率?通常的做法是分块存储:把大文件拆分成若干个小块(block 简写blk),分别存储在不同机器上,并行操作提高效率。
此外分块存储还可以解决数据存储负载均衡问题。此时元数据记录信息也应该更加详细:文件分了几块,分别位于哪些机器上。
如何解决数据丢失问题
机器、磁盘等硬件出现故障是难以避免的事情,如何保证数据存储的安全性。如果某台机器故障,数据块丢失,对于文件来说整体就是不完整的。冗余存储是个不错的选择。采用副本机制。副本越多,数据越安全,当然冗余也会越多。通过“不要把鸡蛋放在一个篮子里”的思想,可以把数据丢失的风险分散到各个机器上。
如何解决用户查询视角统一问题
随着存储的进行,数据文件越来越多,与之对应元数据信息也越来越多,如何让用户视觉层面感觉不到元数据的凌乱,同时也与传统的文件系统操作体验保持一致?传统的文件系统拥有所谓的目录树结构,带有层次感的namespace(命名空间),因此可以把分布式文件系统的元数据记录这一块也抽象成统一的目录树结构。
小结
通过上述场景式分析,可以得出要想实现一个分布式文件系统,是需要多方面综合考虑的。通常来说一个分布式文件系统需要具备:分布式特性、分块存储、副本机制、元数据记录、抽象目录树、统一namespace命名空间。
2.分布式文件HDFS
HDFS简介
- HDFS(Hadoop Distributed File System)是 Apache Hadoop 项目的一个子项目,它的设计初衷是为了能够支持高吞吐和超大文件读写操作
- HDFS是一种能够在普通硬件上运行的分布式文件系统,它是高度容错的,适应于具有大数据集的应用程序,它非常适于存储大型数据 (比如 TB 和 PB)
- HDFS使用多台计算机存储文件, 并且提供统一的访问接口, 像是访问一个普通文件系统一样使用分布式文件系统
HDFS发展历史
- Doug Cutting 在做 Lucene 的时候, 需要编写一个爬虫服务, 这个爬虫写的并不顺利, 遇到 了一些问题, 诸如: 如何存储大规模的数据, 如何保证集群的可伸缩性, 如何动态容错等
- 200x年的时候, Google 发布了三篇论文, 被称作为三驾马车, 其中有一篇叫做 GFS
- GFS是描述了 Google 内部的一个叫做 GFS 的分布式大规模文件系统, 具有强大的可伸缩性和容错
- Doug Cutting后来根据 GFS 的论文, 创造了一个新的文件系统, 叫做 HDFS
HDFS设计目标
- HDFS集群由很多的服务器组成,而每一个机器都与可能会出现故障。HDFS为了能够进行故障检测、快速恢复等。
- HDFS主要适合去做批量数据出来,相对于数据请求时的反应时间,HDFS更倾向于保障吞吐量。
- 典型的HDFS中的文件大小是GB到TB,HDFS比较适合存储大文件
- HDFS很多时候是以: Write-One-Read-Many来应用的,一旦在HDFS创建一个文件,写入完后就不需要修改了
HDFS应用场景
适合的应用场景
- 存储非常大的文件:这里非常大指的是几百M、G、或者TB级别,需要高吞吐量,对延时没有要求。
- 基于流的数据访问方式: 即一次写入、多次读取,数据集经常从数据源生成或者拷贝一次,然后在其上做很多分析工作 ,且不支持文件的随机修改。
- 正因为如此,HDFS适合用来做大数据分析的底层存储服务,并不适合用来做网盘等应用,因为,修改不方便,延迟大,网络开销大,成本太高。
- 运行于商业硬件上: Hadoop不需要特别贵的机器,可运行于普通廉价机器,可以处节约成本
- 需要高容错性
- 为数据存储提供所需的扩展能力
不适合的应用场景
- 低延时的数据访问 对延时要求在毫秒级别的应用,不适合采用HDFS。HDFS是为高吞吐数据传输设计的,因此可能牺牲延时
- 大量小文件的元数据保存在NameNode的内存中, 整个文件系统的文件数量会受限于NameNode的内存大小。 经验而言,一个文件/目录/文件块一般占有150字节的元数据内存空间。如果有100万个文件,每个文件占用1个文件块,则需要大约300M的内存。因此十亿级别的文件数量在现有商用机器上难以支持
- 多方读写,需要任意的文件修改 HDFS采用追加(append-only)的方式写入数据。不支持文件任意offset的修改,HDFS适合用来做大数据分析的底层存储服务,并不适合用来做.网盘等应用,因为,修改不方便,延迟大,网络开销大,成本太高。
HDFS重要特性
-
主从架构
- HDFS采用master/slave架构。一般一个HDFS集群是有一个Namenode和一定数目的Datanode组成。Namenode是HDFS主节点,Datanode是HDFS从节点,两种角色各司其职,共同协调完成分布式的文件存储服务。
-
分块机制
- HDFS中的文件在物理上是分块存储(block)的,块的大小可以通过配置参数来规定,参数位于hdfs-site.xml中:dfs.blocksize。默认大小是128M(134217728)。
-
副本机制
- 为了容错,文件的所有block都会有副本。每个文件的block大小(dfs.blocksize)和副本系数(dfs.replication)都是可配置的。应用程序可以指定某个文件的副本数目。副本系数可以在文件创建的时候指定,也可以在之后通过命令改变。
- 默认dfs.replication的值是3,也就是会额外再复制2份,连同本身总共3份副本。
-
Namespace
- HDFS支持传统的层次型文件组织结构。用户可以创建目录,然后将文件保存在这些目录里。文件系统名字空间的层次结构和大多数现有的文件系统类似:用户可以创建、删除、移动或重命名文件。
- Namenode负责维护文件系统的namespace名称空间,任何对文件系统名称空间或属性的修改都将被Namenode记录下来。
- HDFS会给客户端提供一个统一的抽象目录树,客户端通过路径来访问文件,形如:hdfs://namenode:port/dir-a/dir-b/dir-c/file.data。
-
元数据管理
-
在HDFS中,Namenode管理的元数据具有两种类型:
-
文件自身属性信息
- 文件名称、权限,修改时间,文件大小,复制因子,数据块大小。
-
文件块位置映射信息
- 记录文件块和DataNode之间的映射信息,即哪个块位于哪个节点上。
-
-
-
数据块存储
- 文件的各个block的具体存储管理由DataNode节点承担。每一个block都可以在多个DataNode上存储。
3.HDFS的Shell命令
HDFS是存取数据的分布式文件系统,那么对HDFS的操作,就是文件系统的基本操作,比如文件的创建、修改、删除、修改权限等,文件夹的创建、删除、重命名等。对HDFS的操作命令类似于Linux的shell对文件的操作,如ls、mkdir、rm等。
Hadoop提供了文件系统的shell命令行客户端,使用方法如下:
hadoop fs <args>
文件系统shell包括与Hadoop分布式文件系统(HDFS)以及Hadoop支持的其他文件系统(如本地FS,HFTP FS,S3 FS等)直接交互的各种类似shell的命令。
所有FS shell命令都将路径URI作为参数。URI格式为scheme://authority/path。对于HDFS,该scheme是hdfs,对于本地FS,该scheme是file。scheme和authority是可选的。如果未指定,则使用配置中指定的默认方案。
对于HDFS,命令示例如下:
hadoop fs -ls hdfs://namenode:port/parent/child
hadoop fs -ls /parent/child #core-site.xml中的fs.defaultFS中有配置
对于本地文件系统,命令示例如下:
hadoop fs -ls file:///root/
如果使用的文件系统是HDFS,则也可使用hdfs dfs 命令。
Shell命令选项
无法复制加载中的内容
常用的Shell命令
-ls
格式: hadoop fs -ls URI
作用:类似于Linux的ls命令,显示文件列表
hadoop fs -ls /
-lsr
格式 : hdfs dfs -lsr URI
作用 : 在整个目录下递归执行ls , 与UNIX中的ls-R类似
hadoop fs -lsr /
-mkdir
格式 : hdfs dfs [-p] -mkdir <paths>
作用 : 以<paths>中的URI作为参数,创建目录。使用-p参数可以递归创建目录
hadoop fs -mkdir /dir1
hadoop fs -mkdir /dir2
hadoop fs -p -mkdir /aaa/bbb/ccc
-put
格式 : hadoop fs -put <localsrc > ... <dst>
作用 : 将单个的源文件src或者多个源文件srcs从本地文件系统拷贝到目标文件系统中
(<dst>对应的路径)。也可以从标准输入中读取输入,写入目标文件系统中
echo “Hello HDFS” >> /root/1.txt
hadoop fs -put /root/1.txt /dir1
-moveFromLocal
格式: hdfs dfs -moveFromLocal < localsrc > < dst >
作用 : 和put命令类似,但是源文件localsrc拷贝之后自身被删除
echo “Hello HDFS” >> /root/2.txt
hdfs dfs -moveFromLocal /root/2.txt /
-moveToLocal
未实现
-get
格式 hadoop fs -get [-ignorecrc ] [-crc] <src> <localdst>
作用:将文件拷贝到本地文件系统。 CRC 校验失败的文件通过-ignorecrc选项拷贝。
文件和CRC校验和可以通过-CRC选项拷贝
hadoop fs -get /2.txt /export/data
-getmerge
格式: hadoop fs -getmerge -nl < hdfs dir > < local file >
功能:合并下载多个文件
参数: 加上nl后,合并到local file中的hdfs文件之间会空出一行
示例:比如hdfs的目录 /aaa/下有多个文件:log.1, log.2,log.3,...
hadoop fs -getmerge /aaa/log.* ./log.sum
-mv
格式 : hdfs dfs -mv URI <dest>
作用: 将hdfs上的文件从原路径移动到目标路径(移动之后文件删除),该命令不能夸文件系统
hdfs dfs -mv /dir1/a.txt /dir2
-rm
格式: hadoop fs -rm [-r] 【-skipTrash】 URI 【URI 。。。】
作用: 删除参数指定的文件和目录,参数可以有多个,删除目录需要加-r参数
如果指定-skipTrash选项,那么在回收站可用的情况下,该选项将跳过回收站而直接删除文件;
否则,在回收站可用时,在HDFS Shell 中执行此命令,会将文件暂时放到回收站中。
hadoop fs -rm /2.txt #删除文件
hadoop fs -rm -r /dir1 #删除目录
-cp
格式: hdfs dfs -cp URI [URI ...] <dest>
作用: 将文件拷贝到目标路径中。如果<dest> 为目录的话,可以将多个文件拷贝到该目录下。
-f 选项将覆盖目标,如果它已经存在。
-p 选项将保留文件属性(时间戳、所有权、许可、ACL、XAttr)。
hadoop fs -cp /dir1/1.txt /dir2/2.txt
-cat
hadoop fs -cat URI [uri ...]
作用:将参数所指示的文件内容输出到控制台
hadoop fs -cat /dir2/2.txt
-du
hadoop fs -cat URI
功能:显示目录中所有文件大小,当只指定一个文件时,显示此文件的大小。
hadoop fs -du /
-chmod
格式: hadoop fs -chmod [-R] URI[URI ...]
作用: 改变文件权限。如果使用 -R 选项,则对整个目录有效递归执行。使用这一命令的用户必须是文件的所属用户,或者超级用户。
例如:可以创建一个用户hadoop,将/a.txt的所属用户和所属用户组修改为hadoop
hadoop fs -chmod -R 777 /dir1
-chown
格式: hdfs dfs -chmod [-R] URI[URI ...]
作用: 改变文件的所属用户和用户组。如果使用 -R 选项,则对整个目录有效递归执行。使用这一命令的用户必须是文件的所属用户,或者超级用户。
hadoop fs -chown -R hadoop:hadoop /a.txt
-appendToFile
格式: hdfs dfs -chmod [-R] URI[URI ...]
作用: 改变文件的所属用户和用户组。如果使用 -R 选项,则对整个目录有效递归执行。
使用这一命令的用户必须是文件的所属用户,或者超级用户。
hadoop fs -chown -R hadoop:hadoop /a.txt
-setrep 命令
HDFS中默认每个block会保存三个副本,同样一份数据需要存3份。假设,此处我们需要将 /source/weibo/start/comment_log/20190811_node1 因为已经过去了很久,我们对该目录下的文件容错要求较低、而且数据使用频率也较低,所以,我们可以将它的副本数调整为2,此时我们需要使用setrep命令。
hdfs dfs -setrep [-R] [-w] <numReplicas> <path>
更改文件的副本因子。 如果path是目录,则该命令以递归方式更改以path为根的目录树下所有文件的复制因子。
参数:
- -w:标志请求命令等待复制完成。 这可能会花费很长时间。
- -R:标志是为了向后兼容。 没有作用
[root@node1 ~]# hdfs dfs -setrep -w 2 /dir/a.txt
Replication 2 set: /source/weibo/star/comment_log/20190811_node1/caixukun.csv
Waiting for /source/weibo/star/comment_log/20190811_node1/caixukun.csv ...
WARNING: the waiting time may be long for DECREASING the number of replications.
. done
4.HDFS的安全模式
安全模式是hadoop的一种保护机制,用于保证集群中的数据块的安全性。当集群启动的时候,会首先进入安全模式。当系统处于安全模式时会检查数据块的完整性。
在NameNode启动过程中,等待DataNodes汇报可用的block信息。在此期间,NameNode保持在安全模式。随着DataNode的block汇报持续进行,当整个系统达到安全标准时,HDFS自动离开安全模式。在NameNode Web主页上会显示安全模式是打开还是关闭。
如果HDFS处于安全模式下,不允许HDFS客户端进行任何修改文件的操作,包括上传文件,删除文件,重命名,创建文件夹,修改副本数等操作。
假设我们设置的副本数(即参数dfs.replication)是3,那么在datanode上就应该有3个副本存在,假设只存在2个副本,那么比例就是2/3=0.666。hdfs默认的副本率0.999。我们的副本率0.666明显小于0.999,因此系统会自动的复制副本到其他dataNode,使得副本率不小于0.999。如果系统中有5个副本,超过我们设定的3个副本,那么系统也会删除多于的2个副本。
在安全模式状态下,文件系统只接受读数据请求,而不接受删除、修改等变更请求。在当整个系统达到安全标准时,HDFS自动离开安全模式。
安全模式操作命令
hdfs dfsadmin -safemode get #查看安全模式状态
hdfs dfsadmin -safemode enter #进入安全模式
hdfs dfsadmin -safemode leave #离开安全模式
5.HDFS的数据读写流程
因为namenode维护管理了文件系统的元数据信息,这就造成了不管是读还是写数据都是基于NameNode开始的,也就是说NameNode成为了HDFS访问的唯一入口。入口地址是:http://nn_host:8020。
写数据流程
Pipeline管道、ACK应答响应
Pipeline,中文翻译为管道。这是HDFS在上传文件写数据过程中采用的一种数据传输方式。客户端将数据块写入第一个数据节点,第一个数据节点保存数据之后再将块复制到第二个数据节点,后者保存后将其复制到第三个数据节点。通俗描述pipeline的过程就是:ClientABC。
为什么datanode之间采用pipeline线性传输,而不是一次给三个datanode拓扑式传输呢?因为数据以管道的方式,顺序的沿着一个方向传输,这样能够充分利用每个机器的带宽,避免网络瓶颈和高延迟时的连接,最小化推送所有数据的延时。在线性推送模式下,每台机器所有的出口宽带都用于以最快的速度传输数据,而不是在多个接受者之间分配宽带。
ACK (Acknowledge character)即是确认字符,在数据通信中,接收方发给发送方的一种传输类控制字符。表示发来的数据已确认接收无误。在pipeline管道传输数据的过程中,传输的反方向会进行ACK校验,确保数据传输安全。
具体流程
- HDFS客户端通过对DistributedFileSystem 对象调用create() 请求创建文件。
- DistributedFileSystem对namenode进行RPC 调用,请求上传文件。namenode执行各种检查判断:目标文件是否存在、父目录是否存在、客户端是否具有创建该文件的权限。检查通过,namenode就会为创建新文件记录一条记录。否则,文件创建失败并向客户端抛出一个IOException。
- DistributedFileSystem为客户端返回FSDataOutputStream输出流对象。由此客户端可以开始写入数据。FSDataOutputStream是一个包装类,所包装的是DFSOutputStream。
- 在客户端写入数据时,DFSOutputStream将它分成一个个数据包(packet 默认64kb),并写入一个称之为数据队列(data queue) 的内部队列。DFSOutputStream有一个内部类做DataStreamer,用于请求NameNode挑选出适合存储数据副本的一组DataNode。这一组DataNode采用pipeline机制做数据的发送。默认是3副本存储。
- DataStreamer将数据包流式传输到pipeline的第一个datanode,该DataNode存储数据包并将它发送到pipeline的第二个DataNode。同样,第二个DataNode存储数据包并且发送给第三个(也是最后一个)DataNode。
- DFSOutputStream也维护着一个内部数据包队列来等待DataNode的收到确认回执,称之为确认队列(ack queue) ,收到pipeline中所有DataNode确认信息后,该数据包才会从确认队列删除。
- 客户端完成数据写入后,将在流上调用close()方法关闭。该操作将剩余的所有数据包写入DataNode pipeline,并在联系到NameNode告知其文件写入完成之前,等待确认。
- 因为namenode已经知道文件由哪些块组成(DataStream请求分配数据块),因此它仅需等待最小复制块即可成功返回。
- 数据块最小复制是由参数dfs.namenode.replication.min指定,默认是1.
默认3副本存储策略
默认副本存储策略是由BlockPlacementPolicyDefault指定。策略如下:
第一块副本:优先客户端本地,否则随机
第二块副本:不同于第一块副本的不同机架。
第三块副本:第二块副本相同机架不同机器。
读数据流程
具体流程
- 客户端通过调用DistributedFileSystem对象上的open()来打开希望读取的文件。
- DistributedFileSystem使用RPC 调用namenode来确定文件中前几个块的块位置。对于每个块,namenode返回具有该块副本的datanode的地址,并且datanode根据块与客户端的距离进行排序。注意此距离指的是网络拓扑中的距离。比如客户端的本身就是一个DataNode,那么从本地读取数据明显比跨网络读取数据效率要高。
- DistributedFileSystem将FSDataInputStream(支持文件seek定位读的输入流) 返回到客户端以供其读取数据。FSDataInputStream类转而封装为DFSInputStream类,DFSInputStream管理着datanode和namenode之间的IO。
- 客户端在流上调用read()方法。然后,已存储着文件前几个块DataNode地址的DFSInputStream随即连接到文件中第一个块的最近的DataNode节点。通过对数据流反复调用read()方法,可以将数据从DataNode传输到客户端。
- 当该块快要读取结束时,DFSInputStream将关闭与该DataNode的连接,然后寻找下一个块的最佳datanode。这些操作对用户来说是透明的。所以用户感觉起来它一直在读取一个连续的流。
- 客户端从流中读取数据时,块是按照打开DFSInputStream与DataNode新建连接的顺序读取的。它也会根据需要询问NameNode来检索下一批数据块的DataNode位置信息。一旦客户端完成读取,就对FSDataInputStream调用close()方法。
- 如果DFSInputStream与DataNode通信时遇到错误,它将尝试该块的下一个最接近的DataNode读取数据。并将记住发生故障的DataNode,保证以后不会反复读取该DataNode后续的块。此外,DFSInputStream也会通过校验和(checksum)确认从DataNode发来的数据是否完整。如果发现有损坏的块,DFSInputStream会尝试从其他DataNode读取该块的副本,也会将被损坏的块报告给namenode 。
6.HDFS的元数据辅助管理
元数据是什么
元数据(Metadata) ,又称中介数据,为描述数据的数据(data about data),主要是描述数据属性(property)的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能。
在HDFS中,元数据主要指的是文件相关的元数据,由NameNode管理维护。从广义的角度来说,因为NameNode还需要管理众多DataNode节点,因此DataNode的位置和健康状态信息也属于元数据。
元数据管理概述
在HDFS中,文件相关元数据具有两种类型:
- 文件自身属性信息
文件名称、权限,修改时间,文件大小,复制因子,数据块大小。
- 文件块位置映射信息
记录文件块和DataNode之间的映射信息,即哪个块位于哪个节点上。
按存储形式分为内存元数据和元数据文件两种,分别存在内存和磁盘上。
内存元数据
为了保证用户操作元数据交互高效,延迟低,NameNode把所有的元数据都存储在内存中,我们叫做内存元数据。内存中的元数据是最完整的,包括文件自身属性信息、文件块位置映射信息。
但是内存的致命问题是,断点数据丢失,数据不会持久化。因此NameNode又辅佐了元数据文件来保证元数据的安全完整。
磁盘元数据文件
fsimage 内存镜像文件
是内存元数据的一个持久化的检查点。但是fsimage中仅包含Hadoop文件系统中文件自身属性相关的元数据信息,但不包含文件块位置的信息。文件块位置信息只存储在内存中,时由datanode启动加入集群的时候,向namenode进行数据块的汇报得到的,并且后续间断指定时间进行数据块报告。
持久化的动作是一种数据从内存到磁盘的IO过程。会对namenode正常服务造成一定的影响,不能频繁的进行持久化。
Edits log编辑日志
为了避免两次持久化之间数据丢失的问题,又设计了Edits log编辑日志文件。文件中记录的是HDFS所有更改操作(文件创建,删除或修改)的日志,文件系统客户端执行的更改操作首先会被记录到edits文件中。
加载元数据顺序
fsimage和edits文件都是经过序列化的,在NameNode启动的时候,它会将fsimage文件中的内容加载到内存中,之后再执行edits文件中的各项操作,使得内存中的元数据和实际的同步,存在内存中的元数据支持客户端的读操作,也是最完整的元数据。
当客户端对HDFS中的文件进行新增或者修改操作,操作记录首先被记入edits日志文件中,当客户端操作成功后,相应的元数据会更新到内存元数据中。因为fsimage文件一般都很大(GB级别的很常见),如果所有的更新操作都往fsimage文件中添加,这样会导致系统运行的十分缓慢。
HDFS这种设计实现着手于:一是内存中数据更新、查询快,极大缩短了操作响应时间;二是内存中元数据丢失风险颇高(断电等),因此辅佐元数据镜像文件(fsimage)+编辑日志文件(edits)的备份机制进行确保元数据的安全。
NameNode维护整个文件系统元数据。因此,元数据的准确管理,影响着HDFS提供文件存储服务的能力。
元数据管理相关目录文件
元数据存储目录
在Hadoop的HDFS首次部署好配置文件之后,并不能马上启动使用,而是先要对文件系统进行格式化操作:hdfs namenode -format
在这里要注意两个概念,一个是format之前,HDFS在物理上还不存在;二就是此处的format并不是指传统意义上的本地磁盘格式化,而是一些清除与准备工作。其中就会创建元数据本地存储目录和一些初始化的元数据相关文件。
namenode元数据存储目录由参数:dfs.namenode.name.dir指定,格式化完成之后,将会在$dfs.namenode.name.dir/current目录下创建如下的文件:
其中的dfs.namenode.name.dir是在hdfs-site.xml文件中配置的,默认值如下:
dfs.namenode.name.dir属性可以配置多个目录,各个目录存储的文件结构和内容都完全一样,相当于备份,这样做的好处是当其中一个目录损坏了,也不会影响到hadoop的元数据,特别是当其中一个目录是NFS(网络文件系统Network File System,NFS)之上,即使你这台机器损坏了,元数据也得到保存。
元数据相关文件
fsimage相关
元数据镜像文件。每个fsimage文件还有一个对应的.md5文件,其中包含MD5校验和,HDFS使用该文件来防止磁盘损坏文件异常。
Edits log相关
已完成且不可修改的编辑日志。这些文件中的每个文件都包含文件名定义的范围内的所有编辑日志事务。在HA高可用性部署中,主备namenode之间可以通过edits log进行数据同步。
Fsimage、editslog查看
Fsimage
fsimage文件是Hadoop文件系统元数据的一个永久性的检查点,包含Hadoop文件系统中的所有目录和文件idnode的序列化信息;对于文件来说,包含的信息有修改时间、访问时间、块大小和组成一个文件块信息等;而对于目录来说,包含的信息主要有修改时间、访问控制权限等信息。
oiv是offline image viewer的缩写,用于将fsimage文件的内容转储到指定文件中以便于阅读,该工具还提供了只读的WebHDFS API以允许离线分析和检查hadoop集群的命名空间。
oiv在处理非常大的fsimage文件时是相当快的,如果该工具不能够处理fsimage,它会直接退出。该工具不具备向后兼容性,比如使用hadoop-2.4版本的oiv不能处理hadoop-2.3版本的fsimage,只能使用hadoop-2.3版本的oiv。就像它的名称所提示的(offline),oiv不需要hadoop集群处于运行状态。
命令:hdfs oiv -i fsimage_0000000000000000050 -p XML -o fsimage.xml
edits log
edits log文件存放的是Hadoop文件系统的所有更新操作记录日志,文件系统客户端执行的所有写操作首先会被记录到edits文件中。
NameNode起来之后,HDFS中的更新操作会重新写到edits文件中,因为fsimage文件一般都很大(GB级别的很常见),如果所有的更新操作都往fsimage文件中添加,这样会导致系统运行的十分缓慢,但是如果往edits文件里面写就不会这样,每次执行写操作之后,且在向客户端发送成功代码之前,edits文件都需要同步更新。如果一个文件比较大,使得写操作需要向多台机器进行操作,只有当所有的写操作都执行完成之后,写操作才会返回成功,这样的好处是任何的操作都不会因为机器的故障而导致元数据的不同步。
oev是offline edits viewer(离线edits查看器)的缩写,该工具不需要hadoop集群处于运行状态。
命令:hdfs oev -i edits_0000000000000000011-0000000000000000025 -o edits.xml
在输出文件中,每个RECORD记录了一次操作,示例如下:
SecondaryNamenode
SNN职责概述
NameNode职责是管理元数据信息,DataNode的职责是负责数据具体存储,那么SecondaryNameNode的作用是什么?对很多初学者来说是非常迷惑的。它为什么会出现在HDFS中。从它的名字上看,它给人的感觉就像是NameNode的备份。但它实际上却不是。
当HDFS集群运行一段事件后,就会出现下面一些问题:
- edits logs会变的很大,fsimage将会变得很旧;
- namenode重启会花费很长时间,因为有很多改动要合并到fsimage文件上;
- 如果频繁进行fsimage持久化,又会影响NameNode正常服务,毕竟IO操作是一种内存到磁盘的耗精力操作
因此为了克服这个问题,需要一个易于管理的机制来帮助我们减小edit logs文件的大小和得到一个最新的fsimage文件,这样也会减小在NameNode上的压力。
SecondaryNameNode就是来帮助解决上述问题的,它的职责是合并NameNode的edit logs到fsimage文件中。
SNN checkpoint机制
概述
Checkpoint核心是把fsimage与edits log合并以生成新的fsimage的过程。此过程有两个好处:fsimage版本不断更新不会太旧、edits log文件不会太大。
流程
- 当触发checkpoint操作条件时,SNN发生请求给NN滚动edits log。然后NN会生成一个新的编辑日志文件:edits new,便于记录后续操作记录。
- 同时SNN会将edits文件和fsimage复制到本地(使用HTTP GET方式)。
- SNN首先将fsimage载入到内存,然后一条一条地执行edits文件中的操作,使得内存中的fsimage不断更新,这个过程就是edits和fsimage文件合并。合并结束,SNN将内存中的数据dump生成一个新的fsimage文件。
- SNN将新生成的Fsimage new文件复制到NN节点。
- 至此刚好是一个轮回,等待下一次checkpoint触发SecondaryNameNode进行工作,一直这样循环操作。
触发机制
Checkpoint触发条件受两个参数控制,可以通过core-site.xml进行配置:
dfs.namenode.checkpoint.period=3600 //两次连续的checkpoint之间的时间间隔。默认1小时
dfs.namenode.checkpoint.txns=1000000 //最大没有执行checkpoint事务的数量,满足将强制执行紧急checkpoint,即使尚未达到检查点周期。默认100万事务数量
从上面的描述我们可以看出,SecondaryNamenode根本就不是Namenode的一个热备,只是将fsimage和edits合并。
Namenode 元数据恢复
NameNode存储多目录
namenode元数据存储目录由参数:dfs.namenode.name.dir指定。
dfs.namenode.name.dir属性可以配置多个目录,各个目录存储的文件结构和内容都完全一样,相当于备份,这样做的好处是当其中一个目录损坏了,也不会影响到hadoop的元数据,特别是当其中一个目录是NFS(网络文件系统Network File System,NFS)之上,即使你这台机器损坏了,元数据也得到保存。
从SecondaryNameNode恢复
SecondaryNameNode在checkpoint的时候会将fsimage和edits log下载到自己的本机上本地存储目录下。并且在checkpoint之后也不会进行删除。
如果NameNode中的fsimage真的出问题了,还是可以用SecondaryNamenode中的fsimage替换一下NameNode上的fsimage,虽然已经不是最新的fsimage,但是我们可以将损失减小到最少!
7.使用文件系统方式访问数据
HDFS操作 - Java客户端
介绍
HDFS在生产应用中主要是客户端的开发,其核心步骤是从HDFS提供的api中构造一个HDFS的访问客户端对象,然后通过该客户端对象操作(增删改查)HDFS上的文件。
实现HDFS操作类
HDFS API 介绍
涉及的主要类
在Java中操作HDFS,主要涉及以下Class:
- Configuration: 该类的对象封转了客户端或者服务器的配置
- FileSystem: 该类的对象是一个文件系统对象,可以用该对象的一些方法来对文件进行操作,通过FileSystem的静态方法get获得该对象。
FileSystem fs = FileSystem.get(conf);
- get方法从conf中的一个参数 fs.defaultFS的配置值判断具体是什么类型的文件系统。如果我们的代码中没有指定fs.defaultFS,并且工程classpath下也没有给定相应的配置,conf中的默认值就来自于hadoop的jar包中的core-default.xml,默认值为: file:///,则获取的将不是一个DistributedFileSystem的实例,而是一个本地文件系统的客户端对象。
Java API官方文档:
hadoop.apache.org/docs/r3.1.4…
获取FileSystem方式
使用文件系统方式访问数据
涉及的主要类
在java中操作HDFS,主要涉及以下Class:
Configuration: 该类的对象封转了客户端或者服务器的配置;
FileSystem: 该类的对象是一个文件系统对象,可以用该对象的一些方法来对文件进行操作,通过FileSystem的静态方法get获得该对象。
FileSystem fs = FileSystem. get (conf);
get方法从conf中的一个参数 fs.defaultFS的配置值判断具体是什么类型的文件系统。如果我们的代码中没有指定fs.defaultFS,并且工程classpath下也没有给定相应的配置,conf中的默认值就来自于hadoop的jar包中的core-default.xml,默认值为: file:///,则获取的将不是一个DistributedFileSystem的实例,而是一个本地文件系统的客户端对象。