200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > Hadoop的分布式文件系统—— Hadoop权威指南3

Hadoop的分布式文件系统—— Hadoop权威指南3

时间:2021-04-04 22:40:32

相关推荐

Hadoop的分布式文件系统—— Hadoop权威指南3

本章除了讲解HDFS,还从整个Hadoop文件系统的角度介绍了文件系统的命令行、FileSystem接口(Hadoop文件系统的客户端接口)

1. HDFS概述

1. HDFS的特性、应用场景(适合/不适合什么?why?)

HDFS的是Hadoop的分布式文件系统,全称Hadoop Distributed Filesystem

HDFS具有以下特性:

超大文件:几百MB、几百GB甚至几百TB的大文件,甚至还出现了存储PB级文件的Hadoop集群流式数据访问:HDFS基于一次写入、多次读取是高效的文件访问模式构建的。商用硬件(普通硬件):Hadoop将运行在商用硬件集群上,节点故障将会是常态。HDFS在遇到节点故障时,能继续提供服务而不被用户感知。

HDFS不适用的场景

大量的小文件:HDFS中,文件的元数据信息存储在namenode的内存中。一般,一个文件的元数据信息为150 Byte。如果,HDFS中存在大量的小文件(如数十亿个小文件),则会超过内存的存储容量。低延迟数据访问:HDFS专为大文件实现高吞吐,可能会以提高数据时延为代价。因此,HDFS不适合低延迟数据访问。 —— HBase是更好的选择随机写/多用户写:因为HDFS只允许顺序写,支持单个用户写入。

1.2 HDFS中namenode和datanode

HDFS中的namenode是整个文件系统的管理者,负责管理文件系统的namespace。

① 以文件的形式永久存储namespace镜像文件和编辑日志文件

② 在内存中,存储block的位置信息datanode:

① 负责block的存储和检索

② 同时,定期向namenode上报自己存储的block列表namenode初期的容错机制:

① 将namenode在多个文件系统中保持元数据持久状态:写入本地磁盘和网络文件系统

② 使用辅助namenode,不是真正的namenode,而是定期合并namespace镜像文件和编辑日志,减轻namenode的CPU压力

③ 更好的方法:namenode失效时,从NFS复制到辅助namenode并作为新的namenode运行

注意:

这里的备用namenode就是常说的secondaryNameNode,从Hadoop0.21.0版本中开始出现。也就是说,在Hadoop 1.x中,就有secondaryNameNode了Hadoop 1.x版本和2.x版本,最大的区别是增加了yarn,专门用于资源管理和任务调度,使MR专注于分布式计算Hadoop 3.x没有架构上的变化,而是专注于性能优化 —— 可以参考视频:Hadoop概述–Hadoop发行版本、架构变迁

1.3 HDFS的数据块(block)
磁盘有默认的数据块大小,这是磁盘进行数据读写的最小单位,如512 Byte同时,文件系统也有数据块的概念,一般是磁盘数据块的整数倍。数据块的设置对于用户来说是透明的,他们无法感知到磁盘或文件系统的数据块大小HDFS也有数据块(block)的概念,不同版本的Hadoop中HDFS数据块的默认大小有变化。从Hadoop 2.7.3开始,默认的block从64MB变成了128MB

block大小如何抉择?

HDFS的block大小比磁盘块大很多,这是为了最小化寻址开销。一个块足够大,则数据传输时间会明显大于磁盘寻道时间。这样,一个由多个块组成的大文件的传输时间就会取决于磁盘的传输速率。map任务通常一次只处理一个block中的数据,如果block过于大,数据块将变少。map任务也变少,不利于充分发挥集群的分布式计算能力

block带来的好处

block的概念使得一个超过磁盘大小的文件,可以跨机器存储使用抽象的block作为数据存储单元,而不是使用整个文件,这样可以简化存储子系统的设计;同时,有利于将文件数据和文件元数据独立管理。block还有利于数据备份,提高HDFS的容错能力

注意:在HDFS中,虽然规定一个block为128MB。但是,如果文件末尾的数据块只有1MB,在实际存储时,它是不会真正的占据128MB的存储空间。

2. HDFS的HA(高可用性)

前面有提到说,辅助namenode可以帮助namenode合并编辑日志到namespace镜像文件中,从而减轻namenode的压力。同时,可以结合NFS和辅助namenode,实现在namenode故障时,快速切换到新的namenode

其实,namenode存在单点失效(SPOF)的问题,一旦namenode故障或软/硬件升级,所有的Hadoop将无法读写HDFS

想要切换到新的namenode至少需要30分钟甚至更长时间。

如何能将在namenode故障时,能迅速切换到新的namenode,保证Hadoop服务无任何明显的中断?

Hadoop 2针对这个问题,为HDFS提供了高可用性的支持。将提供服务namenode叫做active namenode,而为实现HA作备份的namenode叫做standby namenode

active namenode:在任何时候都处于active状态,负责处理所有客户端操作

standby namenode:充当工作人员角色的同时,拥有足够多的状态信息,能在时刻提供快速的故障转移

2.1 QJM实现HDFS的HA

Quorum Journal Manager,群体日志管理器,专为HDFS实现,可以提供一个HA的编辑日志。基于QJM的HA集群,需要两种节点:

① namenode节点:配置完全相同、运行active和standby namenode的节点

② 日志节点:用于运行JournalNode进程的节点,由于journalNode是相对轻量级,因此它可以在其他的Hadoop节点上运行。例如,运行namenode、resourceManager、jobTracker的上

注意

至少应该有3个日志节点,对编辑日志的更新要求必须写入了大多数日志节点也就是说,日志节点可以容忍至多 ( N − 1 ) / 2 (N-1)/2 (N−1)/2的故障

基于NFS的HA以及这两种HA的实现方式,后续通过专门的专题进行学习

3. Hadoop的文件系统

我们一说到Hadoop,总会提到HDFS,但是Hadoop不止有HDFS这一种文件系统Hadoop有一个抽象的文件系统概念,提供了fs.FileSystem接口,可以用于实现各种不同的文件系统Hadoop中已经实现的文件系统有:Local(本地文件系统)、HDFS、WebHDFS(基于http的文件系统)、S3(由Amazon S3支持的文件系统)、Swift(由OpenStack Swift支持的文件系统)等

3.1 文件系统命令行

Hadoop不仅基于文件系统接口实现了各种文件系统,它还提供了操作文件系统的丰富命令这些命令以hadoop fs开头,可以操作各种各样的Hadoop文件系统,包括本地文件系统、S3、WebHDFS等完整的命令可以参考官网:FileSystem Shell同时,还有专门针对HDFS的命令行,其中hdfs dfs专门用于操作HDFS文件系统

hadoop fs与hdfs dfs命令的区别与联系?

hadoop fs可以操作各种文件系统,包括HDFS,而hdfs dfs专门用于操作HDFS当通过hadoop fs操作HDFS时,与hdfs dfs命令效果是一样的

3.2 通过文件系统API实现HDFS文件的常见操作

3.2.1 读取HDFS文件到标准输出流

代码示例如下:

public class ReadHdfsFile {public static void main(String[] args) throws IOException {// 获取hdfs文件路径String uri = args[0];// 获取基于hdfs的文件系统Configuration conf = new Configuration();FileSystem fileSystem = FileSystem.get(URI.create(uri), conf);// 创建文件输入流InputStream in = null;try {in = fileSystem.open(new Path(uri));// 使用工具类读取hdfs文件到标准输出流IOUtils.copyBytes(in, System.out, 4096, false);}finally {IOUtils.closeStream(in);}}}

运行程序:注意hdfs的路径需要查看集群的core-site.xml中fs.defaultFS的配置,否则容易出现Call From xxxx to hadoop:8020 failed on connection exception: .ConnectException: Connection refused的异常

hadoop jar original-hadoop-file-operate-1.0-SNAPSHOT.jar com/lucy/hadoop/file/operate/ReadHdfsFile hdfs://hadoop:9000/user/hadoop/output/score_2/part-r-00000

运行结果:

关于FSDataOutputStream

FileSystemopen()方法,返回了一个FSDataOutputStream对象,即为文件创建了一个输入流

FSDataOutputStream类的声明如下:

public class FSDataInputStream extends DataInputStream implements Seekable, PositionedReadable, ByteBufferReadable, HasFileDescriptor, CanSetDropBehind, CanSetReadahead, HasEnhancedByteBufferAccess, CanUnbuffer, StreamCapabilities, ByteBufferPositionedReadable

重点是Seekable接口和PositionedReadable接口

Seekable接口有两个方法:

seek()方法可以设置从文件的哪个位置开始读,使得FSDataInputStream支持随机读

seek()方法与InputStreamskip()方法不同,前者基于文件开头位置的offset偏移处开始读,后者是从当前位置offset偏移处开始读

getPos()可以查询当前位置与文件开头的offset偏移

void seek(long var1) throws IOException;long getPos() throws IOException;

PositionedReadable接口:

read()方法:从指定的position处开始读取至多为length字节的文件,同时从缓冲区buffer的offset偏移处开始存储数据流。如果读到了length字节的数据,或者读至文件末尾,都会自动停止并返回实际读取的字节数

readFully()方法:与read()方法参数相同,但是对文件末尾的处理不同。readFully()读至文件末尾时,仍不够length字节,则会抛出EOFException

read(long position, byte[] buffer, int offset, int length)void readFully(long position, byte[] buffer, int offset, int length) throws IOException;void readFully(long position, byte[] buffer) throws IOException;

3.2.2 将本地文件写入HDFS

代码示例如下:

public class WriteHdfsFile {public static void main(String[] args) throws URISyntaxException, IOException {String hdfsPath = args[0];String localPath = args[1];// 获取文件系统Configuration conf = new Configuration();FileSystem fileSystem = FileSystem.get(new URI(hdfsPath), conf);// 创建本地文件输入流InputStream in = new BufferedInputStream(new FileInputStream(localPath));// 创建hdfs文件输出流// 打印读取进度OutputStream out = fileSystem.create(new Path(hdfsPath), () -> System.out.println("."));IOUtils.copyBytes(in, out, 4096, false);// 关闭文件流IOUtils.closeStream(out);IOUtils.closeStream(in);}}

运行命令

hadoop jar hadoop-file-operate-1.0-SNAPSHOT.jar com/lucy/hadoop/file/operate/WriteHdfsFile hdfs://hadoop:9000/user/hadoop/output/write/local.txt data.txt

运行出错了,后面再说吧 😂

Exception in thread "main" java.io.FileNotFoundException: hdfs://hadoop:9000/user/hadoop/output/write/local.txt (No such file or directory)

关于create()方法:

① 它会默认自动创建文件不存在的父目录;如果想要在父目录不存在的情况下,禁止文件写入,可以先调用exists()方法,判断父目录是否存在

② 第二个参数是Progressable,用于传递回调接口,可以将数据的写入进度通知给应用

③ 其创建的是FSDataOutputStream输出流,它只有getPos()方法,没有设置offset的方法。这样的设计,与HDFS只允许顺序写相照应。

3.2.3 其他常见操作
获取文件的元数据信息:listStatus()方法创建目录:mkdirs()方法,会自动创建父目录及当前目录删除目录/文件:delete()方法,可以通过指定参数,决定是否递归删除目录下的所有文件及子目录。

3.3 HDFS的文件访问权限

通过hdfs dfs -ls path,得到目录信息如下

drwxrwxr-x+ - cms_presto hive0 -04-07 10:40 dm_insight_crowd_upload_df/data_id=104-rwxrwxr-x+ 2 hdfs supergroup 181 -04-09 17:42 dm_insight_crowd_upload_df/0409_094246_08136_x5rhx_a843b61b-45df-498f-b5b8-a6272b5e204c.gz

可以看到HDFS的目录列表与linux中的目录列表格式基本是一致的,只是第二列的数值:linux的hard links

drwxr-xr-x 19 sunrise sunrise4096 Jan 8 14:33 Python-3.7.2-rwxrwxrwx 1 sunrise sunrise 22897802 Dec 24 Python-3.7.2.tgz

通过红框(截图内容的文件名不完整)对HDFS的文件信息进行讲解:

第一列,是文件模式。第一个字符,为d表示这是一个目录,为-表示这是一个文件;后面是owner权限、group权限和其他用户权限,每三位为分隔。第二列,是文件的默认副本数;如果是目录,则无副本的概念,使用-表示;如果是文件,则是文件的副本数,截图中的文件副本数是2第三列,是目录/文件的owner,即所属用户第四列,是目录/文件的group第五列,是文件的size,以字节为单位;目录的size为0,截图中的文件大小为181字节第六七列,是文件的最近一次的修改时间第八列,是目录/文件名

最近也是被业务的读写权限问题搞疯了,找了好几个运维都治标不治本

① 为整个/database目录设置了用户xxx的acl权限,允许xxx读写+执行

② 每次用户新建了表,目录为/database/table1,总是提示没有读写权限

③ 运维A说,给数据库设置了acl,目录下的表时会自动继承这个acl的;运维B说,你还是每次用户新建表以后,用这几条命令去给他们加权限吧

④ 还是我们组的大神(之前做运维,现在是开发为主,运维为辅)告诉了我真正的原因:业务通过presto创建的表,是不会自动继承父目录的acl的

4. 总结

说先是对HDFS的一个认识吧:HDFS适合什么场景(超大文件、流式文件访问、商用硬件)?不适合什么场景(低延迟访问、多用户写入/随机写、小文件存储)?why?

HDFS的两种节点:

① namenode(namespace管理)、datanode(文件存储/检索、block信息上报)

② namenode的容错机制:NFS、辅助namenode(只是负责编辑日志与namespace镜像文件的合并,减轻namenode压力);或者NFS + 辅助namenode

namenode的HA:

① namenode存在单点故障,Hadoop 2提供对HDFS的HA支持:提出了active namenodestandby namenode

active namenode:任意时刻处于active状态,接受客户端操作;standby namenode:拥有足够多的状态信息,可以提供快速的故障转移

③ 通过QJM(群体日志管理器),HDFS专用的日志编辑器,要求至少有3个节点,支持 ( n − 1 ) / 2 (n-1)/2 (n−1)/2的节点故障

Hadoop的文件系统:

① 提供一个抽象的文件系统概念,FileSystem是Hadoop的抽象文件接口

② 基于FileSystem实现了多种文件系统:Local、HDFS、webHDFS、S3等

③ 文件系统的命令:hadoop fs,以及专门针对HDFS的hdfs dfs

④ 通过FileSystem进行简单的HDFS文件操作:读写、创建目录、删除文件/目录、获取元数据信息

hdfs dfs -ls,查看文件系统的相关信息(文件权限、修改时间、副本数等)

HDFS文件的读写:

FSDataInputStream实现了Seekable接口和PositionedReadable接口,从而支持随机读

FSDataOutputStream,只有getPos()方法,不支持随机写

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。