<-
Apache > HTTP Server > 文件 > 2.4 版 > 模組

Apache MPM event

可用的語言: 英文  |  法文 

描述worker MPM 的變型,其目標只對具有活動處理作業的連線使用執行緒
狀態MPM
模組識別項mpm_event_module
來源檔案event.c

摘要

event 多重處理模組 (MPM) 設計用於透過將一些處理工作交由監聽器執行緒來允許同時處理更多要求,並釋放工作執行緒來處理新的要求。

如要使用 event MPM,在建置 httpd 時,將 --with-mpm=event 新增至 configure 指令碼的參數。

Support Apache!

主題

指令

除錯檢查清單

另請參閱

top

與 Worker MPM 的關係

event 基於 worker MPM,實作混合多重程序多執行緒伺服器。單一路由程序 (父程序) 負責啟動子程序。每個子程序建立 ThreadsPerChild 指令中指定的固定伺服器執行緒數目,同時建立一個監聽程序執行緒,用於監聽連線,並在連線抵達時傳遞給工作執行緒處理。

執行時期設定指令與 worker 提供的指令相同,僅新增 AsyncRequestWorkerFactor

top

運作方式

此 MPM 嘗試修正 HTTP 中的「保持存活問題」。當客戶端完成第一項要求後,其可以維持連線開啟,透過同一 socket 傳送進一步的要求,並在建立 TCP 連線時節省大量的額外負擔。然而,Apache HTTP 伺服器傳統上會讓整個子程序或執行緒持續等待來自客戶端的資料,這也帶來自身的缺點。為了解決這個問題,此 MPM 使用一個專屬的監聽執行緒執行每個程序,用於處理監聽 socket,所有處於保持存活狀態的 socket,已由處理常式和通訊協定過濾器完成其工作,以及僅剩將資料傳送給客戶端的 socket。

這個新架構善用非阻擋 socket 和 APR 揭露的現代核心功能(如 Linux 的 epoll),不再需要設定mpm-accept Mutex 來避免驚群現象。

單一程序/執行緒區塊可以處理的總連線數由 AsyncRequestWorkerFactor 指令調整。

非同步連線

非同步連線需要一個固定的專屬工作執行緒和先前的 MPM,但 event 不需要。mod_status 的狀態頁面會在非同步連線區段中顯示新的欄位

撰寫
在將回應傳送至用戶端時,可能會發生 TCP 寫入緩衝區填滿,因為連線過於緩慢。通常在此情況下,write()至套接字會傳回EWOULDBLOCKEAGAIN在閒置一段時間後才能再次寫入。持有套接字的工作執行緒或許能夠將等候中的任務卸載至偵聽執行緒,而偵聽執行緒將在套接字提出事件後(例如,「套接字現在可寫入」)將其重新指派至第一個可用的閒置工作執行緒。請檢查限制區段以取得更多資訊。
保持連線
保留連線處理是工作執行緒 MPM 的最基本改善。一旦工作執行緒完成將回應傳送至用戶端,它便會將套接字處理卸載至偵聽執行緒,而偵聽執行緒進而會等候來自作業系統的任何事件,例如「套接字可讀取」。如果有任何新要求來自用戶端,接著偵聽器將其轉發至第一個可用的工作執行緒。反之,如果KeepAliveTimeout發生,那麼套接字將由偵聽器關閉。如此一來,工作執行緒不必負責閒置套接字,而可以重新用於處理其他要求。
關閉
有時候 MPM 需要執行持續性的關閉,亦即在仍持續將資料傳輸至 httpd 時傳送早期錯誤給用戶端。傳送回應,然後立即關閉連線不是正確的做法,因為用戶端(仍嘗試將要求的其餘部分傳送出去)會得到連線重設,而且無法讀取 httpd 的回應。持續性的關閉有時間限制,但可能會花費相對長的時間,因此它會卸載至一個工作執行緒(包括中斷掛鉤和真正的套接字關閉)。從 2.4.28 開始,當連線最終計時逾時時也會發生這種情況(偵聽執行緒除了等候並調度其事件之外,絕不會處理連線)。

這些改善對 HTTP/HTTPS 連線皆有效。

優雅的程序終止和計分板用量

此 MPM 早期顯示出某些可擴充性瓶頸,導致出現下列錯誤:「計分板已滿,未達 MaxRequestWorkers 值」。MaxRequestWorkers 會限制在任何特定時間點提供的同時請求數,以及允許的程序數 (MaxRequestWorkers / ThreadsPerChild);同時,計分板會顯示所有執行中程序以及它們的工作執行緒狀態。如果計分板已滿 (所以所有執行緒皆為非閒置狀態),但提供的活動請求數未達 MaxRequestWorkers,表示其中某些執行緒會封鎖本可提供但反而是排隊等候的新請求 (其上限由 ListenBacklog 設定)。大部分時候,執行緒會停留在 Graceful 狀態,表示它們正在等候完成與 TCP 連線相關的工作,以安全地終止並釋出計分板插槽 (例如,處理長時間執行之請求、速度很慢的客戶端,或已啟用保持連線功能的連線)。最常見的是發生下列兩個情況

從 2.4.24 開始,mpm-event 變的更聰明,能夠以更好的方式處理優雅終止。部分改進如下

上一個重點中所述的行為可透過 mod_status 中連線摘要表格的兩個新欄位「スロット」和「正在中斷」完整觀察到。前者指示 PID,而後者指示處理程序是否正在中斷;額外的狀態「是 (舊世代)」指示處理程序在順利重新啟動後仍在執行。

限制

改良過的連線處理可能不適用於已宣稱與事件不相容的特定連線篩選器。在這些情況中,此 MPM 會回復為 worker MPM 的行為,並為每個連線保留一個工作執行緒。與伺服器一起配送的所有模組與事件 MPM 相容。

目前的類似限制用於包含輸出篩選器的要求,而輸出篩選器需要讀取和/或修改整個回應本體。如果當篩選器正在處理資料時伺服器端連線遭到封鎖,且篩選器產生的資料量過大而無法緩衝在記憶體中,則用於該要求的執行緒不會在 httpd 等待將待處理資料傳送至伺服器端時釋放。
舉例來說,我們可以考慮以下兩個情況:提供靜態資產(例如 CSS 檔案)相較於提供從 FCGI/CGI 或代理伺服器擷取的內容。前者可以預測,換言之,事件 MPM 對內容結束具有完全的可視性,且可以使用事件:提供回應內容的工作執行緒可以在傳回 EWOULDBLOCKEAGAIN 之前清除第一個位元組,委派其餘部份給監聽器。監聽器依序等待 socket 上的事件,並委派工作將內容的其餘部份清除至第一個閒置工作執行緒。同時,在後一個範例(FCGI/CGI/代理內容)中,MPM 無法預測回應結束,且工作執行緒必須在將控制權回傳給監聽器之前完成其工作。唯一的替代方法是將回應緩衝在記憶體中,但這並非為顧及伺服器穩定性和記憶體使用量而能採行的最安全選項。

背景資料

事件模型得以實現是由於新的 API 導入到所支援作業系統中

在這些新 API 可用之前,必須使用傳統的 selectpoll API。如果用於處理許多連線或是連線的速率很高,這些 API 會變慢。新的 API 能夠監視更多的連線,並且當要監視的連線組經常變更時,它們的執行效能會好很多。因此,這些 API 能夠寫出事件 MPM,這種 MPM 比較容易擴充到有許多閒置連線的典型 HTTP 模式。

MPM 假設底層的 apr_pollset 實作足夠安全。這能讓 MPM 避免過度的高層鎖定,或是為了寄送保持連線 Socket 而喚醒偵聽器執行緒。目前這只與 KQueue 和 EPoll 相容。

top

需求

此 MPM 依賴於 APR 的原子比較及交換運算執行緒同步。如果您要編譯 x86 目標而且不需要支援 386,或是您要編譯 SPARC 而且不需要在 UltraSPARC 之前的晶片上執行,請將 --enable-nonportable-atomics=yes 加入 configure 指令碼的引數。這將導致 APR 使用舊有 CPU 中不存在的有效運算碼來實作原子運算。

此 MPM 在缺乏良好執行緒的舊平台上無法良好執行,但因為 EPoll 或 KQueue 的需求,這一點沒有異議。

top

AsyncRequestWorkerFactor 指令

描述限制每個處理程序的同時連線
語法AsyncRequestWorkerFactor 係數
預設2
上下文伺服器組態
狀態MPM
模組事件
相容性適用於版本 2.3.13 及更新版本

事件 MPM 以非同步方式處理部分連線,其中請求工作執行緒僅會在需要時短時間分配,而其他連線則會保留每個連線一個請求工作執行緒。這可能導致所有工作執行緒都忙碌,而且沒有工作執行緒有空處理已建立的非同步連線上的新工作。

為了緩解此問題,事件 MPM 會執行兩件事

此指令可用於微調處理程序連線限制。如果目前連線數目(不計算「關閉」狀態的連線)小於以下值,**程序**會接受新連線:

ThreadsPerChild + (AsyncRequestWorkerFactor * 閒置工作程序數)

可根據閒置工作程序執行緒的平均值,計算所有程序的最大同時連線數,公式如下:

(ThreadsPerChild + (AsyncRequestWorkerFactor * 閒置工作程序數)) * ServerLimit

範例

ThreadsPerChild = 10
ServerLimit = 4
AsyncRequestWorkerFactor = 2
MaxRequestWorkers = 40

idle_workers = 4 (average for all the processes to keep it simple)

max_connections = (ThreadsPerChild + (AsyncRequestWorkerFactor * idle_workers)) * ServerLimit
                = (10 + (2 * 4)) * 4 = 72

當所有工作程序執行緒都處於閒置狀態時,可用更簡單的方式計算同時連線數的最大絕對值:

(AsyncRequestWorkerFactor + 1) * MaxRequestWorkers

範例

ThreadsPerChild = 10
ServerLimit = 4
MaxRequestWorkers = 40
AsyncRequestWorkerFactor = 2

如果所有程序的所有執行緒都處於閒置狀態,則:

idle_workers = 10

我們可用兩種方式計算同時連線數的最大絕對值:

max_connections = (ThreadsPerChild + (AsyncRequestWorkerFactor * idle_workers)) * ServerLimit
                = (10 + (2 * 10)) * 4 = 120

max_connections = (AsyncRequestWorkerFactor + 1) * MaxRequestWorkers
                = (2 + 1) * 40 = 120

調整 AsyncRequestWorkerFactor 需要瞭解 httpd 在每個特定案例中處理的流量,因此變更預設值需要透過 mod_status 進行廣泛的測試和資料收集。

在版本 2.3.13 之前,MaxRequestWorkers 稱為 MaxClients。以上的變數顯示,對於事件 MPM 而言,舊名稱無法精確描述其意義。

AsyncRequestWorkerFactor 可使用非整數參數,例如「1.5」。

可用的語言: 英文  |  法文 

top

註解

注意事項
此處並非問答區。在此處放置的留言應針對改善文件或伺服器的建議,且我們的管理員可能會移除已實施或被視為無效/離題的留言。有關如何管理 Apache HTTP Server 的問題應轉向 IRC 頻道 #httpd (在 Libera.chat 上),或傳送至我們的 寄件清單