多线程 Spring Boot 应用程序使 MySQL 进程处于睡眠状态

Arm*_*ine 5 java mysql multithreading amazon-web-services amazon-aurora

我有一个用于 cron 任务的 Spring Boot 应用程序。其中一个任务作为一组异步执行的多个线程来执行。每个线程都会在 MySQL 兼容的 AWS Aurora Serverless DB 中插入约 200K 数据。在任务完成之前,所有线程都在完成后关闭,但MySQL中相应的进程仍以“睡眠”状态保留在进程列表中。这是缩短的示例:

@SpringBootApplication
@EnableScheduling
public class ScheduledServiceApp implements SchedulingConfigurer {
    private static final int POOL_SIZE = 20;

    public static void main(String[] args) {
       SpringApplication.run(ScheduledServiceApp.class, args);
    }


    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();

        threadPoolTaskScheduler.setPoolSize(POOL_SIZE);
        threadPoolTaskScheduler.setThreadNamePrefix("scheduled-task-pool-");
        threadPoolTaskScheduler.initialize();

        scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
     }
}


@Component
public class ScheduledTask {

    // .....

    @Scheduled(cron = "${task.cron.expression}", zone="UTC")
    // @Modifying(clearAutomatically = true, flushAutomatically = true)
    @Transactional
    public void runTask() {
        try {
            // .....

            ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(THREAD_COUNT);

            for (int i = 0; i < THREAD_COUNT; ++i) {
                Runnable task = new TaskThread();
                executor.execute(task);
            }

            executor.shutdown();

            while (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
                // wait until the processes in the executor will be terminated
            }

            log.info("Task is completed successfully");
        } catch (Exception e) {
            // log the error
        }
    }
}


public class TaskThread implements Runnable {
    // .....

    public void run() {
        dataService.insertData(/* parameters */);
    }
}
Run Code Online (Sandbox Code Playgroud)

每个单独的线程执行可能会持续约 30 分钟,因为要处理的数据量很大,任务完成后,在 MySQL 控制台中我仍然看到相应的进程处于“睡眠”模式,并且仅在超时后才终止值达到。

正如您在代码中看到的,@Modifying带有参数的注释也没有帮助。另外,我不想减少超时值,因为这也可能会影响直接在 MySQL 中运行的查询。但我想终止这些进程,因为它们会影响应用程序的整体性能。

所以我的问题是:是否有一个解决方案可以使 MySQL 进程在我的任务完成时终止而不是休眠?

更新:忘记提及该应用程序完全由容器管理并在 Tomcat 下运行。适用于 MySQL 的 JDBC/ODBC 桥(兼容 Aurora Serverless MySQL 5.7)。

Bab*_*abl 5

默认情况下,Spring Boot 应用程序使用 HikariCP 进行连接池。因此基本上 HikariCP 负责数据库连接生命周期。因此,当您的一个线程尝试执行任何与数据库相关的操作(例如向数据库读取或写入数据)时,它会要求 HikariCP 为其提供一个连接,因为连接创建过程非常慢并且需要大量资源,HikariCP 默认情况下会保留池中的连接持续配置的时间。因此,您需要参考HikariCP文档maxLifetime中的和属性。idleTimeout

application.properties当您使用 Spring Boot 时,您可以使用以下配置选项从文件中控制 HikariCP 。

spring.datasource.hikari.minimum-idle=XXXX
spring.datasource.hikari.max-lifetime=XXX
Run Code Online (Sandbox Code Playgroud)


SKu*_*mar 1

所有线程在完成后都将被关闭,但 MySQL 中相应的进程仍以“睡眠”状态保留在进程列表中

Spring boot 使用 HikariCP 作为默认数据库连接池。当事务关闭时,连接不会关闭。相反,数据库连接将返回到连接池。因此,MySQL 必须显示那些空闲连接。

所以我的问题是:是否有一个解决方案可以使 MySQL 进程在我的任务完成时终止而不是休眠?

如果不使用连接池,则所有连接将在需要时打开,并在事务完成时关闭。MySQL 将不会显示这些睡眠进程。请尝试以下设置来禁用连接池 -

spring.datasource.type=org.springframework.jdbc.datasource.SimpleDriverDataSource
Run Code Online (Sandbox Code Playgroud)

但是,如果禁用数据库连接池,则会有缺点 -

  1. 当 MySQL 的最大连接限制耗尽时,MySQL 将拒绝连接。
  2. 您将无法获得连接池的好处,例如连接重用和应用程序打开的最大数据库连接数上限。

我建议您找出您的应用程序需要多少个并发连接。然后微调 HikariCP 连接池属性spring.datasource.hikari.maximum-pool-size,使连接池不会影响应用程序性能。