通过研究一些不太常用的替代方案来解决MapReduce性能问题以及选择解决方案时要考虑的因素。
解决MapReduce性能问题
—
以下解决方案来缓解MapReduce性能问题:
- 更改摄取过程/间隔
- 批处理文件合并
- 序列文件
- HBase
- S3DistCp(如果使用Amazon EMR)
- 使用CombineFileInputFormat
- Hive配置
- 使用Hadoop的附加功能
已经讨论过更改摄取过程,批处理文件合并和序列文件。
Hbase
—
如果要生成大量小文件,将数据作为文件存储在HDFS中可能不是最佳解决方案。相反,您可以考虑使用HBase列存储。使用HBase可以将摄取过程从生成许多小型HDFS文件更改为将单个记录写入HBase表。如果您的数据访问模式基于明确定义的随机访问查找,则HBase可能是您的最佳选择。它在架构上针对高速数据记录插入,大容量,单个记录查找和基于流的分析进行了调整。但是,如果您的数据访问模式倾向于完整文件/表扫描,那么HBase可能不是最佳的。
可以创建映射到HBase数据的Hive表; 但是,此设计中的查询性能会有所不同。当选择单行或一系列行时,HBase上的Hive会闪烁,但如果您的查询倾向于全表扫描,则HBase的效率非常低。大多数分析查询,尤其是那些使用group by的查询,都需要进行全表扫描。
HBase提供了将数据流式传输到Hadoop并使其可实时处理的最佳能力。但是,平衡HBase与其他集群进程的需求可能具有挑战性,并且需要高级系统管理。此外,HBase性能在很大程度上取决于数据访问模式,在选择HBase解决小文件问题之前,应仔细考虑这些模式。
S3DistCp
—
此解决方案仅适用于Amazon EMR的用户。Amazon EMR集群的生命周期很短,将数据保存在Amazon S3中。即使使用Amazon S3,处理大量小文件仍然会导致启动不必要的map任务,从而降低性能。
S3DistCp是亚马逊提供的一种实用程序,用于将数据从S3分发复制到临时HDFS甚至其他S3存储桶。该实用程序提供了通过使用groupBy和targetSize选项将文件连接在一起的功能。当您在S3中存储了数千个要使用Amazon EMR处理的小文件时,这非常有用。S3DistCp通过连接许多小文件并使它们出现在更快,短暂的HDFS存储中,一举两得。据报道,使用这种机制可以提高15倍的性能。
出于所有实际目的,S3DistCp执行与提到的批处理文件合并方法相同的任务。如果使用Amazon EMR,请注意您有一个预先构建的工具来完成此任务。
使用CombineFileInputFormat
—
CombineFileInputFormat是Hadoop提供的抽象类,它在MapReduce读取时合并小文件。合并的文件不会持久保存到磁盘。相反,该过程读取多个文件并“动态”合并它们以供单个map任务使用。您可以获得不为每个文件启动一个map任务的好处,并且不需要将多个文件合并到一个持久文件中作为准备步骤的一部分。这解决了MapReduce作业启动太多map任务的问题; 但是,由于作业仍在读取多个小文件,因此随机磁盘IO仍然存在问题。此外,CombineFileInputFormat的大多数实现都不考虑数据局部性,并且通常会通过网络从各种数据节点提取数据。
为了实现这一点,必须在Java中为不同的文件类型扩展CombineFileInputFormat。这需要大量的开发专业知识来开发您的自定义输入格式类。但是,一旦编写,您可以配置最大分割大小,它将合并文件,直到满足此大小。
请注意,由于合并数据不会在HDFS中保留,因此CombineFileInputFormat不会缓解NameNode内存问题。
Hive配置
—
如果您注意到Hive通过“create table as”或“insert overwrite”语句在Hadoop集群中创建小文件,则可以调整一些Hive特定配置设置以进行缓解。使用时,这些设置会告诉Hive将创建的任何小文件合并到较大的文件中。但是,有一个惩罚。Hive将启动一个额外的MapReduce作业后查询,以执行合并。此外,在Hive向用户指示查询已完成处理而不是异步发生之前完成合并。
应该注意,这些设置仅适用于由Hive创建的文件。例如,如果使用其他工具(如Sqoop)在Hive外部创建文件,则使用hdfs fs -mv命令将其复制到Hive表中,Hive将不会合并文件。因此,当摄入Hadoop的文件很小时,此解决方案不起作用。此解决方案仅建议在以Hive为中心的体系结构中,其中insert overwrite和create table as语句中的小性能损失是可接受的。
要使用的设置是:
使用Hadoop的附加功能
—
附加可能是可用的,但Hadoop生态系统中的主要工具都不支持它:Flume,Sqoop,Pig,Hive,Spark和Java MapReduce。MapReduce强制执行一条规则,即MapReduce作业的输出位置在执行之前不得存在。由于这个规则,MapReduce显然不可能通过其输出附加到预先存在的文件。由于Sqoop,Pig和Hive都使用了MapReduce,因此这些工具也不可能支持追加。Flume不支持追加很大程度上是因为它假设经过一段时间(无论是秒,字节,事件数或不活动秒),Flume将关闭文件而不再打开它。Flume社区认为这足够,而不是要求追加支持。
如果你真的必须在Hadoop中使用appends,你必须编写自己的系统来执行摄取并附加到现有文件。此外,如果您的任何群集内处理需要附加到现有文件,您将无法使用Spark或MapReduce。因此,使用HDFS附加功能非常复杂,只能由技术最精湛的组织使用。如果没有重要的工程团队和支持承诺,则不建议使用此选项。
选择解决方案
—
选择使用小文件的最佳解决方案取决于各种问题。可能有必要根据访问模式和数据要求使用这些解决方案的组合。应该考虑的问题包括:
- 数据流中的哪一点是生成的小文件?是在摄取时还是通过群集内处理创建小文件?
- 生成小文件的工具是什么?更改工具配置可以减少小文件的数量吗?
- 您的组织有多少技术技能?您是否有能力维护输入格式或编写自己的摄取引擎?
- 生成小文件的频率是多少?为了创建大文件,可以多久合并一次小文件?
- 这些小文件需要哪种数据访问?这些文件是否需要通过Hive访问?
- 可以在集群内部运行流程以减轻小文件的管理周期类型?
- MapReduce流程可接受的延迟级别是多少?