Hadoop官网翻译 FileSystem模型/FileSystem Class

Posted 油纸雨伞

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hadoop官网翻译 FileSystem模型/FileSystem Class相关的知识,希望对你有一定的参考价值。

Path和Path项

Path是一个字符串,代表一个文件,目录或者是一个符号链接。
Path不能包含. /或者一些其他的字符,如果符号不可行,那么文件系统应该报出InvalidPathException

path相关方法

  • valid-path-element
    检查path项是否符合规范
  • valid-path
  • parent
    获取parent项
  • filename
    获取filename项
  • childElements
  • ancestors
  • 处理绝对路径和相对路径

定义文件系统

  • 定义目录
    路径指向文件系统中的目录
    路径要有父目录,或者该目录是/
    子路径不能重复
  • 定义文件
  • 定义符号连接
  • 定义文件大小
    如果是文件的话是它的长度,如果是目录的话返回0
    -userhome
    用户的HomeDirectory
  • 排他性
    一个路径不能指向两个东西
  • 加密区
    加密的本质和机制没有说明

这个模型考虑了除了权限和元数据之外的其他部分的查询和操作。

FileSystem

实现一个文件系统,要关注的就是原子性,一致性,并发性,以及操作反馈等等。FS定义了一些基本操作,不同的文件系统都要实现,只不过实现时也有些许差别。比如说s3很多操作不支持原子性,它没有属性的文件系统,所以list,rename效率比较低,实现也不一样。所以使用过程中需要注意。

抽象的FileSystem类是访问Hadoop文件系统的原始类,对所有的Hadoop支持的文件系统,都存在非抽象子类。
所有的接口路径操作必须支持相对路径,相对于setWorkingDirectory定义的工作目录进行解析。
对于客户端,添加了组件组件PWD的概念,对应客户机实例是唯一的。
所有对于FileSystem的操作都可以返回一个新的FileSystem

可行性功能

可以定义一些保护目录,删除保护目录会抛出异常

非抽象类需要实现以下方法

断言和其他状态访问操作

  • exists
  • isDirectory
  • isFile
  • getFileStatus
    返回状态有关ACL,加密和擦除编码信息的详细信息。
    yarn启动时,缓存所有的都可以访问,如果声明为加密的,可以控制访问。但是有些文件系统,比如s3不支持POSIX访问控制,就需要创建FileStatus时,直接指定为t-rue
  • msync
    同步元数据,客户端/HA集群
    HDFS Observer请求ActiveNamenode获取最新的事务id来支持msync
  • listStatusIterator
  • listStatus
    list路径下所有文件的status,不保证一致性
  • listLocatedStatus
    返回的是FieStatus的子集
    默认实现是使用了listStatus(path),其他的方式可能实现更动态的枚举,比如说获取child entries的子集.
    调用方需要假定,如果迭代过程中,文件发生了变化,可能会执行失败。
  • listFiles(path,recurive)
    创建一个迭代器,访问目录下的文件和目录。最终调用的是listLocatedStatus
  • getFileBlockLocations(FileStatus,s,l)
    需要可以的快速获取包含s,s+l数据block的位置
  • getDefaultBlockSize
    得到文件系统的默认块大小。尽管没有定义最小值,因为它用于作业提交过程中对工作进行分区,但是块大小太小将导致工作负载的分区很差,计算分区时可能导致客户端内存耗尽。
  • getBlockSize(path)

改变状态的接口

  • mkdir
  • create
    有一些约束
    对于非overwrite的文件创建,该文件必须不存在
    任何祖先都不可以是文件

约束就是实现时的判断

可能会失败,比如说readonly FS,block size小于块最小值,副本数超了,配额,重复等问题。返回的结果是FSDataoutputStream
不同实现的说明:
1)一些实现将Create拆分为几个步骤,会导致该操作不是原子的。
2)S3,Swift等对象存储会在outputStrem close时候才真正的改变FS的状态。这和FileSystem不同。会导致即使获取的独占锁也可能不是安全的。

  • createFile
    返回的是FSDataOutputStreamBuilder,不会立即对文件系统更改。在FSdataOutputStreamBuilder上调用build时,验证构造器参数,底层的文件系统上调用create(path p)
  • append
  • appendFile
  • open
    需要预先检查是不是文件,返回的结果是FSDataInputStrem(0,FS.Files[p])
    异常的话会报错(Cannot open filename + src)
  • openfile
    建造者模式返回一个InputStreamBuilder,依赖open方法。
    有些FS实现是懒加载,(比如S3)因为探测比较耗资源。
  • getPathHandle
  • open(PathHandle handle, bufferSize)

pathHandle包含path,mtime,nodeid等信息。

  • delete
    删除文件,目录或者符号连接。
  • (object stores)root directory deletion
    S3定义了不可以直接删除根目录,为了避免删除特定存储和容器本身混淆。
    在删除语义上S3不是原子性的,所以它并没有很好的替代HDFS
  • rename
    需要预先检查:src是否存在,dest不能是src的后继,dest必须要有parent(除非是root),dest不能是root,dest不能存在文件。

rename有许多方法,不翻译了。主要看看实现不一致的部分。
rename到一个不存在的路径
HDFS: false
Local FS: 返回true,隐含parent目录存在。
S3: 只检查dest父节点不能是一个文件,不管祖先节点。
rename在一些文件系统的实现也是非原子性的。

  • concat
    多个block合并成一个文件,目前仅仅hdfs实现了。
  • truncate
    文件截断成目标长度,不能处理writing或者appending的文件。

dfs实现为,client调用truncate,namenode rpc服务调用namesystem的truncate方法,这里面校验之后,获取iip,找到block,然后进行truncate操作。

  • copyFromLocalFile
    从本地拷贝到文件系统,可以指定删除或者覆盖。
    hdfs是递归拷贝的,object store可以利用并行上传来最大化吞吐。

RemoteIterator

remoteiterator和本地的iterator使用相似,只不过是远程的,不支持remove操作。

最终还是通过一个rpc,从namenode中获取批量文件信息。减少rpc调用次数。通过iterator的接口进行访问。

StreamCapabilities

支持通过编程来查询OutputStream,InputStream,FileSystem支持什么能力
比如说:
hflush:flush缓冲区,其他的reader可见
hsync:buffer到磁盘
dropbehnd: 丢弃缓存

EtagSource

FileSystem支持从FileStatus获取Etag标签

和HTTP资源相关,不太关注

Hadoop官网翻译 FileSystem/OutputStream

介绍

OutputStream是一个标准接口,文档介绍它如何在HFDS上实现。
HDFS增加实现了标准接口之外的Syncable和StreamCapabilities

数据写入文件系统

  • 通常写入是通过FileSystem.create,FileSystem.append,FileDataOutputStreamBuilder.build()得到OutputStream。
  • 通过write写入outputStream中,如果close方法调用了。需要其他客户端可见。
  • 和写数据一起,Hadoop outputStream通过Sync接口提供了flush方法,让数据可以对其他的客户端可见。
  • 接口:StreamCapabilities,允许探测Stream的能力

输出流模型

  • 输出流可以被视为存储在客户机中的字节列表,hsync和hrush是操作。让数据传输到其他读者可以看到的地方,并持久化。
  • open可以追踪输出流是否打开。
  • 输出流可以通过一个三元组定位 (path,open,buffer)

刷新数据的可见性

Syncable操作之后,path中的数据需要和buffer一致。hsync和hrush区别点在于持久化的方式不同,而不是可见性的不同。

Stream状态

  • FileSystem.create
    返回一个空的缓存的stream
    Stream = (path,true,[])
  • FileSystem.append
    返回 Stream = (path,true,data(Fs,path)) 默认填充缓冲区

持久化数据

当close时,当前buffer会替换file的内容,进行持久化。
close是幂等的,但是不能重复写。

FSDataOutputStream

OutputStream可以被Syncable,CanSetDropBehind和StreamCapabilities包装。
HDFS的FileSystem实现,DistributedFileSystem,返回了HdfsDataOutputStream.它实现了两个没有被Java显示声明的行为。
1.多个线程可以往同一个OutputStream里面写入,HBase依赖这一项。

咋实现的?

2.OutputStream.flush在文件关闭时禁止写入。
由于write是HDFS的很重要的API,所以write线程安全非常重要。

OutputStream

Java OutputStream允许应用写bytes到目的文件。

  • write(Stream, data)
  • write(Stream,byte[] data,int offset,int len)
  • write(byte[] data)
  • flush
  • close
    close时要释放锁
    close需要阻塞到write数据完成
    close只能一次,后续的close要异常
    有些close非常慢,比如对象存储要在close时上传全部数据。可能阻塞线程很长时间。

close需要保证一致性,持久化,还要保证文件状态是closed。

  • hdfs的实现上,没有保证close的时候已经完成数据持久化了,所以需要先调用sync来持久化数据。

Syncable

目的是保证数据写入到文件系统即可见,有持久。具有hflush和hsync接口。

Syncable除了被OutputStream的子类实现外,还被其他类比如说Sequence.Writer实现。
FSDataOutputStream实现Syncable,仅仅是看它包裹的OutStream是不是实现了Sync接口,如果没有的话,会降级hflush到flush。

hflush

hflush和flush区别?
flush是should,hflush是阻塞确保刷新的。

hflush可以调用hsync。
通常文件系统只提供hsync,那么时间可能更长。
除非WAL,否则不要每一行都hsync.

hsync

hsync提供持久性和可见性.要求存磁盘。

StreamCapabilities

目的是让调用者动态的决定Stream的行为,比如是否支持HSYNC,HFLUSH等,readAhead,unbuffer,readbytebuffer,preadbytebuffer等。

CanSetDropBehind

改变hdfs的策略,用来判断是否丢弃cache

Output Stream 的 持久性,并发性,一致性和可见性

系统行为的几个方面,文件系统模型没有直接设计,但是在生产中可以看到。

持久化

  • write
    可以同步或者异步的持久化数据
  • flush
    flush数据到目的地,没有持久化要求
  • hflush
    确保结束之后,所有读取新流的客户端可以看到,不保证持久性。
  • hsync
    语义和hflush一致,但是要求持久化存储
  • close
    语义和hflush一致,需要关闭流

并发性

  • 多个线程写入同一个文件的结果未定义。

这里面不用锁吗?hbase是如何支持多个线程公用一个流的?

  • 一个读一个写的时候,啥时候可以读取到新数据。
  • DFSOutputStream具有强的线程安全模型。

DFSOutputStrem他所有的操作都是加锁的了。

一致性和可见性

  • 没有要求数据立即可见,除非是使用了fush等操作。
  • create(path,overwrite==true),那么路径会立刻不可见。
  • 文件的元数据应该在flush和sync或者close以后和内容一致。

Hadoop Output Stream 模型的问题

问题点主要在于何时写入和持久化数据,以及何时同步元数据。HDFS和本地文件系统的实现在某些部分不遵从outputStream的设计规范。

HDFS

  • HDFS: hsync只同步最后一个块。
    WAL要求在提交标志刷新之前,前面字节必须被保存。因此用HDFS实现WAL时,要注意如果上次同步之后写入的数据很多,跨越了block边界,只会同步最后一个块。
    如果一个大的写任务要求同步,那么需要定时同步。
  • HDFS: 元数据通常是滞后的,比如说getFileStatus获取的文件长度通常是过时的。
    需要注意的一点是getFileStatus(Fs,path).getLen()==0并不能说明文件是空的。

localFileSystem

localfilesystem是通过file.crc文件来确保块的完整性的。所以,只有完整块才可以hflush。

所以如果不禁用校验和,不能随时hsync。hdfs是通过一个DataBlockScanner周期性校验。

对象存储

对象存储可能一直到close才put输出。
对象存储不能保准outputStream创建后可见。
对象存储和POSIX文件系统也很不一样,对象存储不能保证close之后,数据可以持久的保存。比较有利的是,PUT操作可以保证原子性。

优化建议

1.实现Syncable接口,或者是抛出不支持。
2.元数据更新
3.close持久化数据。

以上是关于Hadoop官网翻译 FileSystem模型/FileSystem Class的主要内容,如果未能解决你的问题,请参考以下文章

Hadoop官网翻译

Hadoop官网翻译(Distcp)

2-Hadoop集群搭建(官网翻译)

Hadoop官网翻译(HDFS-3)

hadoop学习笔记:HDFS文件的读写流程

hadoop FileSystem类和SequenceFile类实例