Как оптимизировать соединения Postgresql max и пул соединений node-postgres?

короче говоря, у меня возникли проблемы с поддержкой более 5000 запросов на чтение в минуту от API данных, использующего Postgresql, Node.js, и узел-postgres. Узкое место, по-видимому, находится между API и БД. Вот детали реализации.

Я использую экземпляр базы данных AWS Postgresql RDS (m4.4xlarge-64 GB mem, 16 vCPUs, 350 GB SSD, нет подготовленных IOPS)для узла. JS powered data API. По умолчанию max_connections RDS=5000. Узел API балансируется через два кластера с 4 процессами каждый (2 Ec2s с 4 vCPUs, выполняющими API с PM2 в режиме кластера). Я использую узел-postgres чтобы привязать API к Postgresql RDS, и я пытаюсь использовать его функцию пула соединений. Ниже приведен пример кода пула соединений:

var pool = new Pool({
    user: settings.database.username,
    password: settings.database.password,
    host: settings.database.readServer,
    database: settings.database.database,
    max: 25, 
    idleTimeoutMillis: 1000
});

/* Example of pool usage */
pool.query('SELECT my_column FROM my_table', function(err, result){

    /* Callback code here */
});

используя эту реализацию и тестирование с помощью нагрузочного тестера, я могу поддерживать около 5000 запросов в течение одной минуты со средним временем отклика около 190ms (что я ожидать.) Как только я запускаю более 5000 запросов в минуту, мое время ответа увеличивается до более чем 1200 МС в лучшем случае, а в худшем случае API начинает часто тайм-аут. Мониторинг указывает, что для EC2s работает узел.JS API, загрузка ЦП остается ниже 10%. Таким образом, мое внимание сосредоточено на БД и привязке API к БД.

Я попытался увеличить (и уменьшить, если на то пошло) настройку соединений node-postgres "max", но не было изменение поведения ответа/тайм-аута API. Я также пробовал подготовленные IOPS на RDS, но никаких улучшений. Кроме того, интересно, что я увеличил RDS до m4.10xlarge (160 GB mem, 40 vCPUs), и в то время как загрузка процессора RDS значительно снизилась, общая производительность API значительно ухудшилась (не могла даже поддерживать 5000 запросов в минуту, которые я смог с меньшим RDS).

Я на незнакомой территории во многих отношениях и не уверен, как лучше всего определить, какой из эти движущиеся части являются узким местом производительности API, когда более 5000 запросов в минуту. Как уже отмечалось, я попытался выполнить различные корректировки на основе обзора документации по конфигурации Postgresql и документации node-postgres, но безрезультатно.

Если у кого-то есть советы о том, как диагностировать или оптимизировать, я был бы очень признателен.

обновление

после масштабирования до m4.10xlarge, я выполнил серию нагрузочных испытаний, меняя количество запросов / мин и максимальное количество подключений в каждом пуле. Вот некоторые снимки экрана мониторинга метрик:

monitoring metrics

db connections

3 ответов


для того, чтобы поддерживать более 5k запросов, сохраняя ту же скорость ответа, вам понадобится лучшее оборудование...

простая математика утверждает, что: 5000 requests*190ms avg = 950k ms divided into 16 cores ~ 60k ms per core который в основном означает, что ваша система была сильно загружена.
(Я предполагаю, что у вас был запасной процессор, так как некоторое время было потеряно в сети)

теперь, действительно интересная часть в вашем вопросе исходит из попытки масштабирования: m4.10xlarge (160 GB mem, 40 vCPUs).
Падение использования ЦП указывает, что масштабирование освобожденных ресурсов времени БД-так что вам нужно нажать больше запросов!
2 предложения:

  • попробуйте увеличить пул соединений до max: 70 и посмотрите на сетевой трафик (в зависимости от объема данных, которые вы можете использовать в сети)
  • кроме того, ваши запросы к DB a-sync со стороны приложения? убедитесь, что ваше приложение действительно может нажимать больше запросов.

по моему опыту, лучшее, что может сделать служба API, - это использовать отдельный Pool для каждого вызова API в соответствии с приоритетом вызова:

var highPriority = new Pool({...max: 20}); // for high-priority API calls
var lowPriority = new Pool({...max: 5}); // for low-priority API calls

затем вы просто используете правильный пул для каждого из вызовов API для оптимальной доступности службы.


поскольку вас интересует производительность чтения, можно настроить репликацию между двумя (или более) экземплярами PostgreSQL, а затем использовать pgpool II для балансировки нагрузки между экземплярами.

масштабирование по горизонтали означает, что вы не начнете использовать максимальные размеры экземпляров в AWS, если решите на следующей неделе перейти на 10 000 одновременных чтений.

вы также начинаете получать некоторые HA в своей архитектуре.

--

много раз люди будут использовать pgbouncer в качестве пула соединений, даже если он уже встроен в код приложения. pgbouncer работает очень хорошо и обычно проще настроить и управлять этим pgpool, но он не выполняет балансировку нагрузки. Я не уверен, что это очень поможет вам в этом сценарии.