Puma — это простой, быстрый, многопоточный и высокопараллельный HTTP 1.1-сервер для приложений Ruby/Rack .
Puma — это сервер для стоечных HTTP-приложений, написанный на Ruby. Это:
Первоначально разработанный как сервер для Rubinius, Puma также хорошо работает с Ruby (MRI) и JRuby.
В MRI существует глобальная блокировка VM (GVL), которая гарантирует, что только один поток может одновременно выполнять код Ruby. Но если вы часто блокируете ввод-вывод (например, HTTP-вызовы к внешним API, таким как Twitter), Puma все равно улучшает пропускную способность MRI, позволяя выполнять ожидание ввода-вывода параллельно. По-настоящему параллельные реализации Ruby (TruffleRuby, JRuby) не имеют этого ограничения.
$ gem install puma
$ puma
Без аргументов puma будет искать файл Rackup (.ru) в рабочем каталоге с именем config.ru
.
Puma установит/скомпилирует с поддержкой SSL-сокетов, при условии, что в системе установлены файлы разработки OpenSSL.
Если в системе не установлены файлы разработки OpenSSL, Puma установит/скомпилирует, но не разрешит SSL-соединения.
Puma — это сервер по умолчанию для Rails, включенный в сгенерированный Gemfile.
Запустите свой сервер с помощью команды rails
:
$ rails server
Многие параметры конфигурации и функции Puma недоступны при использовании rails server
. Вместо этого рекомендуется использовать исполняемый файл Puma:
$ bundle exec puma
Вы можете запустить приложение Sinatra с помощью Puma из командной строки следующим образом:
$ ruby app.rb -s Puma
Однако для того, чтобы фактически настроить Puma с помощью файла конфигурации, например puma.rb
, вам необходимо использовать исполняемый файл puma
. Для этого вам необходимо добавить файл Rackup в ваше приложение Sinatra:
# config.ru
require './app'
run Sinatra :: Application
Затем вы можете запустить свое приложение, используя:
$ bundle exec puma
Puma предлагает множество вариантов. Полный список параметров CLI см. в puma -h
(или puma --help
) или см. Puma::DSL
или dsl.rb.
Вы также можете найти несколько примеров конфигурации в составе набора тестов.
В целях отладки вы можете установить значение переменной среды PUMA_LOG_CONFIG
, и загруженная конфигурация будет распечатана как часть процесса загрузки.
Puma использует пул потоков. Вы можете установить минимальное и максимальное количество потоков, доступных в пуле, с помощью флага -t
(или --threads
):
$ puma -t 8:32
Puma автоматически масштабирует количество потоков от минимального до максимального в зависимости от объема присутствующего трафика. Текущее значение по умолчанию — 0:16
, а на МРТ — 0:5
. Не стесняйтесь экспериментировать, но будьте осторожны и не устанавливайте большое количество максимальных потоков, так как вы можете исчерпать ресурсы системы (или вызвать конфликт за глобальную блокировку виртуальной машины при использовании MRI).
Имейте в виду, что Puma дополнительно создает потоки для внутренних целей (например, для обработки медленных клиентов). Таким образом, даже если вы укажете -t 1:1, ожидайте, что в вашем приложении будет создано около 7 потоков.
Puma также предлагает «кластерный режим». Кластерный режим fork
рабочие процессы от главного процесса. Каждый дочерний процесс по-прежнему имеет свой собственный пул потоков. Вы можете настроить количество воркеров с помощью флага -w
(или --workers
):
$ puma -t 8:32 -w 3
Или с помощью переменной среды WEB_CONCURRENCY
:
$ WEB_CONCURRENCY=3 puma -t 8:32
Обратите внимание, что потоки по-прежнему используются в кластерном режиме, а флаг потока -t
устанавливается для каждого рабочего процесса, поэтому -w 2 -t 16:16
создаст всего 32 потока, по 16 в каждом рабочем процессе.
Если для переменной среды WEB_CONCURRENCY
установлено значение "auto"
и в вашем приложении доступен гем concurrent-ruby
, Puma установит счетчик рабочих процессов в соответствии с количеством доступных процессоров.
Подробное обсуждение компромиссов между настройками количества потоков и процессов см. в нашей документации.
В кластерном режиме Puma может «предварительно загрузить» ваше приложение. При этом загружается весь код приложения перед разветвлением. Предварительная загрузка снижает общее использование памяти вашим приложением с помощью функции операционной системы, называемой копированием при записи.
Если для переменной среды WEB_CONCURRENCY
установлено значение > 1 (и --prune-bundler
не указан), предварительная загрузка будет включена по умолчанию. В противном случае вы можете использовать флаг --preload
из командной строки:
$ puma -w 3 --preload
Или, если вы используете файл конфигурации, вы можете использовать preload_app!
метод:
# config/puma.rb
workers 3
preload_app!
Предварительную загрузку нельзя использовать с поэтапным перезапуском, поскольку при поэтапном перезапуске рабочие процессы убиваются и перезапускаются один за другим, а предварительная загрузка копирует код мастера в рабочие процессы.
При использовании кластерного режима конфигурационный DSL Puma предоставляет перехватчики before_fork
и on_worker_boot
для запуска кода при разветвлении главного процесса и дочерних рабочих процессах соответственно.
Рекомендуется использовать эти хуки с preload_app!
, иначе константы, загруженные вашим приложением (например, Rails
), не будут доступны внутри хуков.
# config/puma.rb
before_fork do
# Add code to run inside the Puma master process before it forks a worker child.
end
on_worker_boot do
# Add code to run inside the Puma worker process after forking.
end
Кроме того, существует перехватчик on_refork
, который используется только в режиме fork_worker
, когда дочерний процесс Worker 0 разветвляет дочернего Worker:
on_refork do
# Used only when fork_worker mode is enabled. Add code to run inside the Puma worker 0
# child process before it forks a grandchild worker.
end
Важно учитывать следующие соображения, когда Ruby разветвляет дочерний процесс:
SocketError
, Errno::EPIPE
и EOFError
.Поэтому мы рекомендуем следующее:
before_fork
и on_refork
для отключения соединений родительского сокета при разветвлении, чтобы они не были случайно скопированы в дочерний процесс.on_worker_boot
для перезапуска любых фоновых потоков на разветвленном дочернем элементе. DSL конфигурации Puma предоставляет перехватчики жизненного цикла главного процесса on_booted
, on_restart
и on_stopped
, которые можно использовать для указания блоков кода, которые будут запускаться при каждом событии:
# config/puma.rb
on_booted do
# Add code to run in the Puma master process after it boots,
# and also after a phased restart completes.
end
on_restart do
# Add code to run in the Puma master process when it receives
# a restart command but before it restarts.
end
on_stopped do
# Add code to run in the Puma master process when it receives
# a stop command but before it shuts down.
end
Если Puma обнаружит ошибку вне контекста вашего приложения, она ответит кодом 400/500 и простым текстовым сообщением об ошибке (см. Puma::Server#lowlevel_error
или server.rb). Вы можете указать собственное поведение для этого сценария. Например, вы можете сообщить об ошибке в стороннюю службу отслеживания ошибок (в данном примере — в полосу прокрутки):
lowlevel_error_handler do | e , env , status |
if status == 400
message = "The server could not process the request due to an error, such as an incorrectly typed URL, malformed syntax, or a URL that contains illegal characters. n "
else
message = "An error has occurred, and engineers have been informed. Please reload the page. If you continue to have problems, contact [email protected] n "
Rollbar . critical ( e )
end
[ status , { } , [ message ] ]
end
Привяжите Puma к сокету с помощью флага -b
(или --bind
):
$ puma -b tcp://127.0.0.1:9292
Чтобы использовать сокет UNIX вместо TCP:
$ puma -b unix:///var/run/puma.sock
Если вам нужно изменить разрешения сокета UNIX, просто добавьте параметр umask:
$ puma -b 'unix:///var/run/puma.sock?umask=0111'
Вам нужно немного безопасности? Используйте SSL-сокеты:
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert'
localhost
, для использования в целях разработки): Puma поддерживает драгоценный камень localhost
для самозаверяющих сертификатов. Это особенно полезно, если вы хотите использовать Puma с SSL локально, и для вашего случая подойдут самозаверяющие сертификаты. В настоящее время интеграцию можно использовать только в МРТ.
Puma автоматически настраивает SSL, когда гем localhost
загружается в среду development
:
Добавьте драгоценный камень в свой Gemfile:
group ( :development ) do
gem 'localhost'
end
И потребуйте это неявно с помощью упаковщика:
require "bundler"
Bundler . require ( :default , ENV [ "RACK_ENV" ] . to_sym )
Альтернативно, вы можете запросить драгоценный камень в своем файле конфигурации, либо config/puma/development.rb
, config/puma.rb
, либо установить его с помощью опции -C
cli:
require 'localhost'
# configuration methods (from Puma::DSL) as needed
Кроме того, Puma должна прослушивать сокет SSL:
$ puma -b ' ssl://localhost:9292 ' -C config/use_local_host.rb
# The following options allow you to reach Puma over HTTP as well:
$ puma -b ssl://localhost:9292 -b tcp://localhost:9393 -C config/use_local_host.rb
Чтобы использовать или избегать определенных шифров SSL для TLSv1.2 и ниже, используйте параметры ssl_cipher_filter
или ssl_cipher_list
.
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&ssl_cipher_filter=!aNULL:AES+SHA'
$ puma -b 'ssl://127.0.0.1:9292?keystore=path_to_keystore&keystore-pass=keystore_password&ssl_cipher_list=TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA'
Чтобы настроить доступные наборы шифров TLSv1.3, используйте опцию ssl_ciphersuites
(недоступно для JRuby).
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&ssl_ciphersuites=TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256'
См. https://www.openssl.org/docs/man1.1.1/man1/ciphers.html для формата фильтра шифра и полного списка наборов шифров.
Отключите TLS v1 с помощью опции no_tlsv1
:
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&no_tlsv1=true'
Чтобы включить флаги проверки, предлагаемые OpenSSL, используйте verification_flags
(недоступно для JRuby):
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&verification_flags=PARTIAL_CHAIN'
Вы также можете установить несколько флагов проверки (разделив их запятой):
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&verification_flags=PARTIAL_CHAIN,CRL_CHECK'
Список доступных флагов: USE_CHECK_TIME
, CRL_CHECK
, CRL_CHECK_ALL
, IGNORE_CRITICAL
, X509_STRICT
, ALLOW_PROXY_CERTS
, POLICY_CHECK
, EXPLICIT_POLICY
, INHIBIT_ANY
, INHIBIT_MAP
, NOTIFY_POLICY
, EXTENDED_CRL_SUPPORT
, USE_DELTAS
, CHECK_SS_SIGNATURE
, TRUSTED_FIRST
, SUITEB_128_LOS_ONLY
, SUITEB_192_LOS
, SUITEB_128_LOS
, PARTIAL_CHAIN
, NO_ALT_CHAINS
, NO_CHECK_TIME
(см. https://www.openssl.org/docs/manmaster/man3/X509_VERIFY_PARAM_set_hostflags.html#VERIFICATION-FLAGS).
Чтобы включить расшифровку зашифрованного SSL-ключа во время выполнения (недоступно для JRuby), используйте key_password_command
:
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&key_password_command=/path/to/command.sh'
key_password_command
должен:
Например:
#! /bin/sh
echo " this is my password "
key_password_command
можно использовать с key
или key_pem
. Если ключ не зашифрован, исполняемый файл не будет вызываться.
У Puma есть встроенное приложение для управления статусом и контролем, которое можно использовать для запроса и управления Puma.
$ puma --control-url tcp://127.0.0.1:9293 --control-token foo
Puma запустит сервер управления на локальном порту 9293. Все запросы к серверу управления должны будут включать токен управления (в данном случае token=foo
) в качестве параметра запроса. Это обеспечивает простую аутентификацию. Посетите Puma::App::Status
или status.rb, чтобы узнать, что доступно в приложении статуса.
Вы также можете взаимодействовать с сервером управления через pumactl
. Эта команда перезапустит Puma:
$ pumactl --control-url 'tcp://127.0.0.1:9293' --control-token foo restart
Чтобы просмотреть список параметров pumactl
, используйте pumactl --help
.
Вы также можете предоставить файл конфигурации с флагом -C
(или --config
):
$ puma -C /path/to/config
Если файл конфигурации не указан, Puma будет искать файл конфигурации в config/puma.rb
. Если среда указана (с помощью флага --environment
или через переменные среды APP_ENV
, RACK_ENV
или RAILS_ENV
), Puma ищет файл конфигурации в config/puma/<environment_name>.rb
, а затем возвращается к config/puma.rb
.
Если вы хотите запретить Puma искать файл конфигурации в этих местах, включите флаг --no-config
:
$ puma --no-config
# or
$ puma -C "-"
Другими побочными эффектами настройки среды являются необходимость отображения трассировок стека (при development
или test
), а установка RACK_ENV потенциально может повлиять на промежуточное программное обеспечение, которое ищет это значение, чтобы изменить свое поведение. Значение puma RACK_ENV по умолчанию — development
. Вы можете увидеть все значения конфигурации по умолчанию в Puma::Configuration#puma_default_options
или Configuration.rb.
Посетите Puma::DSL
или dsl.rb, чтобы увидеть все доступные варианты.
Puma включает в себя возможность перезагрузки. При доступности (MRI, Rubinius, JRuby) Puma выполняет «горячий перезапуск». Это та же функциональность, которая доступна в Unicorn и NGINX , которые сохраняют сокеты сервера открытыми между перезапусками. Это гарантирует, что во время перезапуска никакие ожидающие запросы не будут удалены.
Дополнительные сведения см. в документации по перезапуску.
Puma реагирует на несколько сигналов. Подробное руководство по использованию сигналов UNIX с Puma можно найти в документации по сигналам.
Некоторые платформы поддерживают не все функции Puma.
Для версий MRI 2.2.7, 2.2.8, 2.2.9, 2.2.10, 2.3.4 и 2.4.1 вы можете увидеть stream closed in another thread (IOError)
. Это может быть вызвано ошибкой Ruby. Это можно исправить с помощью гема https://rubygems.org/gems/stopgap_13632:
if %w( 2.2.7 2.2.8 2.2.9 2.2.10 2.3.4 2.4.1 ) . include? RUBY_VERSION
begin
require 'stopgap_13632'
rescue LoadError
end
end
У Puma есть поддержка Capistrano с помощью внешнего драгоценного камня.
Кроме того, Puma поддерживает встроенную демонизацию с помощью рубинового камня puma-daemon. Гем восстанавливает опцию daemonize
, которая была удалена из Puma, начиная с версии 5, но только для MRI Ruby.
С Puma обычно используются мониторы процессов. Современные мониторы процессов, такие как systemd или rc.d, обеспечивают непрерывный мониторинг и перезапуски для повышения надежности в производственных средах:
Руководства сообщества:
Подробную информацию о вкладе можно найти в руководстве по вкладам.
Авторские права на Puma принадлежат Эвану Фениксу и его участникам и действуют по лицензии BSD 3-Clause. Подробности смотрите в прилагаемом файле ЛИЦЕНЗИИ.