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的主要内容,如果未能解决你的问题,请参考以下文章