Убедитесь, что максимальное количество подключений к базе данных не превышено с помощью Rails и Sidekiq

Я использую Nginx с Phusion Passenger с однопоточным приложением Rails. Вот в чем загвоздка. В этом приложении я использую многопоточный sidekiq для выполнения некоторых фоновых заданий. Обычно в моем файле database.yml мне нужно установить только значение пула 1. Вот пример:

default: &default
  adapter: mysql2
  encoding: utf8
  collation: utf8_unicode_ci
  pool: 1
  username: username
  password: password
  host: localhost

Причина в том, что для каждого открытого соединения сокета tcp, когда HTTP-запрос приходит через этот сокет, nginx принимает запрос и передает информацию пассажиру. Passenger обнаруживает свое приложение Rails и порождает экземпляр Rails, который преобразует ответ в html, который отправляется обратно в nginx, который затем передается обратно клиенту (браузеру) .Таким образом, для каждого экземпляра пассажира мне понадобится только один подключение к базе данных с помощью однопоточного приложения Rails.

Но в моем sidekiq.yml я установил для параллелизма значение 5:

:concurrency: 5 

Это означает, что для каждого экземпляра пассажирской стойки у меня будет 5 параллельных потоков, обрабатываемых sidekiq, плюс одно соединение для основного приложения, то есть всего 6 подключений к базе данных для одного экземпляра пассажира.

Когда я смотрю на статус пассажира, я замечаю, что max_pool_size установлен на 6:

----------- General information -----------
Max pool size : 6

Значит ли это, что пассажир никогда не будет порождать более 6 экземпляров Rails одновременно? И если это так, означает ли это, что моя математика верна: 6 (экземпляров) * 6 (подключений к базе данных: 5 для sidekiq и 1 для основного приложения) = 36 (общее количество подключений к базе данных, возможных для моего приложения rails для одновременной обработки ).

Сейчас моя база данных mysql настроена на обработку 151 максимального количества одновременных подключений.

SHOW VARIABLES LIKE "max_connections";
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 151   |
+-----------------+-------+

Я просто хочу убедиться, что мои расчеты верны в отношении пассажира, рельсов и sidekiq.


person Donato    schedule 09.09.2016    source источник


Ответы (2)


Прежде всего, ваши процессы Sidekiq и ваш веб-сервер (в вашем случае Passenger) отделены друг от друга. Размер пула потоков пассажира не влияет на параллелизм Sidekiq; вместо этого ваша конфигурация Sidekiq определяет отдельный параллелизм. Итак, мы рассмотрим эти два отдельно:

Пассажир

Значение пула базы данных ActiveRecord - это количество подключений к базе данных, которые ваш веб-процесс будет использовать, всего по всем потокам. Если ваш пассажирский сервер настроен в многопроцессорном режиме, то максимальное количество подключений из ваших веб-процессов составляет db pool size * passenger pool size. С другой стороны, если вы настроите его в многопоточном режиме (который я бы порекомендовал, если это возможно), ваше максимальное количество подключений будет просто db pool size (умноженное на количество запущенных процессов; Puma, например, по умолчанию запускает два процесса до пятнадцати потоков или около того, поэтому максимальное количество соединений в этом случае будет 30).

Итак, если вы используете многопоточный режим, размер пула 1 абсолютно недостаточен - вам понадобится пул по крайней мере такого размера, как вы ожидаете иметь потоки. В многопроцессорном режиме 1 может работать, но я сомневаюсь, что действительно стоит отклоняться от значения по умолчанию 5, пока не возникнут проблемы.

Sidekiq

Sidekiq всегда работает в многопоточном режиме (технически вы также можете запускать несколько процессов, но я предполагаю, что это не так). Итак, как и выше, вы хотите, чтобы ваш пул соединений был не меньше количества потоков. Это может означать, что вам технически нужны два разных значения для вашего значения пула db в зависимости от того, вращается ли env Rails для Passenger или для Sidekiq - см. эта проблема в репозитории Sidekiq или это полезное руководство по Heroku для получения дополнительной информации о том, как решить эту проблему.

В итоге

Не забывайте, что, помимо всего вышеперечисленного, у вас может легко быть несколько серверов, на которых работает одно и то же приложение Rails, но только одна база данных с одним ограничением количества подключений. Если вы используете Passenger в режиме нескольких экземпляров с максимум 6 процессами, установите размер пула базы данных на 5, тогда каждый узел веб-сервера будет использовать до 30 подключений. Если он работает на сервере Sidekiq, добавьте к нему 5. Вам, вероятно, не понадобится более одного сервера Sidekiq, поэтому 4 веб-узла @ 30 подключений + один процесс Sidekiq @ 5 подключений = 125 максимальных подключений, что находится в пределах вашего лимита подключений MySQL.

person Robert Nubel    schedule 09.09.2016
comment
Что подразумевается под «узлом веб-сервера»? Я пробовал погуглить и получил разные толкования. - person Donato; 09.09.2016
comment
@Donato: под узлом, я имею в виду сервер. По мере масштабирования производственных приложений Rails вам часто бывает лучше выделить каждый дополнительный сервер в кластере для определенной цели. Например, web, что означает выполнение вашей rails server команды, известной как Passenger; или worker для вашего сервера Sidekiq. Это всего лишь условность, но я думаю, вы найдете это очень распространенным паттерном. - person Robert Nubel; 09.09.2016
comment
На самом деле, это может помочь, если вы описали свою (предполагаемую или текущую) производственную среду. - person Robert Nubel; 09.09.2016
comment
Также обратите внимание, что пул соединений AR ленив, поэтому вы можете установить pool: 1000, и он будет создавать только столько соединений, сколько необходимо для каждого процесса. - person Mike Perham; 09.09.2016

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

  • HTTP-клиент через TCP отправляет запрос в Nginx

  • Phusion Passenger, загруженный в Nginx, проверяет, должен ли пассажир обрабатывать запрос. Если это так, запрос отправляется в Passenger Core.

  • Ядро пассажира, используя правила балансировки нагрузки, определяет, в какой процесс должен быть перенаправлен запрос.

  • Пассажирское ядро ​​также заботится о порождении приложений: если оно определяет, что наличие большего количества процессов приложения необходимо или полезно, тогда оно будет делать это в соответствии с установленными пользователем ограничениями: ядро ​​никогда не будет порождать больше процессов, чем настроенный пользователем максимум.

  • Пассажирское ядро ​​также имеет мониторинг и статистику: данные о пассажирах и статус пассажира.

  • Ядро Passenger перезапускает процесс приложения в случае его сбоя.

  • UstRouter простаивает и не потребляет ресурсы, если вы не настроили его для отправки данных в Union Station, веб-службу мониторинга.

  • Watchdog контролирует Passenger Core и UstRouter. Если какой-либо из них выйдет из строя, они будут перезапущены Watchdog.

    Passenger-memory-stats проверит три вышеупомянутых процесса, а также порожденные стоечные приложения:

------ Passenger processes ------

PID    VMSize     Private   Name
---------------------------------
18355  419.1 MB   ?         Passenger watchdog
18358  1096.5 MB  ?         Passenger core
18363  427.2 MB   ?         Passenger ust-router
18700  818.9 MB   256.2 MB  Passenger RubyApp: myapp_rack_rails
24783  686.9 MB   180.2 MB  Passenger RubyApp: myapp_rack_rails

Passenger-status показывает, что max_pool_size равен 6. То есть, Passenger Core будет создавать не более 6 стоечных приложений:

----------- General information -----------
Max pool size : 6
App groups    : 2
Processes     : 3

Как указано в другом ответе, значение пула базы данных ActiveRecord - это количество подключений к базе данных, которые будет использовать ваш веб-процесс, в сумме по всем потокам.

Но поскольку я использую бесплатный сервер Passenger, который настроен в многопроцессорном режиме, то мое максимальное количество подключений из моих веб-процессов составляет размер пула db * размер пула пассажиров. Итак, поскольку размер пассажирского пула равен 6, а если размер моего пула БД равен 1, то это 6 * 1 = 6. Это будет 6 максимальных подключений к базе данных.

Sidekiq всегда работает в многопоточном режиме.

Если кто-то хочет использовать sidekiq, он должен настроить количество потоков, в которых он хочет запускаться, или использовать значение по умолчанию (25). Если они используют базу данных (вероятно), то, чтобы не столкнуться с ошибкой тайм-аута подключения, им потребуется как минимум столько же подключений в их пуле базы данных, сколько потоков sidekiq. В настоящее время они должны настроить эти два значения в двух разных местах: пул базы данных в database.yml для ActiveRecord и соединения sidekiq либо через командную строку, либо через файл sidekiq yml. Это проблема, поскольку когда вы изменяете одно значение, сложно запомнить, что вам нужно изменить оба.

person Donato    schedule 10.04.2018