在Hadoop Mapreduce中的MultithreadedMapper类的内部线程映射器之间共享大对象?

时间:2017-03-14 11:42:48

标签: java multithreading hadoop

我在java中有一个简单的 Hadoop作业,它有一个mapper逐行处理我的文件。每个映射器都不受CPU约束,但应该在内存中保存一个非常大的对象(在我的情况下是一个Bloom Filter),其大小为2-15千兆字节(取决于计算精度)。在Mapper的setup()方法中,我从磁盘读取此对象并创建它。

我遇到了MultithreadedMapper类,在多个线程中执行计算。

job.setMapperClass(MultithreadMapper.class);
// ...
MultithreadedMapper.setMapperClass(job, MySingleThreadMapper.class);
MultithreadedMapper.setNumberOfThreads(job, 16);

但似乎MultithreadedMapper使用内部private class MapRunner extends Thread来生成线程映射器:

public class MultithreadedMapper<K1, V1, K2, V2> extends Mapper<K1, V1, K2, V2> {
//...
    public void run(Context context) throws IOException, InterruptedException {
    // ...

        runners =  new ArrayList<MapRunner>(numberOfThreads);
        for(int i=0; i < numberOfThreads; ++i) {
            MapRunner thread = new MapRunner(context);
            thread.start();
            runners.add(i, thread);
        }
    }
}

这是一个问题:如何在MultithreadedMapper中创建一个非常大的对象,并在集群节点(相同的jvm)的线程映射器之间共享它(使用上下文或其他)?

我尝试通过Singleton模式实现它,但是如果看起来不是一个漂亮的解决方案。

1 个答案:

答案 0 :(得分:1)

序言:我之前从未这样做过,但我会使用静态锁实现初始化:

static class MySingleThreadMapper extends Mapper<LongWritable, Text, Text, Text> {

    static MyResource sharedResource;

    @Override
    protected void setup(Context context) throws IOException, InterruptedException {
        super.setup(context);
        synchronized (MySingleThreadMapper.class) {
             if (sharedResource == null) {
                 sharedResource = createResource();
             }
        }
    }

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
       // mapper code
       // sharedResource will be initialized here
    }
}

您可能已经知道,Hadoop会在单独的JVM实例中生成Map和Reduce任务。因此,所有单线程映射器都将在同一个JVM中运行,您可以依赖静态锁定。您可以将任何其他静态对象用作锁,您的共享资源只会被初始化一次。