HDFS对小文件的性能表现

7
我是一个Hadoop的新手,最近我试图在hdfs/hadoop上处理(只读)许多小文件。平均文件大小约为1kb,文件数量超过10M。由于一些限制,程序必须用C++编写。
这只是性能评估,所以我只用了5台机器作为数据节点。每个数据节点有5个数据磁盘。
我编写了一个小的C++项目,直接从硬盘(而不是从HDFS)读取文件,以建立性能基线。该程序将为每个磁盘创建4个读取线程。性能结果为每个磁盘约为14MB/s。总吞吐量约为14MB/s * 5 * 5 = 350MB/s(14MB/s * 5个磁盘 * 5个机器)。
然而,当该程序(仍使用C++,动态链接到libhdfs.so,创建4*5*5=100个线程)从hdfs集群中读取文件时,吞吐量仅约为55MB/s。
如果触发此编程映射(hadoop streamming,5个作业,每个作业有20个线程,线程总数仍为100),则吞吐量会降至约45MB/s。(我猜它会被某些簿记过程拖慢)
我想知道HDFS可以提供什么合理的性能。正如您所看到的,与本机代码相比,数据吞吐量仅约为1/7。这是我的配置问题吗?还是HDFS的限制?或Java的限制?对于我的场景,最好的方法是什么?序列文件有帮助(很多)吗?与本机IO读取相比,我们可以期望什么合理的吞吐量?
以下是我的一些配置:
- NameNode堆大小32G。 - Job/Task节点堆大小8G。 - NameNode处理程序计数:128 - DataNode处理程序计数:8 - DataNode最大传输线程数:4096 - 1GBps以太网。
谢谢。

补充说明:该程序从标准输入(stdin)读取一个文件列表,其中包含数百万个文件路径。 - avhacker
我总是忘记“为什么”和“如何”,但尝试使您的输入文件至少与块大小(默认为64 MB)一样大,然后重新运行您的分析。您组合文件的方式取决于它们的格式;例如,如果它们只是文本,则可以将它们连接起来。 - Matt D
我知道将文件合并成更大的文件可以显着提高性能,但这不会是我们的首选。 顺便说一下,直接从磁盘读取文件也会有很大的改进。 我真的很想知道HDFS相对于本地访问可以提供什么合理的吞吐量。 1/7似乎不太好。 - avhacker
3个回答

9

HDFS并不适合存储大量小文件。

每个新文件读取时,客户端必须与Namenode通信,获取文件块的位置信息,然后从Datanode流式传输数据。

在最理想情况下,客户端只需要执行一次此操作,就能找到具有数据的机器,并直接从磁盘中读取,这将非常快速,相当于直接从磁盘读取。

如果不是具有数据的机器,则必须通过网络流式传输数据。此时受网络I/O速度限制,速度会比直接从磁盘读取略慢。

然而,您甚至可能遇到更糟糕的情况-与Namenode交互的开销变得很大。使用1KB文件时,您正在交换的元数据和实际数据一样多。客户端必须分别进行两次网络交换才能获取每个文件的数据。此外,由于Namenode被所有这些不同的线程占用,因此它可能成为瓶颈。

所以回答您的问题:如果您使用HDFS来存储它不适合存储的内容,那么它将变慢。合并您的小文件,并使用MapReduce获取数据本地性,您将获得更好的性能。实际上,由于您能够更好地利用顺序磁盘读取,我不会惊讶,从一个大的HDFS文件中读取会比从许多小的本地文件中读取更快。


我正在考虑合并小文件。但通常我不需要读取它们的全部内容。例如,我有100M的文件,但我只需要读取其中30M的文件。这种情况下,序列文件是否适用?由于我需要将数据加载到C++程序中,我将使用Hadoop流处理。在这种情况下,序列文件是否可行?我有更好的选择吗?顺便说一下,我的场景是我已经有了100M的文件,并且每天会添加数百个文件,每天删除少于100个文件,而且没有文件会被修改。 - avhacker
我同意Joe的观点,应该将小文件合并成大文件。看起来我应该找出如何使用Hadoop Streaming来完成这个任务,并确定Sequence File或HAR是否能够满足我的要求。 - avhacker

3

除了Joe所说的之外,HDFS和其他文件系统的另一个不同之处在于,它通过将数据存储在较大的块中(通常为64M或128M),尽可能地减少磁盘I/O,而传统文件系统的块大小是以KB为单位的。因此,他们总是说HDFS擅长处理少量大文件,而不是大量小文件。这背后的原因是,虽然近年来像CPU、内存等组件方面已经取得了重大进展,但磁盘I/O仍然是我们发展得不够多的领域。这就是为什么有如此巨大的块(不像传统文件系统)并尽可能地减少磁盘使用率的目的。

此外,如果块大小太小,我们将拥有更多的块。这意味着有更多的元数据。这可能会降低性能,因为需要加载更多的信息到内存中。在HDFS中,每个块被认为是一个对象,与之关联的元数据约为200B。如果您有许多小块,它将增加元数据,并可能导致内存问题。

在Cloudera的博客部分有一篇非常好的文章,讨论了同样的问题。你可以访问这里


抱歉打扰了,不过请问一下Hadoop能否用于为一个访问量很大的网站提供图片服务?将许多小文件合并成一个大文件(序列文件)会使访问速度变慢吗?非常感谢您的帮助。 - qualebs
欢迎@qualebs。这个想法似乎不太可行。Hadoop本身(特别是HDFS),像其他文件系统一样,不适合需要实时访问存储数据的用例,比如一个网站,在这个网站上,用户会发布查询并期望即时响应。 - Tariq
我有哪些替代方案可以以分布式方式存储这些小文件,即无限空间?并且还能快速访问? - qualebs

1
让我们尝试了解我们的限制并看看何时会达到极限。
a) 我们需要namenode提供有关文件位置的信息。我可以假设每秒大约有数千个文件。更多信息在此处https://issues.apache.org/jira/browse/HADOOP-2149。假设这个数字为10000K,我们应该能够获取每秒1K文件的10 MB信息。(不知何故你得到了更多...)。可能
b) HDFS的开销。这种开销主要是延迟而不是吞吐量。可以调整HDFS以同时服务很多文件。HBase正在这样做,我们可以从HBase调整指南中获取设置。问题在于您需要多少Datanodes
c) 您的局域网。您从网络中传输数据,因此可能会达到1GB以太网吞吐量限制。(我认为这就是您所拥有的)
我也同意Joe的观点-HDFS不适用于此场景,您应该使用其他技术(例如HBase,如果您喜欢Hadoop堆栈)或将文件压缩在一起-例如成为序列文件。

关于从HDFS读取大文件的问题 - 运行DFSIO基准测试,它将成为您的首选。
同时,单个主机上的SSD也可以是一个完美的解决方案。


我之所以可以获得更好的namenode性能,是因为我使用了更好的硬件。戴尔R620,2个E5-2650 CPU(包括超线程共32个核心),128GB RAM。 - avhacker
我认为我没有达到1GB以太网的限制,因为总吞吐量是由5台机器实现的。这5个数据节点通过1GB以太网交换机连接。由于交换机和以太网适配器都是全双工的,所以对于5台机器,我应该至少获得2.5GB的带宽。 - avhacker
它将增加数据节点可以处理的并发性。同时 - 它不会减少每个文件读取的开销。同时 - 我会认真考虑例如HBASE或其他适合小数据块的解决方案。 - David Gruzman
将文件压缩成序列文件会使访问它们变慢吗?比如说,如果您使用Hadoop存储Web应用程序的图像,会变得更慢吗? - qualebs
它会降低随机访问速度。但如果您需要随机访问 - HDFS 不是最佳解决方案... - David Gruzman
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接