servlet容器的時代已經終結
在Java的世界里, Tomcat 和 Jetty 這樣的servlet容器可以服務于web應用程序。但是最近新起的非java方案,比如 Node.js 和 GO ,則提供了其自帶的內嵌服務器,這讓大家開始意識到 Java 也可以使用內嵌服務器。本文探討servlet容器為何以現在的方式構建的原因,為什么在一些情況下仍然適用,不過它們至少已經不是最初設計的那樣了。
一點歷史
1999年Apache Tomcat(之后的Jakarta Tomcat)出現的時候,互聯網及其工具還遠沒有今天這么復雜和專業。因此servlet容器被設計用來服務的用戶場景和如今也有非常大的差異。
Servlet容器被定位為托管web應用程序的高可用組件。盡管這在當時不失為一個很好的想法,但是它也帶來了一些問題,比如 內存泄露 和類裝載問題。
現狀
現代應用程序環境通常包括多個服務。無論你是否正在運行一個龐大的應用程序,或者正在致力于基于微服務的架構,我知道你都會同意這一點,對于所有基于web的內容,可用性都及其重要,特別是如果你運行的是在線業務的時候。雖然可用性在15年之前就很重要(以前通常會在流量最小的午夜部署變更,停機時間也是小菜一碟),但是以前客戶對性能的期待從來沒有像現在這么高。
不匹配的容器簡化度
如果你正在運行龐大的web應用程序,你可能會想要堅持使用Jetty,Tomcat, WildFly 或其他的獨立實例,因為它們很容易使用。比如,容器通常提供了集成的web接口來部署一個新的.war文件,并且支持基礎的監控需求。
但是,如果從批判的角度看,servlet容器只是一個組件,它需要部署,配置和維護。這并不一定是壞事,因為容器的確能解決一定的問題,任何解決問題的工具都值得被部署,配置和維護,不是么?不過,servlet容器有一個問題:容器和其上運行的服務之間耦合太緊。
部署
既然容器只是組件,那么就需要仔細考慮容器實例的部署。容器有發布周期。在2015年,Tomcat 8至今大概有八個版本發布。如果繼續這樣的趨勢,今年大概還有三到四個版本。
因為所有維護工具也有自己的發布周期,這些單獨看不應該成為問題。真正的問題是無法在容器內運行的服務不中斷的情況下部署新的容器版本。
這種容器及其托管服務之間高度依賴的關系給了我們三種可能的部署場景:
- 部署新的servlet容器,保留當前托管應用程序的版本
- 部署新的servlet容器,更新到最新的托管應用程序的版本
- 部署新的托管應用程序的版本
這三種之中的兩種場景通常都需要多個build作業才能完成,這些作業必須順次執行或者需要相應地組合起來。
使用內嵌的servlet容器的話,你就只能“部署新的托管應用程序的版本”,因為內嵌的容器版本定義在項目的 Maven 或者 Gradle 配置文件里。
部署servlet容器通常并不依賴于容器版本。雖然你可以拷貝一個executable.jar文件到文件系統里并且執行,但是通常還是需要遵照容器的部署API的改變來保證腳本的正確性。這在Tomcat6到8的每個主要版本里都會發生。
單獨容器的倡導者告訴我們在容器里運行的應用程序越多,額外消耗就越小。當容器需要更新時,只需要完成這個單獨容器的更新就好了,而不需要更新所有運行內嵌容器的實例。雖然這有些道理,但并不完全正確:
當某個應用程序在容器里造成嚴重破壞的時候,它會輕易影響到容器里運行的別的所有東西。某個單一失敗的服務影響到別的不直接相關的服務,這顯然不是想要的事情 -- 當這樣的問題發生時,會導致環境里發生完全無法預測的行為。
除了部署和維護單獨容器的運營之外,還需要關注如下幾點:
內存
如果使用自己的硬件,內存現在非常便宜。但是在云環境里,價格通常取決于CPU和內存的使用量,因此價格可能會很貴。
現在你可能并不會考慮運行32-bit的JVM,但是要注意64-bit的JVM要求更多的內存 --平均大概要多30-50%。注意,增加的Java內存使用也會導致 垃圾回收時間的增加 ,因此這不僅僅有關于內存使用量 -- 還有關于性能。
因此,如果你的應用程序或者服務要求少于2GB的內存,32-bit的JVM可以支持的話,那么就應該繼續使用32-bit的JVM。使用64bit的JVM來托管許多可以在32-bit JVM上輕松運行的服務,從性能角度而言是不好的方案。
配置
除了配置應用程序和服務,容器本身也需要配置。端口和日志級別是這些配置中最為重要的部分。雖然有些庫幫助這些配置盡可能得統一和無縫,但是配置一個嵌入式容器仍然是最簡單的方式。
衍生思考
在Google上搜索“embedded Java web server”。特別是服務API或者較小的配置UI,你很可能可以用輕量級的方案來代替重量的Tomcat,Jetty,WildFly等等。
總結
在決定是否堅持使用內嵌式容器的時候,可以試著問問“它依賴于”這個問題。盡管我知道“它依賴于”這個問題比起如今web的性能,擴展性以及可用性標準而言并沒有那么重要。
更簡單的部署方式, 更高效的內存使用,互不依賴服務間更好的隔離,以及更容易的部署都是使用內嵌容器能帶來的優勢。
現狀就是這樣,單獨的容器設計用來解決的問題如今遇到的已經不多了。類似Spring Boot這樣的框架使得更容易開始使用單獨的應用程序。
原文鏈接: The era of servlet containers is over (翻譯:崔婧雯 校對:)===========================
譯者介紹
崔婧雯,現就職于IBM,高級軟件工程師,負責IBM WebSphere業務流程管理軟件的系統測試工作。曾就職于VMware從事桌面虛擬化產品的質量保證工作。對虛擬化,中間件技術,業務流程管理有濃厚的興趣。