首先HDFS是适合大文件存储的文件系统,对于过多的小文件的应用场景并不适合。以下是一些使用过程中的经验和总结,希望对大家有所帮助,当然,如有谬误,也请大家指出,欢迎讨论。
过犹不及——根据数据查询需求,定制数据存储粒度
为了尽可能的细化数据存储粒度,我们对于每个产品的数据,按天进行隔离存储,这样,我们在查询某个产品某天的数据时,从HDFS中读取的数据就只是那一天的数据,这样从IO层面上看,这确实是最优的。但是随着时间的推移,HDFS中创建了越来越多的目录,每个目录对应Hive的一个partition,当我们查询的数据超过数百甚至上千个分区的时候,MR Job提交就变得很慢,而这样的需求却在平时的工作中成为常态,这样,由于数据存储粒度太细而导致的缓慢的任务提交过程,成为了我们的主要问题。而船大难掉头,数据收集系统的模式已经定死,只能寄希望于后期合并数据,而这又是项繁杂耗时的工作。
如果能回到当初。。。
首先,数据粒度并不是越细越好,需要根据存储系统(这里是HDFS)的特点去制定存储粒度。HDFS作为一种适合大文件存储的文件系统,太细的存储粒度,会使系统出现大量的小文件(在我们的场景下,小文件占据了大多数),这样,从存储效率的角度来看,太细的存储粒度是不可取的;其次,对于MapReduce任务的提交,如果有大量分区需要参与计算,那么任务初始化将会是一场灾难。考虑到我们的需求中,对跨度较长的数据的查询较多,且会成为常态,我们的存储策略,必须适应于这样的现实。
仔细观察需求我们会发现,一般的数据查询会限定在一个产品之内,而不会在产品之间进行查询;一个产品的数据可能会查询较长时间范围的数据。根据这些需求,可以初步制定以下的存储粒度策略:
1. 产品之间数据隔离
2. 单个产品的数据按照月份(或周)进行分区,也就是每个月(周)的数据都会集中在一个目录下面,而时间仅仅是数据中的一列
3. Hive数据仓库的表中,以产品ID、月份(或周)为Partition的字段
通过以上的存储结构,我们查询2014-02-14到2014-03-27之间的数据时,我们只需要指定对应的产品ID,然后将月份限定到2,3两个至上即可,这样我们也只是读取了2、3月份的数据,其它月份的数据不会访问。
这样,在将数据存储粒度适当加大之后,我们会消除大量的小文件存储,继而会提高MapReduce任务的提交速度,整个集群的利用率也会从某种程度上提高。