使用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个最大连接数和8000个最大IOPS。
您可能需要考虑其他一些参数:1.数据库的最大并发请求参数。云提供商对不同层的并发请求有不同的限制,您可能需要检查一下。2.当您说50-200 ms时,虽然很难说,但平均有8个50ms的请求和2个200ms的请求,还是全部差不多?为什么?您的doQuery可能受到查询所用的最长时间(即200毫秒)的限制,但是耗时50毫秒的线程将在任务完成后释放,以使它们可用于下一组请求。3.您期望获得什么QPS?
一些计算:如果单个请求占用10个线程,并且您已为100个连接设置了100个并发查询限制,则假设每个查询为200ms,则一次只能处理10个请求(对于此应用程序的单个实例)。如果大多数查询花费50毫秒左右的时间,也许比10好一点(但我不会感到乐观)。
当然,如果您的任何查询花费> 200毫秒(网络等待时间或其他任何时间),这些计算中的一部分都会折腾,在这种情况下,我建议您在连接端有一个断路器(如果允许的话)在超时后或在API结束中止查询。
注:最大连接限制与最大并发查询限制不同。
建议:由于您需要在500毫秒以下响应,因此池上的连接超时也可能约为100-150毫秒。最坏的情况:150毫秒的连接超时+ 200毫秒的查询执行+ 100毫秒的应用程序处理<500毫秒的响应时间。作品。