如何在Java中使用newAPIHadoopRDD读取MongoDB集合后停止线程?

时间:2015-12-23 19:54:37

标签: java mongodb apache-spark

我正在使用Java中的newAPIHadoopRDD读取MongoDB集合。 首先,我使用以下类创建一个JavaSparkContext对象:

public class SparkLauncher {
    public JavaSparkContext javaSparkContext ;

    public SparkLauncher()
    {
        javaSparkContext = null;
    }

    public JavaSparkContext getSparkContext() {
        if (javaSparkContext == null ) {
            System.out.println("SPARK INIT...");
            try {
                System.setProperty("spark.executor.memory", "2g");
                Runtime runtime = Runtime.getRuntime();
                runtime.gc();
                int numOfCores = runtime.availableProcessors();                 
                numOfCores=3;               
                SparkConf conf = new SparkConf();
                conf.setMaster("local[" + numOfCores + "]");
                conf.setAppName("WL");                  
                conf.set("spark.serializer",
                        "org.apache.spark.serializer.KryoSerializer");
                    javaSparkContext = new JavaSparkContext(conf);                  
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return javaSparkContext;
    }   

    public void closeSparkContext(){
        javaSparkContext.stop(); 
        javaSparkContext.close();
        javaSparkContext= null;     
    }   
}

然后,在其他课程中我读了mongodb集合:

SparkLauncher sc = new SparkLauncher(); 
JavaSparkContext javaSparkContext = sc.getSparkContext();

try {
        interactions = javaSparkContext.newAPIHadoopRDD(mongodbConfig,
        MongoInputFormat.class, Object.class, BSONObject.class);
    }
 catch (Exception e) {
        System.out.print(e.getMessage());
    }

这段代码创建了很多线程来读取集合的分裂。关闭JavaSparkContext对象后:

javaSparkContext.close();
sc.closeSparkContext();
System.gc();

所有线程仍处于活动状态且内存未释放。它会导致内存泄漏和线程泄漏。这是因为newAPIHadoopRDD方法吗?有没有办法摆脱这些线程?

以下是仍处于活动状态的部分线程的快照: enter image description here

以下是使用jconsole的程序的内存使用情况: enter image description here

最后,eclipse内存分析器中的漏洞可疑: enter image description here

3 个答案:

答案 0 :(得分:1)

似乎有connection leakage problem mongo-hadoop。运行从mongodb流式传输数据的示例代码后,我可能会遇到同样的问题。

似乎是最新版本1.4.2修复,它在示例代码中对我来说很好。 将您的maven依赖关系更改为:

<dependency>
    <groupId>org.mongodb.mongo-hadoop</groupId>
    <artifactId>mongo-hadoop-core</artifactId>
    <version>1.4.2</version>
</dependency>

答案 1 :(得分:0)

我没有将Spark与MongoDB一起使用,很可能无法完全回答你的问题,但我的评论很少,可能会导致解决方案。

  • System.setProperty("spark.executor.memory", "2g")对您的Spark环境无效,因为您使用local模式,其中一个且只有一个执行程序的内存量是在启动时分配给应用程序的内存(并且不能更改)。

您最好不要删除该线路或切换到其他Spark部署环境,例如独立,YARN或Mesos。

  • 相同的评论适用于conf.set("spark.executor.instances", "10"),因为最多只能有runtime.availableProcessors()numOfCores个帖子来启动任务。在所有只有一个JVM最多有local个线程用于执行任务的情况下,您正在使用Runtime.getRuntime().availableProcessors()模式。

Spark最终将释放Spark使用的线程。它们所属的线程池已作为SparkContext.stop的一部分关闭(在您的示例中看不到它被调用,但由于我使用的是Scala API,因此可能存在差异)。

答案 2 :(得分:0)

我做了另一个实验。这次我只是编写了一个简单的代码来在一个循环中使用相同的方法读取一个Mongo集合,并进行了15次迭代。在循环结束时,我也会调用System.gc()以防万一。

以下是此代码的jconsole输出,它显示了运行期间累积的线程。 enter image description here

我还使用MongoDB api实现了代码,而在另一个集合中没有newAPIHadoopRDD(见下图): enter image description here 一段时间后,内存使用率变得固定。 但是当我使用newAPIHadoopRDD读取相同的集合时,请查看内存使用情况和线程: enter image description here