【发布时间】:2020-02-09 15:08:03
【问题描述】:
使用 Hikari 池的 Spring 应用程序。
现在对于来自客户端的单个请求,我必须查询 10 个表(业务需要),然后将结果组合在一起。查询每个表可能需要 50 毫秒到 200 毫秒。为了加快响应时间,我在我的服务中创建了一个FixedThreadPool 来查询不同线程中的每个表(伪代码):
class MyService{
final int THREAD_POOL_SIZE = 20;
final int CONNECTION_POOL_SIZE = 10;
final ExecutorService pool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
protected DataSource ds;
MyClass(){
Class.forName(getJdbcDriverName());
HikariConfig config = new HikariConfig();
config.setMaximumPoolSize(CONNECTION_POOL_SIZE);
ds = new HikariDataSource(config);
}
public Items doQuery(){
String[] tables=["a","b"......]; //10+ tables
Items result=new Items();
CompletionService<Items> executorService = new ExecutorCompletionService<Items>(pool);
for (String tb : tables) {
Callable<Item> c = () -> {
Items items = ds.getConnection().query(tb); ......
return Items;
};
executorService.submit(c);
}
for (String tb: tables) {
final Future<Items> future = executorService.take();
Items items = future.get();
result.addAll(items);
}
}
}
现在对于单个请求,平均响应时间可能为 500 毫秒。
但是对于并发请求,平均响应时间会迅速增加,请求越多,响应时间就会越长。
我想知道如何设置合适的连接池大小和线程池大小以使应用有效工作?
顺便说一句,数据库使用云中的 RDS,具有 4 个 cpu 16GB 内存,最大连接数 2000 和最大 IOPS 8000。
【问题讨论】:
-
如果您发送的每个请求都需要 10 个到数据库的连接,而您的池中只有 10 个连接,那么一次只能处理 1 个请求。您的线程策略可能会增加 一个 请求的响应时间。但是,如果您期望连续的并发请求,按顺序执行操作,没有这种线程策略,可能会更简单、更高效、需要更少的连接、并具有适当的事务隔离语义,从而返回一致的结果。但可以肯定的是,您可以增加池中的连接数,因为您最多可以有 2000 个。
-
您是否尝试在数据库中合成结果?
-
@MarmiteBomber 我们不能在数据库中这样做。
-
@JBNizet:我不知道为什么
Your threading strategy might increase the response time for one request。对于单个请求,我的线程策略将使用 10 个线程,每个线程使用池中的一个连接,我认为这可能会减少响应。 -
对不起,但是用 10 个表做一些事情然后处理数据:这表明数据库应该组合事物和/或一些数据没有以最佳方式组织。此外:summary 数据可以通过数据库触发器来完成。快 10 倍的速度并不能改善索引之类的东西。 (我知道有时无济于事。)
标签: java multithreading jdbc threadpool connection-pooling