首页 > 解决方案 > 使用多个线程池和连接池

问题描述

我目前正在使用 5 个线程池,我想为这些池找到最佳大小。这是某种先验分析。池按用途划分:用于处理命令(cmdPool)、处理库存事务(invPool)、用于数据库事务的池(dbPool),还用于只需要像 I/O 那样运行异步的普通事物(fastPool)和用于计划任务的池(计时器池)。我还没有任何可用于解决问题的统计数据。

对于数据库查询,我使用带有默认值的 HikariCP。稍后我将尝试更改最大连接数和最小空闲连接数以找到最佳性能。但是现在,当使用 Hikari 池时,它将始终从其中一个池中调用,以不影响主线程。通常的数据库查询在 dbPool 下调用,但仅当代码块不是已提交到线程池之一的已可运行文件的一部分时。

实际设置看起来它只是在应用程序中正常工作。所以我的问题是:

1.) 当我决定停止使用 cachedThreadPool 并使用带有一些最小空闲线程(如 timerPool)的池时,将如何影响性能和资源,或者我应该坚持使用 cached ?

2.) 设置最大池大小以防止在短时间内有 100 个客户端加入并让他们在其他任务完成时等待一小段时间时出现峰值是正确的解决方案。

3.)有没有更好的解决方案如何管理多种任务?

cmdPool = Executors.newFixedThreadPool(3);
invPool = Executors.newFixedThreadPool(2);
dbPool = Executors.newCachedThreadPool();
fastPool = Executors.newCachedThreadPool();
timerPool = new ScheduledThreadPoolExecutor(5);
timerPool.allowCoreThreadTimeOut(true);
timerPool.setKeepAliveTime(3, TimeUnit.MINUTES); 

所以首先,每个动作都取决于连接了多少客户端,让我们假设像 5-25 个客户端这样的值。池的设计应该能够维持 100 个客户端这样的极端情况,并且不会在短时间内创建太多线程。

预期用途可能会有所不同,并且每秒都不相同,甚至可能根本不会运行任何任务。cmdPool 的预期使用量是每秒使用 3-8 次(轻量级任务)。对于 invPool 的使用几乎与 cmdPool 相同,每秒使用 2-6 次(也是轻量级任务)。至于 dbPool,这比其他所有的都更难以预测,但仍然预期的使用量是每秒 5-20 次使用(轻量级和中量级任务)也取决于网络的繁忙程度。计时器和快速池旨在接受任何类型的任务并直接执行,预计每秒使用 20-50 次。

我很感激任何建议,谢谢。

标签: javathreadpoolconnection-pooling

解决方案


最好的解决方案是使您的应用程序适应预期的流量。您可以通过多种方式做到这一点:

  • 使用微服务架构设计它,让编排器来处理流量高峰
  • 设计动态读取线程池大小参数应用程序(从数据库、文件、配置服务器......),以便您可以在需要时更改值
  • 如果您只需要调整您的应用程序但不需要动态更改值,请将您的配置放入文件(或数据库)中。检查不同的配置以找到最适合您需求的配置

重要的是移走与此类似的代码:

cmdPool = Executors.newFixedThreadPool(3);

并将其替换为类似于此的代码

@Value("${cmdPoolSize}")
private int cmdPoolSize;

...

cmdPool = Executors.newFixedThreadPool(cmdPoolSize);

其中池的大小不是取自代码,而是取自外部配置

更好的方法也是定义带参数的池类型:

@Value("${cmdPoolType}")
private String cmtPoolType;

@Value("${cmdPoolSize}")
private int cmdPoolSize;

...

if (cmdPoolType.equals("cached")) {
  cmdPool = Executors.newCachedThreadPool();
} else if (cmdPoolType.equals("fixed")) {
  cmdPool = Executors.newFixedThreadPool(cmdPoolSize);  
}

在哪里选择合理的可用池。

在最后一种情况下,您还可以使用 spring 配置文件并在启动应用程序之前对其进行更改。


推荐阅读