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

Apache 模組 mod_unique_id

提供語言: en  |  fr  |  ja  |  ko 

描述提供環境變數,為每個請求提供唯一識別碼。
狀態擴充功能
模組識別碼unique_id_module
原始檔mod_unique_id.c

摘要

在「所有」請求下,此模組可為每個請求提供確保在非常特定條件下都保持唯一的魔法金鑰。在適當組態的機器群集的各個機器中,這項唯一識別碼甚至是唯一的。環境變數 UNIQUE_ID 已設定為每個請求的識別碼。唯一識別碼具有各種用途,但這不在本文討論範圍內。

Support Apache!

主題

指令

此模組不提供任何指令。

錯誤修正檢查清單

另請參閱

top

理論

首先,簡單回顧 Apache 伺服器在 Unix 機器中的運作方式。目前不支援這項功能 Windows NT。在 Unix 機器中,Apache 會建立幾個子行程,而子行程會一次處理一個請求。每個子行程在其生命週期內可處理多個請求。就這項討論而言,子行程之間不會共用任何資料。我們會將子行程稱為 httpd 處理程序

您的網站中有數台受您管理的機器,我們會將它們合稱為機器群集。每台機器都可以執行多個 Apache 實例。所有這些實例合起來即為「宇宙」,在特定假設下,我們將證明,在這個宇宙中,我們可以為每個請求產生唯一的識別碼,而不必進行群集中的機器之間大量的通訊。

群集中的機器應符合下列需求。(即使只有單一台機器,您仍應將其時鐘與 NTP 同步。)

關於作業系統假設的部分,我們假設 PID (程序 ID) 符合 32 位元。如果作業系統針對 PID 使用超過 32 位元,則解決方式很簡單,但必須在程式碼中執行。

在這些假設下,我們可以於某個時間點,從叢集中所有其他 httpd 程序中識別任何一台機器上存在的任何 httpd 程序。機器的 IP 位址和 httpd 程序的 PID 就足夠執行此動作。如果使用多執行緒 MPM,一個 httpd 程序可以同時處理多個要求。為了辨識執行緒,我們使用 Apache httpd 內部使用的執行緒索引。因此,為了產生要求的獨特識別碼,我們只需要區分不同的時間點。

為了區分時間,我們將使用 Unix 時間戳記 (從 1970 年 1 月 1 日 UTC 開始的秒數) 和一個 16 位元計數器。時間戳記只有一個秒數粒度,因此計數器用於表示一秒內多達 65536 個值。四元組 *(ip_addr、pid、time_stamp、counter)* 足以列舉每個 httpd 程序每秒 65536 個要求。但 PID 隨著時間重複使用會產生一些問題,而計數器用於解決此問題。

當建立 httpd 子行程時,會將計數器初始化為 (當前微秒數除以 10) 模組 65536 (選擇此公式是因為可以在一些系統微秒計時器的低序位元中消除某些變異問題)。當產生唯一識別碼時,所使用的時間戳記為要求抵達網路伺服器時間。我們每次產生識別碼 (並允許重新載入) 時,都會遞增計數器。

當核心為每個程序產生一個 PID 時,會派生程序,並且允許 PID 重新載入 (在許多 Unix 作業系統中為 16 位元,但較新的系統已擴充至 32 位元)。因此,相同的 PID 將隨著時間重複使用。但是,除非在同一個秒數內重複使用,否則不會破壞四元組的獨特性。也就是說,我們假設系統不會在一秒鐘內產生 65536 個程序 (在一些 Unix 作業系統中甚至可能是 32768 個程序,但這不太可能發生)。

假設時間會因為某些原因而重複。也就是假設系統時鐘出了問題,並且它會重新回到過去的時間(或它走得太快,然後正確重設,接著重新回到未來的時間)。在這種情況下,我們可以輕易地證明我們可以重複使用 pid 和時間戳記。計數器初始值的選擇有用意地防止此種情況。請注意,我們真正需要一個隨機數來初始化計數器,但大多數系統上都沒有任何容易取得的數字( 您無法使用 rand(),因為您需要對產生器實施植入,而且您無法對其實施植入,因為時間,至少在一秒的分辨率下,已重複。這並非完美的防禦。

這是一個多好的防禦?假設您的其中一台電腦每秒最多處理 500 個要求(在撰寫本文時,這是一個非常合理的最高值,因為系統通常不只是發送靜態檔案)。為執行此操作,它將需要某些子程式,視您有多少並行的客戶端而定。不過,我們將採取悲觀的態度,認為一個子程式可以每秒處理 500 個要求。有 1,000 個可能的起始計數器值,讓兩個 500 個要求的順序重疊。因此,有 1.5% 的機會,如果時間(在一秒的分辨率)重複,這個子程式會重複一個計數器值,而且獨特性將會被破壞。這是一個非常悲觀的範例,而且根據實際數值,發生的機率甚至更低。如果您的系統仍有可能發生這種情況,那麼或許您應該將計數器設為 32 位元(透過編輯程式碼)。

您可能會擔心在夏令時間回調其間,「時間」會「回調」。但這並不是問題,因為這裡使用的是 UTC,它「總是」會向前走。請注意,x86 為基礎的 Unix 可能需要適當的組態才行 -- 它們應該被組態為假設主機板時鐘位於 UTC 並適當地進行補償。不過,即使如此,如果您正在執行 NTP,您的 UTC 時間將會在重新開機後不久就正確無誤。

UNIQUE_ID 環境變數是以與 MIME base64 編碼類似的方式,使用 [A-Za-z0-9@-] 字母將 144 位元 (32 位元 IP 位址、32 位元 PID、32 位元時間戳記、16 位元計數器、32 位元執行緒索引) 的四元組編碼並產生 24 個字元。MIME base64 字母實際上為 [A-Za-z0-9+/],但是 + 和 / 需要在 URL 中特別編碼,這讓它們較不受青睞。所有值皆以網路位元組順序編碼,以便在不同位元組順序的架構中編碼具可比性。編碼的實際順序為:時間戳記、IP 位址、PID、計數器。這個順序是有目的的,但必須強調的是,應用程式不應剖析編碼。應用程式應將整個編碼的 UNIQUE_ID 視為不透明的令牌,僅可用於與其他 UNIQUE_ID 相比較以確認是否相等。

順序的選取是設定為在不需擔心與現有 UNIQUE_ID 資料庫中的資料碰撞的情形下,仍可變更編碼。新的編碼也應將時間戳記保留為第一個元素,並且可以使用相同的字母和位元長度。由於時間戳記本質上是遞增的序列,因此只需讓叢集中的所有機器停止提供任何要求,並停止使用舊編碼格式即可。之後,他們可以繼續請求並開始發布新的編碼。

我們相信這是解決此問題的相對可攜式方案。所產生的識別碼本質上具有無限的壽命,因為未來的識別碼可以根據需要延長。本質上叢集中的機器間不需要通訊 (僅需要 NTP 同步,這是低開銷的),且不須在 httpd 程序間進行通訊 (通訊隱含於核心所分配的 PID 值中)。在非常特定的情況下,識別碼可以縮短,但需要假設更多資訊 (例如,32 位元 IP 位址對任何網站來說都是過度的,但沒有可攜式較短的替換方式)。

提供語言: en  |  fr  |  ja  |  ko 

top

意見

注意
這不是問答部分。張貼於此處的意見應針對改善文件或伺服器的建議提出,如果它們已實施或被視為無效/離題,則可能會被我們的管理員刪除。有關如何管理 Apache HTTP 伺服器的的疑問,應傳送至我們的 IRC 頻道 (#httpd,在 Libera.chat 上) 或傳送至我們的 郵寄清單