Hadoop官网翻译 【FileSystem/OutputStream】

文章详细介绍了HDFS中OutputStream的实现,包括如何通过Syncable接口保证数据可见性和持久化,以及flush、hflush和hsync的区别。HDFS的DFSOutputStream支持多线程写入,但文件系统模型在某些方面与标准OutputStream规范不符,如数据的可见性和持久化时机。同时,文章提到了对象存储和本地文件系统的特性差异,并给出了优化建议。
摘要由CSDN通过智能技术生成

介绍

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持久化数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值