Puma 是一個簡單、快速、多執行緒、高度並行的 HTTP 1.1 伺服器,適用於 Ruby/Rack 應用程式。
Puma 是一個用 Ruby 編寫的、用於 Rack 驅動的 HTTP 應用程式的伺服器。這是:
Puma 最初設計為 Rubinius 的伺服器,也可以與 Ruby (MRI) 和 JRuby 很好地配合。
在 MRI 上,有一個全域 VM 鎖 (GVL),可確保一次只有一個執行緒可以執行 Ruby 程式碼。但如果您正在進行大量阻塞 IO(例如對 Twitter 等外部 API 的 HTTP 呼叫),Puma 仍然可以透過允許並行完成 IO 等待來提高 MRI 的吞吐量。真正並行的 Ruby 實作(TruffleRuby、JRuby)沒有這個限制。
$ gem install puma
$ puma
如果沒有參數,puma 會在名為config.ru
的工作目錄中尋找rackup (.ru) 檔案。
假設系統上安裝了 OpenSSL 開發文件,Puma 將安裝/編譯並支援 ssl 套接字。
如果系統沒有安裝 OpenSSL 開發文件,Puma 將安裝/編譯,但不允許 ssl 連線。
Puma 是 Rails 的預設伺服器,包含在產生的 Gemfile 中。
使用rails
命令啟動伺服器:
$ rails server
使用rails server
時,許多配置選項和 Puma 功能不可用。建議您使用 Puma 的可執行檔:
$ bundle exec puma
您可以從命令列使用 Puma 運行 Sinatra 應用程序,如下所示:
$ ruby app.rb -s Puma
然而,為了使用設定檔(如puma.rb
實際設定 Puma,您需要使用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
,MRI 上的預設值為0:5
。請隨意嘗試,但請注意不要將最大執行緒數設定為很大的數字,因為您可能會耗盡系統上的資源(或在使用 MRI 時導致全域 VM 鎖定爭用)。
請注意,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
gem 在您的應用程式中可用,Puma 會將工作進程計數設定為可用處理器的結果。
有關線程和進程計數設定的權衡的深入討論,請參閱我們的文件。
在叢集模式下,Puma 可以「預先載入」您的應用程式。這會在分叉之前載入所有應用程式程式碼。預先載入透過稱為寫入時複製的作業系統功能減少應用程式的總記憶體使用量。
如果WEB_CONCURRENCY
環境變數設定為值 > 1(且未指定--prune-bundler
),則預設會啟用預先載入。否則,您可以從命令列使用--preload
標誌:
$ puma -w 3 --preload
或者,如果您使用設定文件,則可以使用preload_app!
方法:
# config/puma.rb
workers 3
preload_app!
預先載入不能與分階段重啟一起使用,因為分階段重啟會逐一殺死並重啟worker,而預先載入會將master的程式碼複製到worker中。
當使用叢集模式時,Puma 的設定 DSL 提供before_fork
和on_worker_boot
鉤子,分別在主進程 fork 和子進程啟動時執行程式碼。
建議將這些鉤子與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 fork 子進程時請注意以下注意事項:
SocketError
、 Errno::EPIPE
和EOFError
。因此,我們建議如下:
before_fork
和on_refork
斷開父程序的socket連接,這樣它們就不會被意外複製到子程序。on_worker_boot
重新啟動分叉子程序上的任何後台執行緒。 Puma 的設定 DSL 提供主進程生命週期掛鉤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)。您可以為此場景指定自訂行為。例如,您可以向第三方錯誤追蹤服務(在此範例中為 rollbar)報告錯誤:
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
使用-b
(或--bind
)標誌將 Puma 綁定到套接字:
$ 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
gem,供開發使用): Puma 支援使用localhost
gem 進行自簽名憑證。如果您想在本機上使用帶有 SSL 的 Puma,並且自簽名憑證適用於您的用例,這尤其有用。目前,該整合只能用於 MRI。
當localhost
gem 在development
環境中載入時,Puma 會自動設定 SSL:
將 gem 新增到您的 Gemfile 中:
group ( :development ) do
gem 'localhost'
end
並使用捆綁器隱式要求它:
require "bundler"
Bundler . require ( :default , ENV [ "RACK_ENV" ] . to_sym )
或者,您可以在設定檔config/puma/development.rb
、 config/puma.rb
中要求 gem,或透過-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
若要使用或避免 TLSv1.2 及更低版本的特定 SSL 密碼,請使用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。
使用no_tlsv1
選項停用 TLS v1:
$ 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
EXTENDED_CRL_SUPPORT
CRL_CHECK_ALL
、 IGNORE_CRITICAL
、 X509_STRICT
、 ALLOW_PROXY_CERTS
INHIBIT_MAP
POLICY_CHECK
、 EXPLICIT_POLICY
、 INHIBIT_ANY
、 AS 、 CHECK_SS_SIGNATURE
、 TRUSTED_FIRST
NOTIFY_POLICY
SUITEB_128_LOS_ONLY
、 SUITEB_192_LOS
、 SUITEB_128_LOS
、 PARTIAL_CHAIN
、 NO_ALT_CHAINS
USE_DELTAS
NO_CHECK_TIME
/ //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 將在本機主機token=foo
埠 9293 上啟動控制伺服器。這允許簡單的身份驗證。查看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 對多種訊號做出反應。有關在 Puma 中使用 UNIX 訊號的詳細指南可以在訊號文件中找到。
某些平台不支援所有 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 bug 引起的。它可以用 gem 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 透過外部 gem 支持 Capistrano。
此外,Puma 透過 puma-daemon ruby gem 支援內建守護程式。 gem 恢復了從 Puma 版本 5 開始刪除的daemonize
選項,但僅適用於 MRI Ruby。
在 Puma 中使用進程監視器是很常見的。現代進程監視器(如 systemd 或 rc.d)提供連續監控和重新啟動,以提高生產環境的可靠性:
社區指南:
在貢獻指南中尋找貢獻詳細資訊。
Puma 的版權歸 Evan Phoenix 及其貢獻者所有,並根據 BSD 3-Clause 許可證獲得許可。有關詳細信息,請參閱隨附的許可證文件。