Puma เป็น เซิร์ฟเวอร์ HTTP 1.1 ที่ใช้งานง่าย รวดเร็ว แบบมัลติเธรด และขนานสูงสำหรับแอปพลิเคชัน Ruby/Rack
Puma เป็นเซิร์ฟเวอร์สำหรับแอปพลิเคชัน HTTP แบบแร็คที่เขียนด้วยภาษา Ruby มันคือ:
เดิมทีได้รับการออกแบบให้เป็นเซิร์ฟเวอร์สำหรับ Rubinius แต่ Puma ยังทำงานได้ดีกับ Ruby (MRI) และ JRuby
บน MRI มี Global VM Lock (GVL) ที่ทำให้แน่ใจว่ามีเธรดเดียวเท่านั้นที่สามารถเรียกใช้โค้ด Ruby ได้ในแต่ละครั้ง แต่ถ้าคุณทำการบล็อก IO เป็นจำนวนมาก (เช่น การเรียก HTTP ไปยัง API ภายนอก เช่น Twitter) Puma ยังคงปรับปรุงปริมาณงานของ MRI โดยปล่อยให้ IO รอดำเนินการแบบคู่ขนาน การใช้งาน 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
ในการดำเนินการนี้ คุณต้องเพิ่มไฟล์แร็คอัปลงในแอป Sinatra ของคุณ:
# config.ru
require './app'
run Sinatra :: Application
จากนั้นคุณสามารถเริ่มแอปพลิเคชันของคุณโดยใช้:
$ bundle exec puma
Puma มีตัวเลือกมากมาย ปรึกษา puma -h
(หรือ puma --help
) เพื่อดูรายการตัวเลือก CLI ทั้งหมด หรือดู Puma::DSL
หรือ dsl.rb
คุณยังดูตัวอย่างการกำหนดค่าต่างๆ ได้จากชุดทดสอบอีกด้วย
เพื่อวัตถุประสงค์ในการแก้ไขจุดบกพร่อง คุณสามารถตั้งค่าตัวแปรสภาพแวดล้อม PUMA_LOG_CONFIG
ด้วยค่าได้ และการกำหนดค่าที่โหลดจะถูกพิมพ์เป็นส่วนหนึ่งของกระบวนการบูต
Puma ใช้เธรดพูล คุณสามารถตั้งค่าจำนวนเธรดขั้นต่ำและสูงสุดที่มีอยู่ในพูลด้วยแฟล็ก -t
(หรือ --threads
):
$ puma -t 8:32
Puma จะปรับขนาดจำนวนเธรดโดยอัตโนมัติจากขั้นต่ำไปจนถึงสูงสุด โดยขึ้นอยู่กับปริมาณการรับส่งข้อมูลที่มีอยู่ ค่าเริ่มต้นปัจจุบันคือ 0:16
และใน MRI คือ 0:5
คุณสามารถทดลองใช้งานได้ แต่ระวังอย่าตั้งค่าจำนวนเธรดสูงสุดเป็นจำนวนมาก เนื่องจากคุณอาจใช้ทรัพยากรในระบบหมด (หรือทำให้เกิดการโต้แย้งสำหรับ Global VM Lock เมื่อใช้ 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
thread เป็นแบบต่อผู้ปฏิบัติงาน ดังนั้น -w 2 -t 16:16
จะสร้างเธรดทั้งหมด 32 เธรด โดยมี 16 เธรดในกระบวนการของผู้ปฏิบัติงานแต่ละราย
หากตัวแปรสภาพแวดล้อม WEB_CONCURRENCY
ถูกตั้งค่าเป็น "auto"
และมี gem 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 จะจัดเตรียม hooks before_fork
และ on_worker_boot
เพื่อเรียกใช้โค้ดเมื่อบูตกระบวนการหลักและพนักงานย่อยตามลำดับ
ขอแนะนำให้ใช้ hooks เหล่านี้กับ preload_app!
มิฉะนั้นค่าคงที่ที่โหลดโดยแอปพลิเคชันของคุณ (เช่น Rails
) จะไม่สามารถใช้ได้ภายใน hooks
# 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
hook ซึ่งใช้ในโหมด fork_worker
เท่านั้น เมื่อกระบวนการของผู้ปฏิบัติงาน 0 ลูกแยกผู้ปฏิบัติงานหลาน:
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 จัดเตรียม hooks วงจรการใช้งานกระบวนการหลัก 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
gem สำหรับการใช้งานในการพัฒนา): Puma รองรับ localhost
gem สำหรับใบรับรองที่ลงนามด้วยตนเอง สิ่งนี้มีประโยชน์อย่างยิ่งหากคุณต้องการใช้ Puma กับ SSL ภายในเครื่อง และใบรับรองที่ลงนามเองจะใช้ได้กับกรณีการใช้งานของคุณ ปัจจุบันการบูรณาการสามารถใช้ได้เฉพาะใน MRI เท่านั้น
Puma กำหนดค่า SSL โดยอัตโนมัติเมื่อโหลด localhost
gem ในสภาพแวดล้อม development
:
เพิ่มอัญมณีลงใน Gemfile ของคุณ:
group ( :development ) do
gem 'localhost'
end
และต้องการมันโดยปริยายโดยใช้ Bundler:
require "bundler"
Bundler . require ( :default , ENV [ "RACK_ENV" ] . to_sym )
หรือคุณสามารถกำหนดให้ gem ในไฟล์การกำหนดค่าของคุณ 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 จะเริ่มเซิร์ฟเวอร์ควบคุมบนพอร์ต localhost 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 สามารถพบได้ในเอกสารประกอบของ Signals
บางแพลตฟอร์มไม่รองรับฟีเจอร์ 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 ยังรองรับการสร้าง daemonization ในตัวผ่านอัญมณีทับทิม puma-daemon เจมจะกู้คืนตัวเลือก daemonize
ที่ถูกลบออกจาก Puma โดยเริ่มต้นเวอร์ชัน 5 แต่สำหรับ MRI Ruby เท่านั้น
เป็นเรื่องปกติที่จะใช้การตรวจสอบกระบวนการกับ Puma การตรวจสอบกระบวนการสมัยใหม่ เช่น systemd หรือ rc.d ให้การตรวจสอบอย่างต่อเนื่องและการรีสตาร์ทเพื่อเพิ่มความน่าเชื่อถือในสภาพแวดล้อมการผลิต:
คู่มือชุมชน:
ค้นหารายละเอียดสำหรับการบริจาคได้ในคู่มือการบริจาค
Puma เป็นลิขสิทธิ์ของ Evan Phoenix และผู้มีส่วนร่วม ซึ่งได้รับอนุญาตภายใต้ใบอนุญาต BSD 3-Clause ดูไฟล์ใบอนุญาตที่ให้มาเพื่อดูรายละเอียด