Какие проблемы возникают при большом количестве запросов к базе данных
Что проверяют
Понимаете ли вы, во что на самом деле упирается сервис под нагрузкой: в соединения, в блокировки или в сами запросы. Для Go-разработчика ключевая часть ответа это настройка пула в database/sql. Следом обычно спрашивают, как уменьшить число запросов, не трогая саму базу.
Как отвечать
Разложите проблемы по слоям:
- исчерпание соединений: у PostgreSQL по умолчанию
max_connections = 100, и каждое соединение это отдельный процесс со своей памятью. Десяток подов с неограниченным пулом легко выбирают лимит, дальше ошибкаtoo many clients; - пул по умолчанию: в
database/sqlзначениеSetMaxOpenConnsпо умолчанию 0, то есть без ограничения, аSetMaxIdleConnsвсего 2. Под всплесками это постоянное открытие и закрытие соединений. Задавайте лимиты явно, плюсSetConnMaxLifetimeиSetConnMaxIdleTime, или беритеpgxpool; - утечки соединений: забытый
rows.Close()или не дочитанный до конца результат держит соединение, и пул тихо пустеет; - блокировки: частые
UPDATEодних и тех же строк выстраиваются в очередь, растут долгие транзакции и дедлоки; - N+1 и мелкие запросы: сотня запросов в цикле вместо одного с
WHERE id = ANY($1)или пачки черезpgx.Batch. Сетевой круг часто стоит дороже самого запроса.
Решения называйте в порядке цены: убрать лишние запросы и оптимизировать тяжёлые по pg_stat_statements, затем кэш (в памяти процесса или Redis) для горячих данных, пулер вроде PgBouncer перед базой, реплики для чтения. Шардинг идёт последним. Обязательно упомяните таймауты: каждый запрос через QueryContext с context.WithTimeout, иначе зависшая база держит горутины и соединения бесконечно.
Где спотыкаются
Предлагают поднять уровень изоляции, чтобы стало меньше блокировок. Эффект обратный: на SERIALIZABLE растёт число конфликтов и откатов, и приложение должно уметь повторять транзакции.
Сразу уходят в шардинг, не проверив, что половина нагрузки это N+1 из одного обработчика.
Ставят огромный SetMaxOpenConns, считая, что больше соединений значит быстрее. База с сотнями активных соединений работает медленнее, чем с несколькими десятками.