Spring 弹簧靴&x2B;骆驼+;producerTemplate=数千个线程

Spring 弹簧靴&x2B;骆驼+;producerTemplate=数千个线程,spring,ssh,memory-leaks,spring-boot,apache-camel,Spring,Ssh,Memory Leaks,Spring Boot,Apache Camel,---更新--- 事实证明,堆在一段时间后会被清空。然而,线程的数量不断增长。在8Gb内存的mac上,我很好,但在1Gb的生产机器上,我得到: 线程“thread-341”java.lang.OutOfMemoryError中出现异常:无法创建新的本机线程 我确实使用SpringBoot(1.2.7.RELEASE)和ApacheCamel(2.15.0)编写了一个简单的应用程序。这个应用程序很简单,只有一条路径:计时器每1s调用一个bean上的方法。调用的方法将使用ProducerTempl

---更新---
事实证明,堆在一段时间后会被清空。然而,线程的数量不断增长。在8Gb内存的mac上,我很好,但在1Gb的生产机器上,我得到:

线程“thread-341”java.lang.OutOfMemoryError中出现异常:无法创建新的本机线程


我确实使用SpringBoot(1.2.7.RELEASE)和ApacheCamel(2.15.0)编写了一个简单的应用程序。这个应用程序很简单,只有一条路径:计时器每1s调用一个bean上的方法。调用的方法将使用
ProducerTemplate
以ssh方式连接到远程计算机,执行一个小脚本,并将输出输出输出到控制台。简单,对吗?
然而,在分析这一点时,我可以看到线程的数量,并且堆可以通过屋顶!似乎任何为ssh创建的线程都不会被终止,而是被停止。正因为如此,我跑得很快。
让我向您展示一些探查器输出:

正如您所看到的,线程/堆非常快速地上升。 应用程序代码很小,因此我将在此处提供所有代码以供参考。
pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>tests</groupId>
    <artifactId>camel-producer-template-testing</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <start-class>app.Application</start-class>
        <camel.version>2.15.0</camel.version>
        <spring-boot.version>1.2.7.RELEASE</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-core</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-spring</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-spring-boot</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-ftp</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-ssh</artifactId>
            <version>${camel.version}</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <!-- Import dependency management from Spring Boot -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <finalName>${project.artifactId}-${project.version}</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.util.TimeZone;

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
    public static void main(String[] args) {
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
        SpringApplication application = new SpringApplication(Application.class);
        application.run(args);
    }
}
import org.apache.camel.CamelContext;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.spring.SpringCamelContext;
import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource("application.properties")
public class MyAppContext {

    private final String sshKeyPath = "/Users/gruszd/.ssh/id_rsa";

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public CamelContext camelContext() {
        return new SpringCamelContext(applicationContext);
    }

    @Bean
    FileKeyPairProvider keyPairProvider() {
        return new FileKeyPairProvider(new String[]{sshKeyPath});
    }

    @Bean
    RoutesBuilder myRouter() {
        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("timer://foo?period=1000").to("bean:sftpStager?method=stage");
            }
        };
    }
}
import org.apache.camel.ProducerTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class SftpStager {

    @Autowired
    private ProducerTemplate producerTemplate;

    public void stage() throws Exception {
        String response = producerTemplate.requestBody(
                "ssh://_remote.machine.url.here_?username=_username_&keyPairProvider=#keyPairProvider",
                "/home/_username_/some_temp_script.sh",
                String.class);
        System.out.println("----");
        System.out.println(response);
        System.out.println("----");
    }
}
MyAppContext.java:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>tests</groupId>
    <artifactId>camel-producer-template-testing</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <start-class>app.Application</start-class>
        <camel.version>2.15.0</camel.version>
        <spring-boot.version>1.2.7.RELEASE</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-core</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-spring</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-spring-boot</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-ftp</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-ssh</artifactId>
            <version>${camel.version}</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <!-- Import dependency management from Spring Boot -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <finalName>${project.artifactId}-${project.version}</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.util.TimeZone;

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
    public static void main(String[] args) {
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
        SpringApplication application = new SpringApplication(Application.class);
        application.run(args);
    }
}
import org.apache.camel.CamelContext;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.spring.SpringCamelContext;
import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource("application.properties")
public class MyAppContext {

    private final String sshKeyPath = "/Users/gruszd/.ssh/id_rsa";

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public CamelContext camelContext() {
        return new SpringCamelContext(applicationContext);
    }

    @Bean
    FileKeyPairProvider keyPairProvider() {
        return new FileKeyPairProvider(new String[]{sshKeyPath});
    }

    @Bean
    RoutesBuilder myRouter() {
        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("timer://foo?period=1000").to("bean:sftpStager?method=stage");
            }
        };
    }
}
import org.apache.camel.ProducerTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class SftpStager {

    @Autowired
    private ProducerTemplate producerTemplate;

    public void stage() throws Exception {
        String response = producerTemplate.requestBody(
                "ssh://_remote.machine.url.here_?username=_username_&keyPairProvider=#keyPairProvider",
                "/home/_username_/some_temp_script.sh",
                String.class);
        System.out.println("----");
        System.out.println(response);
        System.out.println("----");
    }
}
sftptager.java:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>tests</groupId>
    <artifactId>camel-producer-template-testing</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <start-class>app.Application</start-class>
        <camel.version>2.15.0</camel.version>
        <spring-boot.version>1.2.7.RELEASE</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-core</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-spring</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-spring-boot</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-ftp</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-ssh</artifactId>
            <version>${camel.version}</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <!-- Import dependency management from Spring Boot -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <finalName>${project.artifactId}-${project.version}</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.util.TimeZone;

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
    public static void main(String[] args) {
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
        SpringApplication application = new SpringApplication(Application.class);
        application.run(args);
    }
}
import org.apache.camel.CamelContext;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.spring.SpringCamelContext;
import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource("application.properties")
public class MyAppContext {

    private final String sshKeyPath = "/Users/gruszd/.ssh/id_rsa";

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public CamelContext camelContext() {
        return new SpringCamelContext(applicationContext);
    }

    @Bean
    FileKeyPairProvider keyPairProvider() {
        return new FileKeyPairProvider(new String[]{sshKeyPath});
    }

    @Bean
    RoutesBuilder myRouter() {
        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("timer://foo?period=1000").to("bean:sftpStager?method=stage");
            }
        };
    }
}
import org.apache.camel.ProducerTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class SftpStager {

    @Autowired
    private ProducerTemplate producerTemplate;

    public void stage() throws Exception {
        String response = producerTemplate.requestBody(
                "ssh://_remote.machine.url.here_?username=_username_&keyPairProvider=#keyPairProvider",
                "/home/_username_/some_temp_script.sh",
                String.class);
        System.out.println("----");
        System.out.println(response);
        System.out.println("----");
    }
}
正如您所看到的,该应用程序非常简单,并且可以正常工作(我可以在运行该应用程序的控制台中看到远程脚本的输出)。但就像我说的,它像新鲜饼干一样吞噬记忆
现在我确实读了。但是,在我的应用程序中,
ProducerTemplate
是由
Camelcontext
本身实例化的bean。因此,我无法
producerTemplate.stop()
,因为下一个触发器将引发异常,表示模板未启动…
所以我的主要问题是:我是否以错误的方式使用了
ProducerTemplate
?如果我这样做了,我应该如何使用它?

如果我没有做错什么,那是一个错误吗?我应该报告吗?

如原始海报所示:

事实证明,这是Apache Camel本身的一个bug,应该在2.16.2中修复:


必须停止/清除产品模板的状态


有内置的方法,如
producerTemplate.stop()
,或者在您的情况下,由于您已经自动连接了生产者模板,您可以尝试
producerTemplate.cleanUp()

是否可以尝试使用最新发布的Camel 2.15.4版本执行相同的测试?只是为了继续处理同一个未成年人。与最新的骆驼完全相同的情况。在运行了3分钟后,我有将近2000个线程坐在那里…愚蠢的问题:为什么要使用ProducerTemplate?只需从(“timer://foo?period=1000“”.setBody(简单(“/home/\u username\uu/some\u temp\u script.sh”)。到(“”ssh://_remote.machine.url.here_?username=_username_&keyPairProvider=#keyPairProviderlog(…)我给出的示例是非常简化的场景。实际上,我正在生成url,用户名是根据其他一些事情动态选择的。此外,根据spring概要文件,我可能会加载bean的不同实现等。