如果我们可以在hadoop中更改数据块大小,请告诉我如何做。更改块大小是否有利?如果是,请告诉我原因和方法?如果没有,请告诉我原因和方法?
edqdpe6u1#
关于这个主题似乎有很多困惑,也有很多错误的建议。为了消除混淆,思考hdfs是如何实际实现的是有帮助的:hdfs是对基于磁盘的分布式文件系统的抽象。所以“block”和“blocksize”这两个词的含义与一般理解的不同。对于hdfs,“文件”只是块的集合,每个“块”作为回报存储为datanode上的实际文件。事实上,根据复制因子,同一个文件存储在多个数据节点上。这些单独文件的块大小及其其他性能特征反过来又取决于各个数据节点的底层文件系统。hdfs文件和datanodes上的各个文件之间的Map由namenode维护。但是namenode不需要特定的blocksize,它只存储在hdfs文件创建过程中创建的Map,hdfs文件通常根据默认值进行拆分 dfs.blocksize (但可以单独覆盖)。这意味着,例如,如果您有一个1 mb的文件,其复制为3,块大小为64 mb,则不会丢失63 mb*3=189 mb,因为在物理上,只有三个1 mb的文件以底层文件系统(例如ext4)的标准块大小存储。所以问题就变成了 dfs.blocksize 是否有必要改变它。首先让我列出一个更大的区块的方面:namenode压力:如前所述,namenode必须维护dfs文件及其块到datanodes上的物理文件之间的Map。因此,块/文件越少,内存压力和通信开销就越小磁盘吞吐量:在hadoop中,文件由单个进程写入,这通常会导致数据按顺序写入磁盘。这对于旋转磁盘尤其有利,因为它避免了昂贵的搜索。如果数据是这样写的,那么它也可以这样读,因此它成为读写的一个优势。事实上,这种与本地数据相结合的优化(即在数据所在的位置进行处理)是mapreduce的主要思想之一。网络吞吐量:数据局部性是更重要的优化,但在分布式系统中,这并不总是能够实现的,因此有时需要在节点之间复制数据。通常一个文件(dfs块)通过一个持久tcp连接传输,当传输大文件时,该连接可以达到更高的吞吐量。更大的默认拆分:尽管splitsize可以在作业级别配置,但大多数人不考虑这一点,只使用默认值,通常是blocksize。但是,如果splitsize太小,那么最终可能会有太多的Map器,而这些Map器没有太多的工作要做,这反过来又会导致更小的输出文件、不必要的开销和许多占用的容器,这些都会导致其他工作的匮乏。这对reduce阶段也有不利影响,因为结果必须从所有Map器获取。当然,理想的分割大小很大程度上取决于你要做的工作类型。但在必要时,您始终可以设置较低的splitsize,而当您设置的splitsize高于blocksize时,您可能会丢失一些数据局部性。后一个方面的问题比人们想象的要少,因为hdfs中的块放置规则是:第一个块写在创建文件的进程运行的datanode上,第二个块写在同一机架的另一个节点上,第三个块写在另一机架的一个节点上。因此,通常可以在单个数据节点上找到文件的每个块的一个副本,因此即使一个Map程序正在读取多个块,仍然可以实现数据局部性,因为splitsize是块大小的倍数。在这种情况下,mapred框架只能选择一个节点而不是通常的三个节点来实现数据的局部性,因此效果是不容否认的。但最终,对于更大的块大小来说,这一点可能是最薄弱的,因为如果需要,可以单独设置splitsize。但也必须有一个更小的块大小的论点,否则我们应该把它设置为无穷大…并行性/分布性:如果您的输入数据仅仅位于几个节点上,即使是一个大的集群也无助于实现并行处理,至少如果您希望维护一些数据局部性的话。作为一个规则,我会说一个好的blocksize应该与您也可以接受的默认工作负载的splitsize相匹配。容错性和延迟:如果网络连接中断,则重新传输较小文件的干扰较小。tcp吞吐量可能很重要,但单个连接也不应该花费很长时间。这些因素之间的权重取决于您的数据类型、集群、工作负载等,但一般来说,对于典型用例,默认块大小128MB已经有点低了。512MB甚至1GB可能值得考虑。但在深入研究之前,应该先检查输入文件的大小。如果您的大多数文件都很小,甚至没有达到最大默认块大小,那么您的块大小基本上总是文件大小,增加默认块大小没有任何帮助。有一些解决方法,比如使用输入组合器来避免产生太多的Map器,但最终需要确保输入文件足够大以利用大的块大小。如果你的文件已经很小了,不要让块的大小变小,从而使问题更加复杂。
dfs.blocksize
l5tcr1uw2#
这取决于输入数据。Map器的数量与输入拆分成正比,后者取决于dfs块大小。如果您想最大化一个非常大的输入文件的吞吐量,使用非常大的块 (128mb甚至256mb)是最好的。如果一个作业有超过1tb的输入,请考虑将输入数据集的块大小增加到256m甚至512m,这样任务的数量就会更小。对于较小的文件,使用较小的块大小更好。看看这篇文章如果有小文件并且小于最小dfs块大小,则可以使用har或sequencefiles等替代方法。看看这个cloudera博客
clj7thdc3#
您可以随时更改块大小,除非 dfs.blocksize 参数在hdfs-site.xml中定义为final。更改块大小跑步时 hadoop fs 可以运行的命令 hadoop fs -Ddfs.blocksize=67108864 -put <local_file> <hdfs_path> . 此命令将以64mb块大小保存文件跑步时 hadoop jar 命令- hadoop jar <jar_file> <class> -Ddfs.blocksize=<desired_block_size> <other_args> . reducer将在hdfs中存储输出时使用定义的块大小作为map reduce程序的一部分,可以使用job.set并设置值更改块大小的标准:对于未压缩的文件,通常128MB的内存可以正常工作您可以考虑减少压缩文件的块大小。如果压缩率太高,则具有更大的块大小可能会减慢处理速度。如果压缩编解码器是不可拆分的,这将加剧问题。只要文件大小大于块大小,就不需要更改块大小。如果要处理数据的Map器数量非常多,可以通过增加拆分大小来减少Map器的数量。例如,如果有1tb的数据块大小为128 mb,则默认情况下需要8000个Map器。您可以考虑将分割大小更改为512MB甚至1GB,而不是更改块大小,这样处理数据所需的Map器数量就会少得多。我已经在性能调整播放列表的第2和第3部分中介绍了大部分内容。
hadoop fs
hadoop fs -Ddfs.blocksize=67108864 -put <local_file> <hdfs_path>
hadoop jar
hadoop jar <jar_file> <class> -Ddfs.blocksize=<desired_block_size> <other_args>
3条答案
按热度按时间edqdpe6u1#
关于这个主题似乎有很多困惑,也有很多错误的建议。为了消除混淆,思考hdfs是如何实际实现的是有帮助的:
hdfs是对基于磁盘的分布式文件系统的抽象。所以“block”和“blocksize”这两个词的含义与一般理解的不同。对于hdfs,“文件”只是块的集合,每个“块”作为回报存储为datanode上的实际文件。事实上,根据复制因子,同一个文件存储在多个数据节点上。这些单独文件的块大小及其其他性能特征反过来又取决于各个数据节点的底层文件系统。
hdfs文件和datanodes上的各个文件之间的Map由namenode维护。但是namenode不需要特定的blocksize,它只存储在hdfs文件创建过程中创建的Map,hdfs文件通常根据默认值进行拆分
dfs.blocksize
(但可以单独覆盖)。这意味着,例如,如果您有一个1 mb的文件,其复制为3,块大小为64 mb,则不会丢失63 mb*3=189 mb,因为在物理上,只有三个1 mb的文件以底层文件系统(例如ext4)的标准块大小存储。
所以问题就变成了
dfs.blocksize
是否有必要改变它。首先让我列出一个更大的区块的方面:namenode压力:如前所述,namenode必须维护dfs文件及其块到datanodes上的物理文件之间的Map。因此,块/文件越少,内存压力和通信开销就越小
磁盘吞吐量:在hadoop中,文件由单个进程写入,这通常会导致数据按顺序写入磁盘。这对于旋转磁盘尤其有利,因为它避免了昂贵的搜索。如果数据是这样写的,那么它也可以这样读,因此它成为读写的一个优势。事实上,这种与本地数据相结合的优化(即在数据所在的位置进行处理)是mapreduce的主要思想之一。
网络吞吐量:数据局部性是更重要的优化,但在分布式系统中,这并不总是能够实现的,因此有时需要在节点之间复制数据。通常一个文件(dfs块)通过一个持久tcp连接传输,当传输大文件时,该连接可以达到更高的吞吐量。
更大的默认拆分:尽管splitsize可以在作业级别配置,但大多数人不考虑这一点,只使用默认值,通常是blocksize。但是,如果splitsize太小,那么最终可能会有太多的Map器,而这些Map器没有太多的工作要做,这反过来又会导致更小的输出文件、不必要的开销和许多占用的容器,这些都会导致其他工作的匮乏。这对reduce阶段也有不利影响,因为结果必须从所有Map器获取。
当然,理想的分割大小很大程度上取决于你要做的工作类型。但在必要时,您始终可以设置较低的splitsize,而当您设置的splitsize高于blocksize时,您可能会丢失一些数据局部性。
后一个方面的问题比人们想象的要少,因为hdfs中的块放置规则是:第一个块写在创建文件的进程运行的datanode上,第二个块写在同一机架的另一个节点上,第三个块写在另一机架的一个节点上。因此,通常可以在单个数据节点上找到文件的每个块的一个副本,因此即使一个Map程序正在读取多个块,仍然可以实现数据局部性,因为splitsize是块大小的倍数。在这种情况下,mapred框架只能选择一个节点而不是通常的三个节点来实现数据的局部性,因此效果是不容否认的。
但最终,对于更大的块大小来说,这一点可能是最薄弱的,因为如果需要,可以单独设置splitsize。
但也必须有一个更小的块大小的论点,否则我们应该把它设置为无穷大…
并行性/分布性:如果您的输入数据仅仅位于几个节点上,即使是一个大的集群也无助于实现并行处理,至少如果您希望维护一些数据局部性的话。作为一个规则,我会说一个好的blocksize应该与您也可以接受的默认工作负载的splitsize相匹配。
容错性和延迟:如果网络连接中断,则重新传输较小文件的干扰较小。tcp吞吐量可能很重要,但单个连接也不应该花费很长时间。
这些因素之间的权重取决于您的数据类型、集群、工作负载等,但一般来说,对于典型用例,默认块大小128MB已经有点低了。512MB甚至1GB可能值得考虑。
但在深入研究之前,应该先检查输入文件的大小。如果您的大多数文件都很小,甚至没有达到最大默认块大小,那么您的块大小基本上总是文件大小,增加默认块大小没有任何帮助。有一些解决方法,比如使用输入组合器来避免产生太多的Map器,但最终需要确保输入文件足够大以利用大的块大小。
如果你的文件已经很小了,不要让块的大小变小,从而使问题更加复杂。
l5tcr1uw2#
这取决于输入数据。Map器的数量与输入拆分成正比,后者取决于dfs块大小。
如果您想最大化一个非常大的输入文件的吞吐量,使用非常大的块 (128mb甚至256mb)是最好的。
如果一个作业有超过1tb的输入,请考虑将输入数据集的块大小增加到256m甚至512m,这样任务的数量就会更小。
对于较小的文件,使用较小的块大小更好。
看看这篇文章
如果有小文件并且小于最小dfs块大小,则可以使用har或sequencefiles等替代方法。
看看这个cloudera博客
clj7thdc3#
您可以随时更改块大小,除非
dfs.blocksize
参数在hdfs-site.xml中定义为final。更改块大小
跑步时
hadoop fs
可以运行的命令hadoop fs -Ddfs.blocksize=67108864 -put <local_file> <hdfs_path>
. 此命令将以64mb块大小保存文件跑步时
hadoop jar
命令-hadoop jar <jar_file> <class> -Ddfs.blocksize=<desired_block_size> <other_args>
. reducer将在hdfs中存储输出时使用定义的块大小作为map reduce程序的一部分,可以使用job.set并设置值
更改块大小的标准:
对于未压缩的文件,通常128MB的内存可以正常工作
您可以考虑减少压缩文件的块大小。如果压缩率太高,则具有更大的块大小可能会减慢处理速度。如果压缩编解码器是不可拆分的,这将加剧问题。
只要文件大小大于块大小,就不需要更改块大小。如果要处理数据的Map器数量非常多,可以通过增加拆分大小来减少Map器的数量。例如,如果有1tb的数据块大小为128 mb,则默认情况下需要8000个Map器。您可以考虑将分割大小更改为512MB甚至1GB,而不是更改块大小,这样处理数据所需的Map器数量就会少得多。
我已经在性能调整播放列表的第2和第3部分中介绍了大部分内容。