小文件BLOCK占用

  • 小于block大小的小文件不会占用整个HDFS block空间,但是较多的小文件会占用更多的NAMENODE的内存(记录了文件的位置等信息);再者,在文件处理时,可能会有较大的网络开销。
  • 一个常被问到的一个问题是: 如果一个HDFS上的文件大小(file size) 小于块大小(block size) ,那么HDFS会实际占用Linux file system的多大空间?答案是实际的文件大小,而非一个块的大小。
  • 可以使用命令来查看文件的实际占用情况,如 hadoop dfs -stat、hadoop fsck
  • 如果hdfs占用Linux file system的磁盘空间按实际文件大小算,那么这个”块大小“有必要存在吗?其实块大小还是必要的,一个显而易见的作用就是当文件通过append操作不断增长的过程中,可以通过来block size决定何时split文件。以下是Hadoop Community的专家给我的回复: “The block size is a meta attribute. If you append to the file later, it still needs to know when to split further - so it keeps that value as a mere metadata it can use to advise itself on write boundaries.”

 HDFS设置BLOCK的目的

  • 减少硬盘寻道时间(disk seek time)。HDFS设计前提是支持大容量的流式数据操作,所以即使是一般的数据读写操作,涉及到的数据量都是比较大的。假如数据块设置过少,那需要读取的数据块就比较多,由于数据块在硬盘上非连续存储,普通硬盘因为需要移动磁头,所以随机寻址较慢,读越多的数据块就增大了总的硬盘寻道时间。当硬盘寻道时间比io时间还要长的多时,那么硬盘寻道时间就成了系统的一个瓶颈。合适的块大小有助于减少硬盘寻道时间,提高系统吞吐量。
  • 减少Namenode内存消耗。对于HDFS,他只有一个Namenode节点,他的内存相对于Datanode来说,是极其有限的。然而,namenode需要在其内存FSImage文件中中记录在Datanode中的数据块信息,假如数据块大小设置过少,而需要维护的数据块信息就会过多,那Namenode的内存可能就会伤不起了。

为什么不能远大于64MB(或128MB或256MB)?

这里主要从上层的MapReduce框架来讨论

  • Map崩溃问题:系统需要重新启动,启动过程需要重新加载数据,数据块越大,数据加载时间越长,系统恢复过程越长
  • 监管时间问题:主节点监管其他节点的情况,每个节点会周期性的把完成的工作和状态的更新报告回来。如果一个节点保持沉默超过一个预设的时间间隔,主节点记录下这个节点状态为死亡,并把分配给这个节点的数据发到别的节点。对于这个“预设的时间间隔”,这是从数据块的角度大概估算的。假如是对于64MB的数据块,我可以假设你10分钟之内无论如何也能解决了吧,超过10分钟也没反应,那就是死了。可对于640MB或是1G以上的数据,我应该要估算个多长的时间内?估算的时间短了,那就误判死亡了,分分钟更坏的情况是所有节点都会被判死亡。估算的时间长了,那等待的时间就过长了。所以对于过大的数据块,这个“预设的时间间隔”不好估算。
  • 问题分解问题:数据量大小是问题解决的复杂度是成线性关系的。对于同个算法,处理的数据量越大,它的时间复杂度也就越大。
  • 约束Map输出:在Map Reduce框架里,Map之后的数据是要经过排序才执行Reduce操作的。想想归并排序算法的思想,对小文件进行排序,然后将小文件归并成大文件的思想,然后就会懂这点了

hadoop在文件的split中使用到了一个 变量是blocksize,这个值默认配置是64M ,1.0的代码 给的默认值是32M ,这个值我们先不要纠缠他到底是多少,因为这个值是可配置的,而且已经给了默认配置64M ,只有我们不配置的时候才会使用32M ,且在官方文档上2.0已经是64M。那么为什么这个大小是64M ,记得在jvm的一片论文中提到这个大小是64M ,我们在使用linux的时候,linux系统也有块的大小,一般是4K 。

[root@cluster-19 workspace]# du -sk  
272032  .  
[root@cluster-19 workspace]# vi 1  
[root@cluster-19 workspace]# du -sk  
272036  .  
[root@cluster-19 workspace]# ls -la 1  
-rw-r--r--. 1 root root 2 8月  27 14:56 1

以上代码可以看到,我们使用du命令时看到 1 这个文件占用了一个块的空间,由于一个块的空间是 4096 (4K) 所有我们创建1这个文件之后我们看到磁盘空间增加了4K ,但是我们在使用ls 查看 1 这个文件的时候,我么看到这里文件的大小是 2 个字节。其实我们使用ls看到的只是文件的meta信息。

那么在hdfs中呢,前边已经说过块的大小是64M,我们做个假设如果  1T 的盘 ,我们上传小文件到 hdfs ,那么我们是不是只能上传1632个小文件,这个和我们预期远远不相符,hadoop确实是处理大文件有优势,但是也有处理小文件的能力,那就是在shuffle阶段会有合并的,且map的个数和块的数量有关系,如果块很小,那其不是有很多块 也就是很多map了,所以 hdfs中的块,会被充分利用,如果一个文件的大小小于这个块的话那么这个文件不会占据整个块空间。hdfs 的块如此之大主要还是为减小寻址开销的 ,用hadoop权威指南一句话:

HDFS的块比磁盘块大,其目的是为了最小化寻址开销。如果块设置得足够大,从磁盘传输数据的时间可以明显大于定位这个块开始位置所需的时间。这样,传输一个由多个块组成的文件的时间取决于磁盘传输速率。  

我们来做一个速算,如果寻址时间为10ms左右,而传输速率为100MB/s,为了使寻址时间仅占传输时间的1%,我们需要设置块大小为100MB左右。而默认的块大小实际为64MB,但是很多情况下HDFS使用128MB的块设置。以后随着新一代磁盘驱动器传输速率的提升,块的大小将被设置得更大。  

但是该参数也不会设置得过大。MapReduce中的map任务通常一次处理一个块中的数据,因此如果任务数太少(少于集群中的节点数量),作业的运行速度就会比较慢。