我有一个hadoop作业,可以合并表中不同分区的不同存储桶文件。 例如:我有一个表,该表按create_date分区,并有12个存储桶。
@Configuration
class DataSourceConfig {
public final static int SPAIN = 2;
public final static int BRAZIL = 1;
@Bean
@Qualifier("dataSources")
public Map<Integer, DataSource> dataSources() {
Map<Integer, DataSource> ds = new HashMap<>();
ds.put(SPAIN, buildSpainDataSource());
ds.put(BRAZIL, buildBrazilDataSource());
return ds;
}
private DataSource buildSpainDataSource() {
...
}
private DataSource buildBrazilDataSource() {
...
}
}
@Service
class MyService {
@Autowired
@Qualifier("dataSources")
Map<Integer, DataSource> dataSources;
Map<String, Object> getObjectForCountry(int country) {
NamedParameterJdbcTemplate t = new NamedParameterJdbcTemplate(dataSources.get(country));
return t.queryForMap("select value from mytable", new HashMap<>());
}
}
所以说我有12个create_date分区。 当我运行Hadoop作业(这是仅地图作业,不涉及reducer)时,它将从每个分区中选择具有相同名称的存储桶文件,将它们合并为一个文件,并将其存储在新分区中。
create_date='2019-10-01' will have 4 bucket files, viz., part00000_0, part00000_1, part00000_2, part00000_3,........,part00000_11
create_date='2019-10-02' will have 4 bucket files, viz., part00000_0, part00000_1, part00000_2, part00000_3,........,part00000_11
因此,将在我的应用程序中启动12个mapper作业进行合并(每个mapper处理12个文件)。 我的工作的默认映射器内存(mapreduce.map.memory.mb)为2.5G 但是在执行此操作时,在大多数情况下会出现以下错误:
For eg:
merge(create_date='2019-10-01'/part00000_0, create_date='2019-10-02'/part00000_0,
create_date='2019-10-03'/part00000_0,.....,create_date='2019-10-12'/part00000_0)
into
merge_partition/part00000_0
Similarly:
merge(create_date='2019-10-01'/part00000_1, create_date='2019-10-02'/part00000_1,
create_date='2019-10-03'/part00000_1,.....,create_date='2019-10-12'/part00000_1)
into
merge_partition/part00000_1
我通过了ORC代码,发现: https://github.com/apache/orc/blob/master/java/core/src/java/org/apache/orc/impl/RecordReaderImpl.java。 readStripe()方法在读取条带时将整个条带拉入内存。
因此,如果考虑到这一点,我将对12个part00000_x文件执行合并操作,并且我的ORC条带大小为256 MB。 因此12x256 MB = 3072MB。这超出了我的容器限制。 我做了一个小的POC来确认这一点,然后签出。 另外,我确认文件的大小无关紧要。即使文件大小为1G,也要占用256MB的堆空间;对于文件大小为4.5G的文件,它也要占用相同的堆空间。 因此,我想到添加一个简单的代码,该代码将根据表的分区数量来增加映射器的内存。
但是我发现生产中很少有大约200多个分区(=要合并的文件数量)的作业,并且运行良好。按照我的POC的说法,它们应该占用超过50G的映射器内存才能成功,但是在使用10G的映射器内存时它们可以正常运行。
有人可以提供有关解决此问题的宝贵建议。