Hadoop FileSystem是否应该关闭?

时间:2019-03-14 17:41:14

标签: java spring-boot hadoop hadoop-2.7.2

我正在构建一个由弹簧启动的服务,该服务使用文件系统API将数据写入Hadoop。一些数据被写入镶木地板文件,大块被缓存在内存中,因此当服务关闭时,可能必须将数百Mb的数据写入Hadoop。

FileSystem默认情况下自动关闭,因此,当服务关闭时,有时FileSystem会在所有编写器都关闭之前关闭,从而导致镶木地板文件损坏。

文件系统fs.automatic.close中有Configuration标志,但是FileSystem实例是从多个线程中使用的,我不知道有什么干净的方法可以在关闭{ {1}}手动。我尝试使用专用的filesysem关闭bean,它使用最大FileSystem来实现Spring SmartLifeCycle,因此它最后被销毁了,但是实际上它没有被销毁,但是最后被通知了shutdown,而其他bean仍在关闭过程中下来。

理想情况下,每个需要phase的对象都将得到一个并负责关闭它。问题是FileSystem返回了一个缓存的实例。有FileSystem.get(conf),但尚不清楚在性能上使用多个FileSystem.newInstance(conf)实例会带来什么后果。另一个问题是-无法将FileSystem实例传递给FileSystem-使用ParquetWritergets one传递给would be returned。有人会认为该行将仅返回分配给该文件的path.getFileSystem(conf)实例,但是会出错-最有可能是同一缓存的实例{{3}},因此关闭它是错误的。

是否有推荐的方法来管理FileSystem的生命周期?如果将FileSystem设置为FileSystem且从未手动关闭过fs.automatic.close,该怎么办?也许spring-boot支持一种干净的方法来在所有其他bean实际上都被销毁(未销毁)之后关闭true

谢谢!

1 个答案:

答案 0 :(得分:1)

您可以使用FileSystem配置(发现here,一些讨论here)来禁用fs.<scheme>.impl.disable.cache缓存,其中<scheme>将是{ {1}}(假设您正在使用HDFS)。这将迫使hdfs在调用ParquetWriter时创建一个新的FileSystem实例。该配置没有充分的理由证明-虽然在Hadoop本身内部的单元测试中广泛使用了此配置,但在生产系统中使用它可能非常危险。为了回答有关性能的问题,假设您正在使用HDFS,则每个path.getFileSystem(conf)实例都会创建一个与HDFS NameNode的单独TCP连接。应用程序和库代码通常是在假设FileSystempath.getFileSystem(conf)之类的调用既便宜又轻巧的前提下编写的,因此经常使用它们。在生产系统中,我已经看到客户端系统DDoS一个NameNode服务器,因为它禁用了缓存。您不仅需要仔细管理{em>您的代码创建的FileSystem.get(conf)实例的生命周期,而且还需要仔细管理由您使用的库创建的实例的生命周期。我通常会建议不要这样做。

听起来问题似乎真的来自于Spring使用的JVM shutdown hooks与Hadoop使用的错误交互,而Hadoop是用于自动关闭FileSystem实例的机制。 Hadoop包含自己的ShutdownHookManager,用于在关机期间对事件进行排序; FileSystem关机是有目的地进行的,以便可以首先完成其他关机钩子(例如,在MapReduce任务之后进行清理)。但是,Hadoop的FileSystem仅知道已向其注册的关闭任务,因此它不会知道Spring的生命周期管理。听起来确实像利用Spring的关闭顺序和利用ShutdownHookManager可能最适合您的应用程序;我没有Spring的经验,所以在这方面我无法为您提供帮助。您还可以使用非常高的优先级向Hadoop的fs.automatic.close=false注册Spring的整个关闭序列,以确保Spring的关闭序列在关闭队列中排在首位。

要专门回答此部分:

是否存在建议的管理文件系统生命周期的方法?

推荐的方法通常是不对其进行管理,而由系统为您完成。每当您尝试自己进行管理时,都会碰到龙,因此请谨慎操作。