简体   繁体   English

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

[英]Multithreaded Spring Boot Application leaves MySQL processes in sleep state

I have a Spring Boot Application for cron tasks.我有一个用于 cron 任务的 Spring Boot 应用程序。 One of those tasks is executed as a group of several threads executed asynchronously.其中一个任务作为一组异步执行的多个线程来执行。 Each thread inserts ~200K data in MySQL compatible AWS Aurora Serverless DB.每个线程在 MySQL 兼容的 AWS Aurora Serverless DB 中插入约 200K 数据。 Before the task is finished, all the threads are being shutdown upon their completion, but the corresponding processes in MySQL remain in the process list with 'sleep' status.在任务完成之前,所有线程都在完成后关闭,但MySQL中的相应进程仍以'sleep'状态保留在进程列表中。 Here is the shorten sample:这是缩短的样本:

@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 */);
    }
}

Each separate thread execution may last for ~30min because of the huge amount of data to be processed and after the task's completion, in MySQL console I still see the corresponding processes which are in 'sleep' mode and which are being terminated only after the timeout value reaches.由于要处理的数据量巨大,每个单独的线程执行可能会持续约 30 分钟,并且在任务完成后,在 MySQL 控制台中,我仍然看到相应的进程处于“睡眠”模式,并且仅在超时后才终止值达到。

As you can see in the code, @Modifying annotation with its parameters didn't help either.正如您在代码中看到的,带有参数的@Modifying注释也没有帮助。 Also, I don't want to decrease the timeout value since that may affect on queries running directly in MySQL as well.另外,我不想减少超时值,因为这也可能影响直接在 MySQL 中运行的查询。 But I would like to terminate those processes since they affect on application's overall performance.但我想终止这些进程,因为它们会影响应用程序的整体性能。

So my questions is: is there a solution which will make the MySQL processes to be terminated instead of being slept when my task is finished?所以我的问题是:是否有一种解决方案可以使 MySQL 进程在我的任务完成时终止而不是休眠?

Update: Forgot to mention that the application is completely container managed and running under Tomcat.更新:忘记提及该应用程序完全由容器管理并在 Tomcat 下运行。 JDBC/ODBC bridge for MySQL (Aurora Serverless MySQL 5.7 compatible).用于 MySQL 的 JDBC/ODBC 桥(与 Aurora Serverless MySQL 5.7 兼容)。

By default, Spring Boot apps use HikariCP for connection pooling.默认情况下,Spring Boot 应用程序使用 HikariCP 进行连接池。 So basically the HikariCP is in charge of DB connection lifecycle.所以基本上 HikariCP 负责数据库连接生命周期。 So when one of your threads tries to execute any DB-related action, like read or write data to DB, it asks HikariCP to give it a connection, as the connection creation process is pretty slow and requires lots of resources, HikariCP by default keeps the connection in the pool for a configured time.所以当你的一个线程试图执行任何与数据库相关的操作时,比如读取或写入数据到数据库,它要求 HikariCP 给它一个连接,因为连接创建过程非常缓慢并且需要大量资源,HikariCP 默认情况下保持池中的连接在配置的时间内。 So you will need to refer to the maxLifetime and idleTimeout properties from HikariCP Documentation .因此,您需要参考 HikariCP文档中的maxLifetimeidleTimeout属性。

And as you are on spring boot, you may control the HikariCP from you application.properties file with the following config options.当您使用 spring boot 时,您可以使用以下配置选项从application.properties文件控制 HikariCP。

spring.datasource.hikari.minimum-idle=XXXX
spring.datasource.hikari.max-lifetime=XXX

all the threads are being shutdown upon their completion, but the corresponding processes in MySQL remain in the process list with 'sleep' status所有线程都在完成后关闭,但 MySQL 中的相应进程仍以“睡眠”状态保留在进程列表中

Spring boot uses HikariCP as a Default DB Connection Pool. Spring boot 使用 HikariCP 作为默认的数据库连接池。 When the transactions are closed, Connections are not closed.当事务关闭时,连接不会关闭。 Rather, DB connections are returned to the Connection Pool.相反,数据库连接返回到连接池。 So, MySQL must be showing those idle connections.因此,MySQL 必须显示那些空闲连接。

So my questions is: is there a solution which will make the MySQL processes to be terminated instead of being slept when my task is finished?所以我的问题是:是否有一种解决方案可以使 MySQL 进程在我的任务完成时终止而不是休眠?

If the connection pool is not used, then all the connections are opened when required and closed when transactions are completed.如果不使用连接池,则所有连接在需要时打开,并在事务完成时关闭。 MySQL won't show those sleep processes then.那时 MySQL 不会显示那些睡眠进程。 Please try setting below to disable connection pooling -请尝试以下设置以禁用连接池 -

spring.datasource.type=org.springframework.jdbc.datasource.SimpleDriverDataSource

But, if you disable DB Connection Pool, there are downsides to it -但是,如果您禁用数据库连接池,它就会有缺点 -

  1. MySQL will refuse connections when max connection limit on MySQL is exhausted.当 MySQL 的最大连接限制用尽时,MySQL 将拒绝连接。
  2. You won't get those benefits of connection pooling like connection reuse and a cap on maximum open DB Connections by the application.您不会获得连接池的那些好处,例如连接重用和应用程序对最大打开数据库连接的上限。

I suggest you find how many concurrent connections are needed by your application.我建议您找出您的应用程序需要多少个并发连接。 Then fine tune HikariCP connection pool property spring.datasource.hikari.maximum-pool-size so that connection pool is not impacting application performance.然后微调 HikariCP 连接池属性spring.datasource.hikari.maximum-pool-size以便连接池不影响应用程序性能。

You can try using these connection pool properties, and set the following in your application.properties file.您可以尝试使用这些连接池属性,并在您的 application.properties 文件中设置以下内容。

spring.datasource.hikari.idle-timeout=XXXXX
spring.datasource.hikari.maximum-pool-size=XX

To terminate the MySQL processes when your task is finished, you could try using a connection pooling library that allows you to close idle connections after a certain period of time.要在任务完成时终止 MySQL 进程,您可以尝试使用连接池库,它允许您在一段时间后关闭空闲连接。 This would allow you to reclaim resources that are being used by idle connections.这将允许您回收空闲连接正在使用的资源。

One option is to use the HikariCP library, which is a high-performance JDBC connection pool that allows you to configure a maximum idle time for connections.一种选择是使用 HikariCP 库,这是一个高性能的 JDBC 连接池,允许您为连接配置最大空闲时间。 To use it, you would need to add the HikariCP library as a dependency in your project and configure it as the connection pool for your application.要使用它,您需要将 HikariCP 库添加为项目中的依赖项,并将其配置为应用程序的连接池。

Here's an example of how you could configure HikariCP in your Spring Boot application:以下是如何在 Spring Boot 应用程序中配置 HikariCP 的示例:

@Configuration
public class DataSourceConfig {

  @Bean
  @ConfigurationProperties(prefix = "spring.datasource")
  public DataSource dataSource() {
      return DataSourceBuilder.create().type(HikariDataSource.class).build();
  }
}

You can then set the maximum idle time for connections using the idleTimeout property:然后,您可以使用 idleTimeout 属性设置连接的最大空闲时间:

spring.datasource.hikari.idle-timeout=600000 # idle connections will be closed after 10 minutes

This would cause the idle connections to be closed after they have been idle for 10 minutes.这会导致空闲连接在空闲 10 分钟后关闭。 You can adjust this value to suit your needs.您可以调整此值以满足您的需要。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Spring 启动 GCP PUBSUB 消费者应用程序 - Spring boot GCP PUBSUB Consumer application 通过 configMap 将参数传递给 GKE google cloud 中的 Spring boot 应用程序 - Passing params via configMap to Spring boot application in GKE google cloud 无法将 spring 引导指标发布到 GCP 堆栈驱动程序 - Unable to publish spring boot metrics to GCP stackdriver 使用 spring 引导从 Secret Manager GCP 获取值 - get values from Secret Manager GCP with spring boot Spring 启动 &amp; kubernetes JVM 不能 Z34D1F91FB2E514B8576FAB1A75A89AB6 CPU - Spring Boot & kubernetes JVM can not go over 1 CPU 在 Google App Engine 中部署 Spring boot gradle 应用 - Deploy Spring boot gradle app in Google App Engine 在 spring 启动 2.6.1 中使用 spring-cloud-gcp-pub-sub-stream-binder 时未发现内部方法错误 - internal method not found error while using spring-cloud-gcp-pub-sub-stream-binder in spring boot 2.6.1 如何将 ByteString 转换为 yml 文件中的字符串。 GCP 秘密管理器,spring 启动 - How to convert a ByteString to String in yml file. GCP secret manager, spring boot 我在 Amazon Elastic Bean Stalk 上尝试访问我的 spring boot 应用程序时收到错误 404 - I'm getting error 404 while trying to access my spring boot app on Amazon Elastic Bean Stalk Spring Docker 容器中的启动应用程序在构建成功后未在 Cloud Run 中启动 - 无法访问 jarfile - Spring Boot app in Docker container not starting in Cloud Run after building successfully - cannot access jarfile
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM