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

在Java中使用newAPIHadoopRDD读取MongoDB集合后如何停止线程?,java,mongodb,apache-spark,Java,Mongodb,Apache Spark,我正在使用Java中的newAPIHadoopRDD阅读MongoDB集合。 首先,我使用以下类创建一个JavaSparkContext对象: public class SparkLauncher { public JavaSparkContext javaSparkContext ; public SparkLauncher() { javaSparkContext = null; } public JavaSparkContext

我正在使用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方法吗?有没有办法摆脱这些线程

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

以下是使用jconsole的程序的内存使用情况:

最后是eclipse内存分析器中的泄漏嫌疑犯:

我没有将MongoDB与Spark一起使用,很可能无法完全回答您的问题,但我有一些可能导致解决方案的意见

  • System.setProperty(“spark.executor.memory”,“2g”)
    对于spark环境无效,因为您使用
    local
    模式,其中一个且仅有一个执行器的内存量是启动时分配给应用程序的内存量(并且永远不能更改)
您最好删除该线路或切换到其他Spark部署环境,例如独立、纱线或Mesos

  • 同样的注释也适用于
    conf.set(“spark.executor.instances”,“10”)
    ,因为最多只能有
    runtime.availableProcessor()
    numofores
    线程来启动任务。毕竟,您使用的是
    local
    模式,其中只有一个JVM具有多达
    Runtime.getRuntime().availableProcessors()
    线程来执行任务

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

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

下面是这段代码的jconsole输出,它显示了在运行期间累积的线程。

我还使用MongoDB api在另一个集合上实现了代码,但没有使用newAPIHadoopRDD(见下图): 过了一段时间,内存使用就固定了。 但请参阅我使用newAPIHadoopRDD读取同一集合时的内存使用情况和线程:

似乎对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>

org.mongodb.mongo-hadoop
mongo hadoop内核
1.4.2

您如何知道“所有线程仍处于活动状态且内存未释放。”?你如何测量/跟踪它?很少有截图可以帮助您查看所看到和引用的内容。感谢您的回复。我添加了一些显示场景的图像(第一个和第二个图像与运行停止命令后的图像相关)。关于你文章中提到的其他设置,你是对的,但它们不是问题的原因。这是我问题的解决方案。谢谢Zoran。所以处理这些奇怪问题的最好方法是检查POM文件中包的版本,并始终尝试使用它们的最新版本。