我正在构建一个spring启动的服务,它使用文件系统api将数据写入hadoop。一些数据被写入parquet文件,大块数据被缓存在内存中,因此当服务关闭时,可能需要将几百mb的数据写入hadoop。 FileSystem
默认情况下自动关闭,因此当服务关闭时,有时 FileSystem
在关闭所有写入程序之前关闭,从而导致损坏的Parquet文件。
有 fs.automatic.close
文件系统中的标志 Configuration
,但是 FileSystem
示例是从多个线程中使用的,我不知道有什么干净的方法可以在关闭前等待它们全部完成 FileSystem
手动。我尝试使用专用的filesysem关闭bean来实现spring SmartLifeCycle
与max phase
所以它是最后销毁的,但实际上它不是最后销毁的,而是最后通知关闭的,而其他bean仍在关闭过程中。
理想情况下,每个需要 FileSystem
会得到一个并负责关闭它。问题是 FileSystem.get(conf)
返回缓存示例。有 FileSystem.newInstance(conf)
,但目前尚不清楚使用多个 FileSystem
示例性能方面。还有另一个问题-没有办法通过 FileSystem
示例到 ParquetWriter
-它得到一个使用 path.getFileSystem(conf)
. 有人会认为这条线会返回 FileSystem
示例只分配给该文件,但其中一个可能是错误的-很可能返回相同的缓存示例,因此关闭它将是错误的。
有没有一种推荐的方法来管理 FileSystem
? 如果 FileSystem
创建时使用 fs.automatic.close
设置为 true
从来没有手动关闭过?也许Spring Boot支持一种干净的关闭方式 FileSystem
在所有其他豆子都被销毁(没有被销毁)之后?
谢谢!
1条答案
按热度按时间kmb7vmvb1#
您可以禁用
FileSystem
使用缓存fs.<scheme>.impl.disable.cache
配置(在这里找到,这里有一些讨论),在哪里<scheme>
对你来说hdfs
(假设您使用的是hdfs)。这将迫使ParquetWriter
创建新的FileSystem
调用时的示例path.getFileSystem(conf)
. 这种配置没有文档化是有充分理由的——虽然在hadoop本身的单元测试中广泛使用,但在生产系统中使用它可能非常危险。为了回答有关性能的问题,假设您使用的是hdfs,则FileSystem
示例将创建到hdfs namenode的单独tcp连接。应用程序和库代码的编写通常假定path.getFileSystem(conf)
以及FileSystem.get(conf)
它们既便宜又轻,所以经常使用。在一个生产系统中,我看到一个客户机系统ddos一个namenode服务器,因为它禁用了缓存。您需要谨慎地管理FileSystem
您的代码创建的示例,以及您使用的库创建的示例。我一般不建议这样做。听起来这个问题实际上是来自spring使用的jvm关闭钩子和hadoop使用的那些钩子之间的错误交互,hadoop是用来自动关闭的机制
FileSystem
示例。hadoop包含自己的shutdownhookmanager,用于在关闭期间对事件进行排序;FileSystem
shutdown故意放在末尾,这样其他shutdown钩子(例如mapreduce任务之后的清理)可以首先完成。但是,hadoop的ShutdownHookManager
只知道已注册到它的关闭任务,因此它不会知道spring的生命周期管理。听起来确实像是利用spring的关闭序列fs.automatic.close=false
可能适合您的申请;我没有Spring的经验,所以在这方面我帮不了你。您还可以将spring的整个关闭序列注册到hadoop的ShutdownHookManager
,使用非常高的优先级来确保spring的关闭序列位于关闭队列的第一位。具体回答这一部分:
有没有推荐的方法来管理文件系统的生命周期?
建议的方法通常是不管理它,让系统为您做。每当你试图自己管理它的时候,就会有龙,所以要小心行事。