【问题标题】:Is there a better approach to reduce execution time of a long running quartz job?有没有更好的方法来减少长时间运行的石英作业的执行时间?
【发布时间】:2020-02-09 22:54:06
【问题描述】:

我有一个将在晚上某个时间触发的 cron 作业,它会从数据库中获取大约 100k 的大量 productId, 并从一个服务中获取所有这些产品的 productInfo,该服务对 1 个 productId 的 API 调用大约需要 700 毫秒。

CronJob

public class GetProducts extends QuartzJobBean {

    @Autowired
    private ProductClient productClient;

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {

        List<Long> ProductsIds = fetchAllProductIdsFromDb();

        Response<ProductClientResponse> response = null;

        for (Long productId : ProductsIds) {
            ProductClientRequestBody requestBody = new ProductClientRequestBody();
            requestBody.putIdInsideTheRequestBody(productId);
            response = productClient.getResult(requestBody).execute();

            if (response != null && response.isSuccessful()) {
                log.info("We have got successful response for {}", i);
            }
        }
    }
}

这里的 productClient 是服务的 Retrofit 客户端。 所以这项工作在技术上需要 5 个小时才能完成。

#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName=QuartzScheduler
org.quartz.scheduler.instanceId=AUTO
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=80
org.quartz.threadPool.threadPriority=5
#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.misfireThreshold=60000
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties=true
org.quartz.jobStore.dataSource=myDS
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval=20000
#============================================================================
# Configure Datasources
#============================================================================
org.quartz.dataSource.myDS.driver=com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.maxConnections=10
org.quartz.dataSource.myDS.validationQuery=select 0 from dual
org.quartz.scheduler.batchTriggerAcquisitionMaxCount =10
org.quartz.dataSource.myDS.URL=jdbc:mysql://127.0.0.1:3306/quartz
org.quartz.dataSource.myDS.user=root
org.quartz.dataSource.myDS.password=root

这是我的石英属性文件。 我想知道是否有更好的方法来获取所有 100k 产品的 ProductInfo。

一种方法

我为所有 ProductId 安排了 100k 个作业。而在集群环境中运行的quartz会根据可用的实例进行调度。

org.quartz.threadPool.threadCount=80 - 该属性表明在一个服务实例中最多有 80 个线程可以占用作业。 是吗? 如果我有 2 个实例正在运行,那么至少 100-160 个作业可以同时运行。我的方法正确吗?这可以大大减少时间。

还有比这更好的方法吗?

【问题讨论】:

  • 你可以使用quartz来调度job,也可以使用Executors来实际运行job。所以本质上,你不会持有由quartz框架调用的线程。
  • 所以你的意思是我应该像我一样创建一个工作,并且在里面应该使用执行器线程。是吗?
  • 是的。所以创建作业,然后将责任委托给另一个类,该类将拥有执行器并可以并行运行您的作业。根据您的要求调整执行器的线程数。这将使任何其他石英计划任务的空间,因为线程将被快速释放。

标签: java spring spring-boot quartz-scheduler


【解决方案1】:

注意:- 这是为了演示代码可以进一步即兴发挥的方法(我没有测试过代码,可能存在语法错误)



public class ProductsJob extends QuartzJobBean {

@Autowired
private ProductClient productClient;

@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
    List<Long> ProductsIds = fetchAllProductIdsFromDb();
    ProductsExecutor productsExecutor=new ProductsExecutor();
    productsExecutor.runTasks(ProductsIds);
}

}

public class ProductsExecutor {

private int threadPoolSize=10;
private ExecutorService executorService;

public ProductsExecutor()
{
    executorService =Executors.newFixedThreadPool(threadPoolSize);
}

public void runTasks(List<Integer> productIds)
{
    //Loop and execute the task and wait for them it necessary
    ProductsWorker worker=new ProductsWorker();
    worker.setProductId(productId);
     executorService.invokeAll(worker);
}

}

public class ProductsWorker implements Runnable {

private int productId; @Override public void run() { ProductClientRequestBody requestBody = new ProductClientRequestBody(); requestBody.putIdInsideTheRequestBody(productId); response = productClient.getResult(requestBody).execute(); if (response != null && response.isSuccessful()) { log.info("We have got successful response for {}"); } } public void setProductId(int productId) { this.productId=productId; }

}

不要忘记销毁您的执行器服务,因为每次石英运行都会创建一个新的执行器服务。您还可以为所有提交的任务添加 awaitTermination。

【讨论】:

    猜你喜欢
    • 2016-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 1970-01-01
    • 2010-12-13
    • 1970-01-01
    相关资源
    最近更新 更多