Правильный способ определения размера пула соединений - это оставить его по умолчанию.
С веб-сайта hikari :
Если у вас есть 10 000 внешних пользователей, наличие пула соединений в 10 000 будет безумным сдвигом. 1000 все еще ужасно. Даже 100 соединений, перебор. Вам нужен небольшой пул, состоящий максимум из нескольких десятков соединений, и хотите, чтобы остальные потоки приложений были заблокированы в пуле в ожидании соединений. Если пул правильно настроен, он устанавливается прямо на пределе количества запросов, которые база данных способна обрабатывать одновременно - что редко намного больше, чем (ядра ЦП * 2), как отмечено выше.
Если вы знаете, что каждый запрос будет занимать 10 потоков, то вы захотите отказаться от этого совета и перейти к большему количеству потоков - вероятно, если его число будет меньше 100, это обеспечит достаточную емкость.
Я бы реализовал контроллер следующим образом:
Сделайте ваши запросы асинхронными в классах контроллера / службы с CompletableFuture
s и позвольте пулу соединений беспокоиться о том, чтобы его потоки были заняты.
Таким образом, контроллер может выглядеть следующим образом (я адаптирую его из некоторого другого кода, который не работает, как в этом примере, поэтому немного соли с этим кодом):
public class AppController {
@Autowired private DatabaseService databaseService;
public ResponseEntity<Thing> getThing() {
CompletableFuture<Foo> foo = CompletableFuture.runAsync(databaseService.getFoo());
CompletableFuture<Bar> bar = CompletableFuture.runAsync(databaseService.getBar());
CompletableFuture<Baz> baz = CompletableFuture.runAsync(databaseService.getBaz());
// muck around with the completable future to return your data in the right way
// this will be in there somewhere, followed by a .thenApply and .join
CompletableFuture<Void> allFutures = CompletableFuture.allOf(foo, bar, baz);
return new ResponseEntity<Thing>(mashUpDbData(cf.get()));
}
}
Контроллербудет порождать столько потоков, сколько вы разрешите использовать ForkJoinPool
, они будут забивать всю БД одновременно, и пул соединений может беспокоиться о сохранении соединений активными.
Но я думаю, что причина, по которой вы видите всплески времени отклика при небольшой нагрузке, заключается в том, что по своей конструкции JDBC блокирует поток в ожидании возвращения данных из БД.
Чтобы блокировка не влияла на время отклика так сильно, вы можете попробовать стиль реагирующий на пружинную опору . При этом используются асинхронный ввод и обратное давление для согласования производительности ввода-вывода и потребления, в основном это означает, что потоки приложения настолько заняты, насколько это возможно. Это должно остановить это поведение под нагрузкой, когда время отклика увеличивается линейным образом.
Обратите внимание, что если вы идете по реактивному пути, драйверы jdbc по-прежнему блокируются, поэтому у Spring есть большой толчок для создания реактивного драйвера базы данных .