Prefork 模組:
Prefork 模組實作了一個非執行緒、預先分叉 (Pre-fork) 的網頁伺服器。當 httpd 在啟動時就預先 fork 一些子程序來等待請求。優點:較為成熟穩定,兼容所有新舊模組;沒有使用執行緒,可以完全的區隔每一個不同的請求,所以不用擔心執行緒安全的問題。
缺點:每一個子程序相對的會占用更多的系統資源,消耗更多的記憶體;面對高並發 (High Concurrency) 請求時,系統效能會大幅下降。
Worker 模組:
這個模組混合使用多個子程序 (Multi-process) 和多個執行緒 (Multi-threaded)。一個單一控制程序 (父程序) 會預先啟動數個子程序,然後每個子程序會建立一些伺服器執行緒,以及一個監聽執行緒;監聽執行緒負責監聽連線 (Connection),並將連線傳遞給伺服器執行緒進行處理。相較於基於程序的伺服器,因為使用執行緒回應請求,可以有效減少系統資源的使用。優點:使用較少的記憶體、CPU 時間等系統資源,因此相較於 Prefork 模組,較能夠回應高並發請求。
缺點:因為多個執行緒共享父程序的記憶體地址,所以必須考慮執行緒的安全問題;每個執行緒處理一個連線,會有阻塞 (Blocking) 的問題。
Event 模組:
以 Worker 模組為基礎, Event 模組一樣是使用子程序和執行緒處理客戶諯請求;最大的差別在於 Event 模組會為每個 HTTP 請求對應到一個執行緒,而 Worker 模組則是每一個 HTTP 連線(可能會有多個請求)對應到一個執行緒。在 keep-alive1 連線模式下,httpd 傳統上會持續占用整個子程序 / 執行緒來等待客戶端的資料,造成了自身的劣勢。而在 Event 模組中,每一個程序會有一個專門的監聽執行緒來管理兩種不同的監聽插座 (Listening Socket):在 Keep-alive 狀態的所有插座,以及已經處理完畢或是只剩下等待回傳資料給客戶端的插座。因此 Event 模組可以修正 Worker 模組會碰到的 keep-alive 問題。這種架構需要利用非阻塞 (Non-blocking) 插座和現代作業系統內核的輪詢 (Polling) 功能,以避免驚群問題 (Thundering Herd Problem)。
優點:解決了在 keep-alive 情境下,資源被沒有 HTTP 請求的連線長期占用的問題。
註1. 當一個客戶端完成第一項請求時,它可以繼續維持連線,讓後續的請求使用相同的插座 (Socket),節省在建立 TCP 連線時的顯著負擔。
模組設定
下列的指令可以檢查目前的 MPM。
httpd -V
Server version: Apache/2.4.29 (Unix)
Server built: Nov 6 2017 14:32:45
Server's Module Magic Number: 20120211:68
Server loaded: APR 1.6.3, APR-UTIL 1.6.1
Compiled using: APR 1.6.3, APR-UTIL 1.6.1
Architecture: 64-bit
Server MPM: prefork
threaded: no
forked: yes (variable process count)
…
Server built: Nov 6 2017 14:32:45
Server's Module Magic Number: 20120211:68
Server loaded: APR 1.6.3, APR-UTIL 1.6.1
Compiled using: APR 1.6.3, APR-UTIL 1.6.1
Architecture: 64-bit
Server MPM: prefork
threaded: no
forked: yes (variable process count)
…
(預設為使用 prefork 模組)
使用 Homebrew 安裝的 httpd 已經將 3 種模組都預先編譯到套件內了,只需要在 httpd.conf 啟用相關的模組就可以了。例如,要啟用 Event 模組,只需要完成下列的設定:
LoadModule mpm_event_module lib/httpd/modules/mod_mpm_event.so
#LoadModule mpm_prefork_module lib/httpd/modules/mod_mpm_prefork.so
#LoadModule mpm_worker_module lib/httpd/modules/mod_mpm_worker.so
#LoadModule mpm_prefork_module lib/httpd/modules/mod_mpm_prefork.so
#LoadModule mpm_worker_module lib/httpd/modules/mod_mpm_worker.so
重新啟動 httpd,就可以改為 Event 模組:
httpd -V
Server version: Apache/2.4.29 (Unix)
Server built: Nov 8 2017 08:51:12
mac1deiMac:~ timmy$ httpd -V
Server version: Apache/2.4.29 (Unix)
Server built: Nov 8 2017 08:51:12
Server's Module Magic Number: 20120211:68
Server loaded: APR 1.6.3, APR-UTIL 1.6.1
Compiled using: APR 1.6.3, APR-UTIL 1.6.1
Architecture: 64-bit
Server MPM: event
threaded: yes (fixed thread count)
forked: yes (variable process count)
…
Server built: Nov 8 2017 08:51:12
mac1deiMac:~ timmy$ httpd -V
Server version: Apache/2.4.29 (Unix)
Server built: Nov 8 2017 08:51:12
Server's Module Magic Number: 20120211:68
Server loaded: APR 1.6.3, APR-UTIL 1.6.1
Compiled using: APR 1.6.3, APR-UTIL 1.6.1
Architecture: 64-bit
Server MPM: event
threaded: yes (fixed thread count)
forked: yes (variable process count)
…
預設的 MPM
根㨿 httpd 官網,在安裝 MPM 時,主要考慮下列的兩個問題:
1. 系統支援執行緒嗎?
2. 系統支援執行緒安全輪詢 (thread-safe polling)嗎 (特別是 kqueue 以及 epoll 兩個函數)?
如果兩個答案都是肯定的,預設安裝的 MPM 會是 Event 模組;如果只有問題 1 的答案是肯定的,預設的 MPM 會是 Worker 模組;如果兩個答案都是否定的,預設的 MPM 會是 Prefork 模組。因為現代的作業系統都支援這兩個特性,實際上預設的 MPM 都會是 Event 模組。
不過,MPM 的選擇還牽涉到 SAPI 對於 MPM 的支援;例如,在生產環境,如果使用 PHP 的 Apache 2 Handler 模組,就不建議使用執行緒類型的 MPM。相關理由請參考。
沒有留言:
張貼留言