《Hadoop权威指南:大数据的存储与分析》—3.6.3 一致模型
3.6.3 一致模型
文件系统的一致模型(coherency model)描述了文件读/写的数据可见性。HDFS为性能牺牲了一些POSIX 要求,因此一些操作与你期望的可能不同。
新建一个文件之后,它能在文件系统的命名空间中立即可见,如下所示:
Path p = new Path("p");
Fs.create(p);
assertThat(fs.exists(p),is(true));
但是,写入文件的内容并不保证能立即可见,即使数据流已经刷新并存储。所以文件长度显示为0:
Path p = new Path("p");
OutputStream out = fs.create(p);
out.write("content".getBytes("UTF-8"));
out.flush();
assertThat(fs.getFileStatus(p).getLen(),is(0L));
当写入的数据超过一个块后,第一个数据块对新的reader就是可见的。之后的块也不例外。总之,当前正在写入的块对其他reader不可见。
HDFS提供了一种强行将所有缓存刷新到datanode中的手段,即对FSDataOutputStream调用hflush()方法。当hflush ()方法返回成功后,对所有新的reader而言,HDFS能保证文件中到目前为止写入的数据均到达所有datanode的写入管道并且对所有新的reader均可见:
Path p = new Path("p");
FSDataOutputStream out = fs.create(p);
out.write("content".getBytes("UTF-8"));
out.hflush();
assertThat(fs.getFileStatus(p).getLen(), is(((long) "content".length())));
注意,hflush()不保证datanode已经将数据写到磁盘上,仅确保数据在datanode的内存中(因此,如果数据中心断电,数据会丢失)。为确保数据写入到磁盘上,可以用hsync()替代[1]。
hsync()操作类似于POSIX中的fsync()系统调用,该调用提交的是一个文件描述符的缓冲数据。例如,利用标准Java API数据写入本地文件,我们能够在刷新数据流且同步之后看到文件内容:
FileOutputStream out = new FileOutputStream(localFile);
out.write("content".getBytes("UTF-8"));
out.flush(); // flush to operating system
out.getFD().sync(); // sync to disk
assertThat(localFile.length(), is(((long) "content".length())));
在HDFS中关闭文件其实隐含了执行hflush()方法:
Path p = new Path("p");
OutputStream out = fs.create(p);
out.write("content".getBytes("UTF-8"));
out.close();
assertThat(fs.getFileStatus(p).getLen(), is(((long) "content".length())));
对应用设计的重要性
这个一致模型和设计应用程序的具体方法息息相关。如果不调用hflush()或hsync()方法,就要准备好在客户端或系统发生故障时可能会丢失数据块。对很多应用来说,这是不可接受的,所以需要在适当的地方调用hflush()方法,例如在写入一定的记录或字节之后。尽管hflush()操作被设计成尽量减少HDFS负载,但它有许多额外的开销(hsync()的开销更大),所以在数据鲁棒性和吞吐量之间就会有所取舍。怎样权衡与具体的应用相关,通过度量应用程序以不同频率调用hflush()或hsync()时呈现出的性能,最终选择一个合适的调用频率。
- 点赞
- 收藏
- 关注作者
评论(0)