Как понять, что проблема в базе данных или в сервисе
Что проверяют
Умеете ли вы локализовать проблему по данным, а не по ощущениям, и знаете ли звенья между сервисом и базой: пул соединений, ORM, транзакции. Типичный уточняющий вопрос: база отвечает быстро, а сервис тормозит, где искать.
Как отвечать
Задача сводится к тому, чтобы разложить время запроса на части:
- трассировка: OpenTelemetry или Micrometer Tracing в Spring Boot показывают спаны JDBC-вызовов внутри запроса. Если из 2 секунд 1,8 уходит на один SQL, подозреваемый ясен;
- метрики пула: HikariCP через Actuator отдаёт число активных и ожидающих соединений и время получения соединения. Очередь за соединением при спокойной базе значит, что проблема в сервисе: пул мал или его держат долгие транзакции;
- thread dump:
jcmd <pid> Thread.printилиjstack. Потоки вHikariPool.getConnectionждут пул, потоки в чтении сокета внутри JDBC-драйвера ждут базу, потоки вBLOCKEDна своих мониторах указывают на сервис; - сторона базы: в PostgreSQL это
pg_stat_activity(что выполняется и чего ждёт, включая блокировки),pg_stat_statements(самые дорогие запросы) иEXPLAIN (ANALYZE, BUFFERS). Если в базе запрос быстрый, а в трейсе долгий, тормозит сеть или сервис; - JVM: паузы GC видны в GC-логах и метрике
jvm.gc.pause. Во время длинной паузы медленными выглядят все запросы, хотя база ни при чём.
Отдельно проверьте ORM. Hibernate с проблемой N+1 делает сотни быстрых запросов вместо одного: каждый быстрый, а в сумме секунды. Включите hibernate.generate_statistics или лог SQL на стенде и посчитайте запросы на операцию.
Где спотыкаются
Запускают запрос в SQL-клиенте, видят 10 мс и объявляют базу невиновной. В приложении тот же запрос идёт с другими параметрами, может получить другой план или ждать соединение из пула.
Сразу увеличивают пул. Если база уже перегружена, лишние соединения сделают хуже; пул в сотни соединений на PostgreSQL обычно ошибка.
Держат @Transactional на время внешнего HTTP-вызова. Соединение занято, пока идёт чужой запрос, и пул кончается при здоровой базе.