天天看點

如何設計一個web容器

開發一個web容器涉及很多不同方面不同層面的技術,例如通信層的知識,程式語言層面的知識等等,且一個可用的web容器是一個比較龐大的系統,要說清楚需要很長的篇幅,本文旨在介紹如何設計一個web容器,隻探讨實作的思路,并不涉及過多的具體實作。把它分解劃分成若幹子產品群組件,每個元件子產品負責不同的功能,下圖列出一些基本的元件,并将對每個元件進行介紹。

如何設計一個web容器

連接配接接收器

主要的職責就是監聽是否有用戶端套接字連接配接并接收socket,再将socket交由任務執行器(線程池)執行。不斷從系統底層讀取socket,做盡可能少的處理,再扔進線程池。為什麼強調要做盡可能少的處理?這裡關系到系統性能問題,過多的處理會嚴重影響吞吐量。因為一般隻有一個接收器(一條線程負責套接字接收工作),是以它對每次接收處理的時間長短将很可能對整體性能産生影響。于是接收器所幹的活都是非常少且簡單的,僅僅維護了幾個狀态變量、流量控制閘門的累加操作、serverSocket的接收操作、設定接收到的socket的一些屬性、将接收到的socket放入線程池以及一些異常處理。其他需要較長時間處理的邏輯就交給了線程池,例如對socket底層資料的讀取,對http協定封包的解析及響應用戶端的一些操作等等。

如何設計一個web容器

連接配接數控制器

對于一台機器而言,通路請求的總流量有高峰期且伺服器有實體極限,為了保證web伺服器不被沖垮我們需要采取一些措施進行保護預防,需要稍微說明的此處的流量更多的是指套接字的連接配接數,通過控制套接字連接配接個數來控制流量。其中一種有效的方法就是采取流量控制,它就像在流量的入口增加了一道閘門,閘門的大小決定了流量的大小,一旦達到最大流量将關閉閘門停止接收直到有空閑通道。計數器可用JDK的AQS架構實作。

如何設計一個web容器

套接字工廠

不同的使用場合可能需要不同的安全級别,例如在支付相關的交易就必須對資訊加密後再發送,這其中還涉及到密鑰協商的過程,而在另外一些普通場合則無需對封包加密。反應到應用層則是使用http與https的問題。

簡單講TLS\SSL協定給每次通信①提供認證服務,認證本次會話實體身份的合法性。②提供加密服務,強加密機制能保證通信過程中的消息不會被破譯。③提供防篡改服務,利用Hash算法對消息進行簽名,通過驗證簽名保證通信内容不被篡改。

http協定對應Socket,而https則對應SSLSocket。如何生成Socket及SSLSocket則交由套接字工廠。

如何設計一個web容器

任務定義器——Task

定義需要執行的任務,告訴線程池要執行什麼樣的任務。任務主要分為三點:處理socket并響應用戶端、連接配接數計數器減一、關閉socket。其中對socket的處理是最重要也是最複雜的,它包括對底層socket位元組流的讀取、http協定請求封包的解析(請求行、請求頭、請求體等資訊的解析)、根據請求行解析得到路徑去尋找相應主機上web項目的資源、根據處理的結果組裝好http協定響應封包輸出到用戶端。

如何設計一個web容器

任務執行器

一個擁有最大最小線程數限制的線程池,之是以稱之為“任務執行器”是因為線程池可以看做是啟動了若幹線程不斷檢測某個任務隊列,一旦發現有需要執行的任務則執行。最大最小線程數限制、多餘線程回收時間限制、超出最大線程數時線程池做出的拒絕動作等等。

如何設計一個web容器

封包讀取

用于向作業系統底層讀取來自用戶端的封包并提供緩沖機制。封包複制到desBuf。

如何設計一個web容器

封包輸出

用于向作業系統底層寫入由web容器處理後的封包并提供緩沖機制。将封包outputBuf通過緩沖區寫入到作業系統。

如何設計一個web容器

輸入過濾器

在這個讀取的過程中希望做一些額外的處理,并且這些額外處理可能是根據不同條件做不同的處理,考慮到程式解耦與擴充,于是引入過濾器。通過一層層的過濾器完成過濾操作後才能到desBuf,這個過程就像被加入了一道道處理關卡,經過關卡都會被執行相應操作,最終完成源資料到目的資料的操作。

如何設計一個web容器

輸出過濾器

與輸入過濾器功能類似,用于在封包輸出的時候。

如何設計一個web容器

封包解析器

提供解析http協定各個部分的能力。

如何設計一個web容器

請求生成器

按照面向對象的思想,把每個請求過程中與請求相關的屬性及協定字段等抽象成一個Request對象。包括請求行、請求頭、請求體三部分資訊,在處理過程中需要什麼值可直接從request對象中擷取。為實作servlet标準提供友善。

如何設計一個web容器

響應生成器

與請求相對應,需要一個響應對象生成器。包括響應行、響應頭、響應體三部分資訊,在處理結果相關值可直接設定到response對象中。為實作servlet标準提供友善。

如何設計一個web容器

位址映射器

位址映射器是請求與各個web項目、各個資源的路由器。一個請求的通路根據路徑被映射找到響應的資源輸出給請求用戶端。

如何設計一個web容器

生命周期

為了進一步子產品化,整個容器擁有很多元件,這些元件可能在不同的時刻需要做不同的事件,需要一個生命周期統一把所有元件管理起來。例如所有元件的啟動、停止、關閉等操作都抽離由生命周期統一管理,就可以友善管理這些元件的生命周期。希望在某某狀态事情發生之前之後做點什麼?添加一個生命周期監聽器即可優雅實作。

如何設計一個web容器

JMX管理器

系統運作狀态的監控及管理,伺服器性能、伺服器相關參數的收集、JVM負載、web連接配接數、線程池、資料庫連接配接池、緩存管理、配置檔案重新加載等方面。可提供一些遠端可視化管理,實時性高。同時也為分布式系統的管理提供了一個解決方案。

如何設計一個web容器

Web載入器

WebLoader用于加載web應用項目,一個web容器可能包含了若幹個web應用。為了達到lib及servlet的隔離,對于每個web應用要使用不同的類加載器ClassLoader,且這些類加載器不是父子關系,以此達到class隔離效果,即一個web應用的lib不會被其他web應用使用。

如何設計一個web容器

會話管理器

會話管理器主要對session進行管理,包括:①生成sessionid,一般cookies或url未帶jsessionid值則認為不存在會話,需要重新生成sessionid用作會話id。②很多用戶端的會話都儲存在伺服器中,對于逾時的會話要定期清理以確定伺服器記憶體不會浪費。③對于一些重要的會話可以持久化到磁盤,需要時可重新加載到記憶體中使用。

如何設計一個web容器

運作日志

對運作時一些警告、異常、錯誤進行記錄。

如何設計一個web容器

通路日志

通路日志一般會記錄用戶端的通路相關資訊,包括用戶端ip、請求時間、請求協定、請求方法、請求位元組數、響應碼、會話id、處理時間等等。通路日志可以統計通路使用者的數量、通路時間分布等規律及個人愛好等等,這些資料可以幫助公司在營運政策上做出抉擇。

如何設計一個web容器

安全管理器

Web項目運作在web容器平台上,這就好比将一個應用嵌入到一個平台上面運作,要使嵌入的程式能正常運作,首先平台要能安全正常運作。并且要最大程度做到平台不受嵌入的應用程式影響,兩者在一定程度上達到隔離的效果。啟動時通過-Djava.security.manager -Djava.security.policy==web.policy指定policy檔案,此檔案定義了各種權限。

如何設計一個web容器

運作監控&遠端管理

提供一個可以實時監控web容器運作狀态的平台,并且能進行遠端管理。

如何設計一個web容器

叢集

叢集一般有兩種:①負載均衡叢集,一般是通過一定的分發算法把通路流量均勻分布到叢集裡面的各個機器上進行處理。②高可用叢集,叢集通信把若幹機器連接配接起來,這種叢集更偏重的是當叢集中某個機器發生故障後能通過自動切換或流量轉移等措施來保證整個叢集對外的可用性。

web一般請求都是無狀态,可以直接做叢集,但涉及session則屬于有狀态,需要使用叢集通信技術進行session拷貝。相關技術包括多點傳播、單點傳播。

如何設計一個web容器

Servlet引擎

servlet引擎利用反射把web應用中的servlet及jsp生成對象并放入servlet對象池中,并根據實際調用相應的方法。web應用将業務邏輯處理都放在dopost或doget方法中,web容器處理請求時就會按照這裡定義好的處理邏輯進行處理,處理完響應用戶端。

如何設計一個web容器

JSP編譯器

按照規範JSP最終都是被編譯成servlet執行,是以要按照規範對jsp檔案進行編譯。JSP編譯器其實就是對jsp文法進行翻譯,根據jsp文法處理。

如何設計一個web容器

一個web容器基本包含以上介紹的元件的功能,根據各個元件子產品進行實作即可搭建起一個可以讓你的web運作起來的web容器。

 ==========廣告時間==========

鄙人的新書《Tomcat核心設計剖析》已經在京東預售了,有需要的朋友可以到 https://item.jd.com/12185360.html 進行預定。感謝各位朋友。

=========================