На самом деле у Puma есть два параметра: количество потоков и количество рабочих. Если немного изменить значение по умолчанию puma.rb
, это будет выглядеть так:
# WORKERS_NUM is not a default env variable name
workers Integer(ENV['WORKERS_NUM'] || 1)
max_threads_count = Integer(ENV['RAILS_MAX_THREADS'] || 1)
min_threads_count = max_threads_count
threads min_threads_count, max_threads_count
Количество рабочих - это количество отдельных процессов, которые Puma запускает для вас. Обычно рекомендуется устанавливать его равным количеству ядер процессора на вашем сервере. Вы можете создать больше из них, чтобы обеспечить одновременную обработку большего количества запросов, но рабочие создают дополнительные накладные расходы на память - каждый рабочий запускает копию вашего приложения rails, поэтому обычно вы должны использовать потоки для достижения более высокой пропускной способности.
RAILS_MAX_THREADS
- это способ установить количество потоков, которые каждый из ваших воркеров будет использовать под капотом. В приведенном выше примере min_threads_count
равно max_threads_count
, поэтому количество потоков постоянно. Если вы установите их разные, он будет масштабироваться от минимума до максимума, но я не видел этого в дикой природе.
Есть несколько причин ограничить количество потоков - ваш интерпретатор и время ответа:
- Если вы используете MRI, ваши потоки ограничены GIL, поэтому они не работают параллельно. МРТ имитирует параллельное выполнение путем переключения контекста. Большое количество потоков позволит использовать гораздо больше одновременных подключений, но среднее время отклика увеличится из-за GIL.
- Ограничения платформы: т.е. heroku имеет ограничения на количество потоков https://devcenter.heroku.com/articles/dynos#process-thread-limits, Linux ограничивает только количество процессов Максимальное количество потоков на процесс в Linux?.
- Когда код не является потокобезопасным, есть вероятность, что использование более одного потока приведет к непредсказуемым проблемам. На самом деле это мой случай, поэтому я особо не экспериментировал с количеством потоков.
Также был аргумент, что медленный ввод-вывод блокирует процесс ruby и не позволяет переключение контекста (то есть вызовы внешних служб или создание больших файлов на лету), но оказалось, что это не так http://yehudakatz.com/2010/08/14/threads-in-ruby-enough-already/. Но оптимизация вашей архитектуры для выполнения как можно большего объема работы в фоновом режиме - это всегда хорошая идея.
Этот ответ поможет вам найти идеальную комбинацию количества потоков и количества рабочих процессов с учетом вашего оборудования.
Это показывает, как можно проводить сравнительный анализ сделано, чтобы найти точные числа.
Подводя итог: умножение WORKERS_NUM
на RAILS_MAX_THREADS
дает максимальное количество одновременных подключений, которые может обрабатывать puma. Если число слишком мало, ваши пользователи увидят тайм-ауты во время скачков нагрузки. Для достижения максимальной производительности при использовании MRI вам необходимо установить WORKERS_NUM
на количество ядер и найти оптимальное RAILS_MAX_THREADS
на основе среднего времени отклика во время тестов производительности.
person
Nikolay Shebanov
schedule
18.05.2017