原文来自云台博客:http://yuntai.1kapp.com/?p=954
虽然说之前也对HDFS的应用场景有个大致的认识,但是总感觉不是十分彻底,因此前几天花了点时间进行了整理,现在把它贴出来。
1) HDFS不适合大量小文件的存储,因NameNode将文件系统的元数据存放在内存中,因此存储的文件数目受限于NameNode的内存大小。HDFS中每个文件、目录、数据块占用150Bytes。如果存放1million的文件至少消耗300MB内存,如果要存放1billion的文件数目的话会超出硬件能力,但是目前HDFS版本引入了Federation这种多NameNode的机制,可以支持NameNode的横向扩展;同时也可以适用HDFS的小文件合并为大文件的机制;
2) HDFS适用于高吞吐量,而不适合低时间延迟的访问(因为写文件可能存在初始化socket,初始化RPC,及其多次通信等)。如果同时存入1million的files,那么HDFS 将花费几个小时的时间;
3)流式读取的方式,不适合多用户写入一个文件(一个文件同时只能被一个客户端写),以及任意位置写入(不支持随机写),支持文件尾部apend操作,或者文件的覆盖操作;
4)没有HDFS HA机制之前,HDFS不能提供7*24小时的服务,由于有了HA机制出现,定时软硬件升级维护不再需要停机;
5)HDFS更加适合写入一次,读取多次的应用场景,通过线上HDFS集群的监控,hadoop目前业务的读写比为10:1,在设计上也是考虑了这一点,读速度比较快。
在上面一部分,已经提到HDFS不适合低延迟的访问,原因是写入一个文件,经过的通信次数比较多;如果对于一个大文件,它写数据流的时间远远大于RPC通信,socket建立连接,及其磁盘寻址等时间,因此大文件比较适合;如果对于小文件则相反,其他方面所消耗时间比写数据流的时间消耗得多。
由上图可知,写入文件大致经过如下流程:
1、首先创建RPC连接(客户端可创建一次,不再创建);
2、 创建文件元数据(必须);
3、 为文件分配块(文件有几个数据块,就请求分配几次);
4、 客户端与DataNode,DataNode之间建立socket(4,5,6),并且几者之间socket均建立成功才算成功,才能进行数据块的写入操作;
5、 每个DataNode接收完某个块会向NameNode进行报告;
6、 如果一个文件的每个块的三个副本中,只要有一个副本报告给NameNode,客户端发送消息给NameNode确认文件完成;
综合以上,对于一个比较小的文件,通信时间可能远大于数据上传时间,因此对于小文件给出以下建议:
上传小文件的时候,HDFS设置的数据块不宜太小,以免引起更多的通信交互,及其引起更多的磁盘寻址,建议用64MB即可。
备注:对于一个文件的数据块的3个副本,每个都上传成功,才算成功,否则该数据块上传失败,HDFS客户端重新选择DataNode进行上传。
上图仅表示出了在读取文件的时候的主要流程图,步骤如下:
1、首先创建RPC连接(客户端可创建一次,不再创建);
2、获取文件数据块位置(文件有几个数据块,就获取几次位置);
3、客户端与DataNode建立socket链接,该数据节点会选择离客户端最近的DataNode节点;
4、下载文件的数据块;
综合以上,对于一个相对比较小的文件,HDFS设置的数据块不宜太小,以免引起更多的通信交互,及其引起更多的磁盘寻址,建议用64MB即可;部署多客户端,而不是单客户端,这样可以平衡DataNode集群的IO;
对于小文件问题,hadoop自身提供了三种解决方案:Hadoop Archive、 Sequence File 和 CombineFileInputFormat,具体细节可参考:http://www.open-open.com/lib/view/open1330605869374.html
下线DataNode节点机器,rebalance等都比较成熟,方便。
除了支持命令行,原始客户端调用方式之外,还支持WebHDFS REST API,HttpFS Gateway,挂载等方式。