文件系统
Flink通过org.apache.flink.core.fs.FileSystem
类有自己的文件系统抽象。这种抽象提供了一组通用的 算子操作,并且在各种类型的文件系统实现中提供了最小的保证。
在FileSystem
可用 算子操作的设置是非常有限的,为了支持多种文件系统。例如,不支持附加或更改现有文件。
文件系统是由识别的文件系统格式,如file://
,hdfs://
等。
实现
Flink使用以下文件系统方案直接实现文件系统:
file
,表示机器的本地文件系统。其他文件系统类型由桥接到Apache Hadoop支持的文件系统套件的实现访问。以下是不完整的示例列表:hdfs
:Hadoop分布式文件系统s3
,s3n
和s3a
:亚马逊S3文件系统gcs
:Google云端存储maprfs
:MapR分布式文件系统- …如果在类路径中找到Hadoop文件系统类并找到有效的Hadoop配置,Flink将透明地加载Hadoop的文件系统。默认情况下,它在类路径中查找Hadoop配置。或者,可以通过配置条目指定自定义位置
fs.hdfs.hadoopconf
。
坚持保证
这些FileSystem
及其FsDataOutputStream
实例用于持久存储数据,既用于应用程序的结果,也用于容错和恢复。因此,必须明确定义这些流的持久性语义。
持久性保证的定义
如果满足两个要求,则写入输出流的数据被认为是持久的:
可见性要求:必须保证能够访问该文件的所有其他进程,计算机,虚拟机,容器等在给定绝对文件路径时始终看到数据。此要求类似于POSIX定义的close-to-open语义,但仅限于文件本身(通过其绝对路径)。
持久性要求:必须满足文件系统的特定持久性/持久性要求。这些特定于特定文件系统。例如,{@link LocalFileSystem}不为硬件和 算子操作系统的崩溃提供任何持久性保证,而复制的分布式文件系统(如HDFS)通常在出现n个并发节点故障时保证持久性,其中n是复制因子。
不需要更新文件的父目录(以便在列出目录内容时显示文件),以使文件流中的数据被认为是持久的。对于目录内容的更新最终只是一致的文件系统来说,这种放松很重要。
在FSDataOutputStream
必须保证数据的持久性,一旦调用写入的字节FSDataOutputStream.close()
回报。
例子
- 对于容错的分布式文件系统,一旦数据被文件系统接收和确认,数据就被认为是持久的,通常是通过复制到法定数量的机器(持久性要求)。此外,绝对文件路径必须对可能访问该文件的所有其他计算机可见(可见性要求)。
数据是否已达到存储节点上的非易失性存储取决于特定文件系统的特定保证。
对文件的父目录的元数据更新不需要达到一致状态。允许某些机器在列出父目录的内容时看到该文件而其他机器没有,只要在所有节点上都可以通过其绝对路径访问该文件。
- 一个本地文件系统必须支持POSIX 贴近开放语义。由于本地文件系统没有任何容错保证,因此不存在进一步的要求。
以上特别暗示,当从本地文件系统的角度考虑持久性时,数据可能仍然在OS高速缓存中。导致 算子操作系统缓存丢失数据的崩溃对本地计算机来说是致命的,并且不受Flink定义的本地文件系统保证的影响。
这意味着仅保证可以从本地计算机的故障中恢复仅写入本地文件系统的计算结果,检查点和保存点,从而使本地文件系统不适合生产设置。
更新文件内容
许多文件系统根本不支持覆盖现有文件的内容,或者在这种情况下不支持更新内容的一致可见性。因此,Flink的FileSystem不支持附加到现有文件,也不支持在输出流中搜索,以便可以在同一文件中更改以前写入的数据。
覆盖文件
通常可以覆盖文件。通过删除文件并创建新文件来覆盖文件。但是,某些文件系统无法使有权访问该文件的所有各方同步显示该更改。例如,Amazon S3仅保证文件替换可见性的最终一致性:某些计算机可能会看到旧文件,某些计算机可能会看到新文件。
为了避免这些一致性问题,Flink中的故障/恢复机制的实现严格避免多次写入同一文件路径。
线程安全
实现FileSystem
必须是线程安全的:相同的实例FileSystem
经常在Flink中的多个线程之间共享,并且必须能够同时创建输入/输出流和列表文件元数据。
这些FSDataOutputStream
和FSDataOutputStream
实现严格地说不是线程安全的。在读取或写入 算子操作之间的线程之间也不应传递流的实例,因为不能保证跨线程的 算子操作的可见性(许多 算子操作不会创建内存防护)。