在为我当前的一个项目构建基础设施时,我遇到了替换现有hdfs文件的问题。更确切地说,我想做以下几点:
我们有一些机器(日志服务器)不断生成日志。我们有一个专门的机器(日志预处理器),负责从日志服务器接收日志块(每个块长约30分钟,大小约500-800 mb),对它们进行预处理并上传到我们hadoop集群的hdfs。
预处理分3步进行:
对于每个logserver:filter(并行)接收到的日志块(输出文件约为60-80mb)
合并(合并排序)步骤1中的所有输出文件并进行一些小的筛选(另外,30分钟的文件合并为1小时的文件)
使用外部数据库的当前Map,处理步骤#2中的文件以获得最终的日志文件,并将此文件放入hdfs。
最终的日志文件将用作在hadoop集群上运行的几个periodoc hadoop应用程序的输入。在hdfs中,日志文件存储如下:
hdfs:/spool/.../logs/YYYY-MM-DD.HH.MM.log
问题描述:
步骤3中使用的Map会随着时间的推移而变化,我们需要通过重新计算步骤3并用新的hdfs文件替换旧的hdfs文件来反映这些变化。至少在过去12小时内,以一定的周期(例如每10-15分钟)执行此更新。请注意,如果Map已更改,则在同一输入文件上应用步骤3的结果可能会显著不同(它将不仅仅是先前结果的超集/子集)。所以我们需要覆盖hdfs中的现有文件。
但是,我们不能只执行hadoop fs-rm,然后执行hadoop fs-copytolal,因为如果某个hadoop应用程序正在使用临时删除的文件,那么该应用程序可能会失败。我使用的解决方案是——在旧文件旁边放一个新文件,这些文件有相同的名称,但后缀不同,表示文件的版本。现在布局如下:
hdfs:/spool/.../logs/2012-09-26.09.00.log.v1
hdfs:/spool/.../logs/2012-09-26.09.00.log.v2
hdfs:/spool/.../logs/2012-09-26.09.00.log.v3
hdfs:/spool/.../logs/2012-09-26.10.00.log.v1
hdfs:/spool/.../logs/2012-09-26.10.00.log.v2
任何hadoop应用程序在启动(安装)期间都会选择具有最新版本的文件并使用它们。因此,即使正在进行某些更新,应用程序也不会遇到任何问题,因为没有删除任何输入文件。
问题:
您知道一些更简单的方法来解决这个问题,而不使用这种复杂/难看的文件版本控制吗?
一些应用程序可能开始使用当前正在上载但尚未上载的hdfs文件(应用程序在hdfs中看到此文件,但不知道是否一致)。对于gzip文件,这可能会导致Map程序失败。你能告诉我怎么处理这个问题吗?我知道对于本地文件系统,我可以执行以下操作:
cp infile/finaldir/outfile.tmp和mv/finaldir/output.tmp/finaldir/output
这是因为mv是一个原子操作,但是我不确定hdfs是这样的。如果hdfs在传统的本地文件系统中有mv这样的原子操作,您能给出建议吗?
提前谢谢!
1条答案
按热度按时间dy1byipe1#
在我看来,文件重命名的方法绝对是好的。
高达1.x的hdfs缺少原子重命名(它们是脏的更新iirc),但是这个操作通常被认为是“类似原子的”,并且从来没有给你在这里想到的特定场景带来问题。因为源文件已经创建并关闭,所以您可以依赖它而不用担心部分状态。
HDFS2.x以后的版本支持正确的原子重命名(通过一个新的api调用),它已经取代了早期版本的脏版本。如果使用filecontext API,这也是重命名的默认行为。