《程式設計時間簡史系列》Web Server 編年史

然後去遠足發表於2020-07-02

引言

本文是《程式設計時間簡史系列》的第二篇文章。

全系列索引:

  1. 《程式設計時間簡史系列》JavaScript 模組化的歷史程式
  2. 《程式設計時間簡史系列》Web Server 編年史

網際網路今天已經廣泛存在於人們的生活中,人們的衣食住行等方方面面早已離不開網際網路的支撐,這其中離不開 Web 技術的發展。

Web 是一種典型的分散式應用架構。Web 應用中的每一次資訊交換都要涉及到客戶端和服務端兩個層面。因此,Web 開發技術大體上也可以被分為客戶端技術和服務端技術兩大類。

本文將會講述 Web 服務端技術的萌芽和演進過程,旨在使讀者能更清晰地掌握 Web 服務端技術的發展脈絡。

Web 服務端技術的發展與客戶端技術的進步是相輔相成的,本文雖是討論 Web 服務端,在講述過程中卻不可避免地會提及一些 Web 客戶端的有關內容,但不會過多深入。對此感興趣的讀者,可以自行閱讀最下方的參考連結。

同樣的,不談具體程式碼,只聊歷史故事。

P.S. 下一篇的選題還沒有敲定,如果有朋友想了解某一方面的歷史又苦於沒有資料,可以在文章下方給我留言。


正文

廣義上的 Web Server(Web 伺服器),包含硬體和軟體兩方面。今天我們只談及其中的軟體部分,即能向客戶端提供 Web 服務的程式。

現在大家耳熟能詳的 ApacheIISTomcatNginx 等等,都屬於 Web Server。

那麼它們之間究竟有何不同?又是由誰、在什麼時間發明的?我們常說的靜態網頁、動態網頁又是指什麼?HTTPd 和 Web Server 有何不同?網上總提的 libuv,它是個啥?

讓我們先帶著這些疑問,回到 HTTP 協議尚未誕生的時代。

時代前夜:HTML、HTTP 與全球資訊網

1960 年,Theodor Holm Nelson 在哈佛計算機程式設計的選修課程上,使用了當時哈佛大學唯一可用的計算機 —— IBM 7090。在臨近課程結束的時候,Theodor Holm Nelson 決定使用機器語言編寫一個計算機程式,讓他能夠將自己的筆記和手稿儲存在計算機中,可以以各種方式修改和編輯草稿,並生成可列印的最終版本。在他的專案進行到第 4 萬行左右的程式碼時,他開始意識到,他對這項任務的完成難度最初估計得過於樂觀。

1963 年,已經從哈佛大學畢業的 Theodor Holm Nelson 決定將自己大學時的想法繼續進行下去。他首次提出了名為 “HyperText”(超文字)的概念,並找到了一些志同道合、痴迷計算機的朋友,成立了 Project Xanadu,試圖制訂規範,並應用到實際的計算機程式中。

1969 年,IBM 公司的 Charles F. Goldfarb 發明了一種可以用於描述超文字文件的描述語言 —— Generalized Markup Language(簡稱為 GML,通用標記語言)。在之後的幾年時間裡,形成了 Standard Generalized Markup Language(簡稱為 SGML,標準通用標記語言)的標準規範,成為了 ISO 國際標準。

制訂 SGML 的基本思想是把文件的內容與樣式分開。在 SGML 中,標記分兩種:一種用來描述文件顯示的樣式,稱為程式標記;另一種用來描述文件中語句的用途,稱為描述標記。一個 SGML 檔案通常分三個層次:結構、內容和樣式。結構為組織文件的元素提供框架,內容是資訊本身,樣式控制內容的顯示。

不過,由於 GML/SGML 過於龐大且複雜,雖然有不少大公司在內部使用,但始終沒能得到廣泛的應用。

暫且按下 Theodor Holm NelsonCharles F. Goldfarb 這邊不表,讓我們來到 1989 年。

此時已是不惑之年的 Tim Berners-Lee,負責在 CERN(歐洲粒子物理實驗室)做 IT 支援工作。由於粒子物理在當時是前沿研究領域,需要全世界的物理學家合作參與,那麼如何與世界各地的物理研究所保持通訊,就是一件十分重要也棘手的事情。

起初,CERN 使用傳真機來傳輸檔案,但物理傳輸速度極慢,且會耗費大量紙張與油墨,對於資訊檢索工作而言也十分不便。

後來,因 ARPANET 網路在美國軍方和多所大學內成功使用,CERN 也開始採用這種使用計算機網路進行通訊的方式來傳輸資料。

但在此時,可選擇的網路協議並不多。從時間順序上來看,有:

  • 要麼是 1971 年出現的 FTP,用於傳輸檔案。但這種方式不能直接展示文字內容,而是需要下載到本地後才能開啟。更何況,即是開啟了檔案,如果需要同時顯示包含文字、圖片、音訊、視訊等資訊的多媒體內容,那麼需要特定的程式才能編輯、預覽。
  • 要麼是 1973 年出現的 TELNET 協議,可以與遠端終端進行互動。但這種操作方式極其繁瑣,且對於搞科研的物理科學家而言操作並不友好,往往還需要 Theodor Holm Nelson 這樣的 IT 部門來配合。
  • 要麼是 1982 年出現的 SMTP,通過電子郵件進行交流。但這種方式不適合用於資訊的公開展示,只適合點對點或群組之間的資訊溝通。

這一年年底,Tim Berners-Lee 向其上級提出了一項名為 Information Management: A Proposal(《關於資訊化管理的建議》)的提議:使來自世界各地的遠端站點的研究人員能夠組織和彙集資訊,在個人計算機上訪問大量的科研文獻,並建議在文件中連結其他文件。

在參考了 Theodor Holm Nelson 有關超文字的規範、並參考了 Charles F. GoldfarbGML/SGML 實現後,Tim Berners-Lee 於 1990 年發明了 Hypertext Markup Language(簡稱為 HTML,超文字標記語言)和 Hypertext Transfer Protocol(簡稱為 HTTP,超文字傳輸協議)。

1990 年,Tim Berners-Lee 建立了一款最原始的 GUI 的 HTML 瀏覽器(同時也是編輯器),和第一個 HTTP 伺服器。

1991 年,Tim Berners-Lee 作為佈道者開始廣泛推廣 Web 的理念,提出了 World Wide Web(全球資訊網)的概念。

值得一提的是,在這一時期,Web 領域還有其他諸如 NNTP、Gopher 等傳輸協議。但它們都因為種種原因,沒能像 HTTP 一樣流行起來,最終消失在了歷史長河之中。

1993 年,NCSA(美國國家超算應用中心)對此表現出了濃厚的興趣,並開發了名為 Mosaic 的瀏覽器,於當年 4 月釋出。

1994 年,第一屆國際全球資訊網大會於 4 月在瑞士日內瓦召開,World Wide Web Consortium(簡稱為 W3C,全球資訊網聯盟)組織正式成立,並從 IETF(網際網路工程任務組)接管了 HTML 的標準制訂工作。

同年 6 月,IETF 非正式地指出了之前在“民間”流傳的 URL(統一資源定位符)與 URN(統一資源名稱)這兩種叫法的存在,並進一步地定義了一個名為 Uniform Resource Identifier(簡稱為 URI,統一資源識別符號)的規範文法。

同年 10 月,CERN 的另一位 IT 員工 Håkon Wium Lie 吸收了當時已有的一些 Web 樣式的實踐經驗,提出併發明瞭 Cascading Style Sheets(簡稱為 CSS,層疊樣式表)。

同年 11 月,Mosaic 瀏覽器的開發人員創立了 Netscape(網景)公司,併發布了 Mosaic Netscape 瀏覽器 1.0 版本,後改名為 Netscape Navigator(網景導航者)。

1995 年,W3C 制訂了 HTML 2.0 標準。

同年 5 月,Netscape 公司的工程師 Brendan Eich 發明了一門名為 LiveScript 的指令碼語言,可用在 Web 伺服器和瀏覽器。在之後與 Netscape Navigator 2.0 一同釋出時,被改名為 JavaScript

同年 8 月,Microsoft(微軟)旗下的 Internet Explorer(簡稱為 IE)1.0 版本正式釋出。

1996 年,IETF 將 HTTP 列為網際網路標準之一,並制訂了 HTTP/1.0 協議標準。

同年 12 月,W3C 將 CSS 納入工作範圍,並在隨後個幾個月裡制訂了 CSS 1 標準。

1997 年,JavaScript 被提交給 ECMA(歐洲計算機制造商協會),並最終形成了編號 262、名為 ECMAScript 的標準規範。這一規範下包含了 Netscape 1995 年發明的 JavaScript、Microsoft 1995 年發明的 JScript、Adobe 1999 年發明的 ActionScript 等幾個實現。在接下來的幾年時間裡,這一標準規範同樣被 ISO(國際標準化組織)及 IEC (國際電工委員會)所採納。

1997 - 1999 年,HTML 3.0HTTP/1.1HTML 4.0CSS 2ECMAScript 3 等標準先後被髮布,並統治了今後二十餘年的網際網路。

終於,Web 時代降臨。

開天闢地:CERN HTTPd 和 NCSA HTTPd

HTTPd,即 HTTP daemon 的縮寫。

今天我們談到這個名詞,大部分人會把它認為是 Apache 的代名詞。但這其實只是個誤解(原因下文會提到)。

在類 Unix 的作業系統中,一個在後端週期性地執行某種任務或等待處理理某些事件的程式,往往被稱為 “Daemon Process”(守護/幽靈程式)。HTTPd 即取此意,意思就是在後臺處理 HTTP 請求的程式。

因此實際上來說,HTTPd 應該是近似等同於 Web Server。在 HTTP 協議尚未出現的時代,Web Server 一般指 FTP 伺服器。但 HTTP 協議出現後,Web Server 就立刻變成了指代 HTTP 伺服器。今天的 Web Server 一定會、但不僅僅只會支援 HTTP 協議及其衍生協議,還可能支援諸如 FTP、SMTP、MQTT 甚至是更底層的 TCP、UDP 協議。

1990 年年底,Tim Berners-Lee 在一臺執行著 NeXTSTEP 系統的 NeXT Computer 上編寫了首個 HTTPd 程式,起名為 Common Library。這是一個由 C 語言編寫的元件,只能處理 HTTP 請求中的 GET 謂詞,並不是一個獨立且完整的程式。因其屬於 CERN 專案的一部分,所以也被稱為 CERN HTTPd

1993 年,Tim Berners-LeeCommon Library 從 CERN 專案中獨立出來,更名為 libwww 並開源。

同年,NCSA 在此基礎之上擴充套件並開發出了 NCSA HTTPd

1994 年,libwww 的開發維護工作轉交給了 W3C,在此階段,libwww 新增了很多特性,諸如相容 HTTP/1.0、支援 CGI、虛擬主機等。此時它也被稱為 W3C HTTPd

1996 年,W3C 的工作重心已經不在 libwww 上,遲遲沒有新版本釋出,並最終於 2003 年宣告專案中止。

libwww 提供了基礎的 HTTP 協議的解析與包裝方式,既可用於服務端,也可用於服務端,被廣泛地使用在包括 MosaicLynxArenaMacWWW 在內的諸多早期 Web 程式中。

胎死腹中:夭折的 Jigsaw

上一小節提到,1996 年時 W3C 的工作重心已經不在 libwww 上,因為他們已經另有其他重點工作。

由於 libwww 只能被編譯到類 Unix 的作業系統中,且只支援靜態網頁。隨著 Web 技術的不斷髮展,以及 Windows 系統的廣泛流行,W3C 亟需一種可以跨平臺的的 Web 伺服器。因此,W3C 將目光放在了橫空出世、發展迅猛的一種跨平臺程式語言 —— Java。

W3C 聯合當時的擁有 Java 的 Sun(昇陽)公司,開發了一個名為 Jigsaw 的程式。

它由 Java 編寫,起初只作為 JDK 1.2 版本的一個模組釋出,意圖讓開發者能快速搭建一個跨平臺 Web 伺服器專案。它採用了多執行緒的處理方式,相容 HTTP/1.1,支援 SSL/TLS、WebDAV 等新特性,同時也是首個支援 Servlet 和 JSP 的伺服器程式。由於 Java 的跨平臺特性,它可以執行在 BeOS、AS-400、AIX、Unix、Solaris 2、OS/2、MacOS、Linux、Windows 95、Windows NT 等作業系統上。

但遺憾的是,W3C 組織內的大部分成員,都是 IT 巨頭公司,隨著它們分別釋出了各自的 Web 伺服器商業產品後,Jigsaw 專案已經在事實上被廢棄。雖然 W3C 沒有明確地宣佈專案中止,但從提交記錄上來看,2007 年以後已經沒有新特性被引入了,僅僅在 2007 - 2010 四年時間裡修復了三五個 Bug,從此就悄無聲息。

雖然 Jigsaw 命運早夭,但因為它是第一個由 Java 編寫的 Web Server,起到了很多綱領性的指導作用,為後續 Java 技術在 Web 領域的擴充套件打下了堅實的基礎。

值得一提的是,JDK 9 中新引入了與 Jigsaw 同名的模組化方案,但與 Jigsaw HTTPd 並沒有什麼關聯。

萌芽初生:SSI 的誕生與 CGI 的興起

最早的 Web 伺服器只是簡單地響應瀏覽器發來的 HTTP 請求,並將儲存在伺服器上的 HTML 檔案返回給瀏覽器。可以近似理解為擁有文件預覽功能的 FTP。文件內容在檔案未修改前就是不變的,所有訪問 Web 的使用者看到的內容都是相同的。

這也就是前文提到的所謂的“靜態網頁”,這顯然滿足不了人們對資訊豐富性和多樣性的強烈需求。

由此,Web 技術的發展出現了兩條分支路線。一條是嘗試向客戶端、即瀏覽器引入動態互動,例如 Sun 公司的 Java Applet、Netscape 公司的 JavaScript、Microsoft 公司的 JScriptVBScript、Adobe 公司的 FlashActionScript 等等。另一條是試圖從服務端、即 Web Server 入手,想在返回給客戶端時就輸出動態的內容。這兩條路線都在未來有了十分迅猛的發展,我們今天按下客戶端不表,只談服務端這面。

1991 年,NCSA 首次提出了 Server Side Includes(簡稱為 SSI,服務端嵌入) 的概念,並在之後釋出的 NCSA HTTPd 中實現這一技術。

不過 SSI 的功能十分有限,通常用於實現網站頁面的公共部分引用,比如在網頁底部重複出現的版權宣告等資訊。它既不支援運算表示式,也不能根據邏輯條件判斷是否輸出特定內容,更遑論支援資料庫這種 “高階操作” 了。所以雖然早期的 Web Server 都支援這種技術,但它並沒有流行起來。

1993 年,在 NCSA 釋出 NCSA HTTPd 的同時,NCSA 又提出了 Common Gateway Interface(簡稱為 CGI,通用閘道器介面)這一概念,並在未來幾年內先後制訂了 CGI 1.0CGI 1.1CGI 1.2 等標準。

CGI 本質上來說,就是接受一個輸入、並返回一個輸出的程式。CGI 獨立於 Web Server 存在,在收到特定請求後(這些請求通常以 /cgi-bin/ 路徑開頭),Web Server 將 HTTP 請求的內容作為引數傳遞給 CGI 程式,並將 CGI 程式的返回值作為 HTTP 響應返回給客戶端。所以 CGI 程式不能獨立執行,需要配合 Web Server 才能工作。

早期通常是在 Web Server 接受到一個請求後,開啟一個新的程式來執行 CGI 程式,這種方式在請求量稍微大一些時,就會嚴重拖累伺服器的效能。

所以,隨後又誕生了 FastCGI(簡稱為 FCGI)技術。簡單來說,就是一個常駐記憶體的程式池技術,可以複用程式,使得 CGI 的工作負載效能大大提升。

在今天,由於 CGI 編寫的複雜難度過大,已經很少有人再直接應用這種技術(間接的還有很多)。但它的出現,給其他程式語言帶來了啟發,諸如 FCGISCGIWSGIServlet 乃至後來的動態指令碼語言等技術不斷湧現,它們都濫觴於 CGI

承前啟後:WebServer 之 Apache HTTP Server

1995 年,在隨著 NCSA HTTPd 1.3 版本的釋出,NCSA 就逐漸放緩了對 NCSA HTTPd 版本的開發工作。但為了滿足日益豐富的 Web 服務端技術的需要,NCSA HTTPd 的社群成員在 Brian Behlendorf 的領導下,決定在 NCSA HTTPd 1.3 版本的基礎上建立一個新的分支,並取名為 Apache

為什麼取名為 Apache?其中一個流傳最廣的解釋是,Apache 是在 NCSA HTTPd 的基礎上修改的,因此是一個 “修補過的”(a patchy)Web Server。

但後來在 Apache 的 2.0 版本里,Apache 社群已將 NCSA HTTPd 的原始碼全部移除,二者在今天已經沒有了直接關係。

Apache 在前人的基礎上,支援了很多新的 Web 特性。例如:多種身份認證方案、支援 CGI、支援 SSL/TLS、支援 IPv6、反向代理、URL 重寫、定製化日誌檔案等等。與此同時,在其 2.0 版本中還加入了對非 Unix 作業系統的跨平臺支援。

隨著 Apache 逐漸發展壯大,它成為了首個最為廣泛使用的開源 Web Server,曾一度佔領了 70% 以上的市場份額,現在是主流的 Web Server 之一。加之其可執行檔名為 httpd,所以很多後人也將 HTTPd 理解成 Apache 的代名詞,但這只是個誤解。

Apache 的設計理念,影響了很多後來的 Web Server,是開源世界和 Web 歷史中不能不提的一環。

值得一提的是,Apache 社群在 1999 年成立了 Apache Software Foundation(Apache 軟體基金會)組織,致力於支援開源軟體事業。我們今天談及 Apache,即指的是最初的 Apache HTTP Server,也指 Apache 軟體基金會。

正如前文提到的那樣,雖然被稱為 Apache HTTP Server,但它不僅僅支援 HTTP 協議及其衍生協議,還可以通過外掛的形式支援其他協議。

異軍突起:WebServer 之 IIS

1995 年 5 月,在令世界為之瘋狂的 Windows 95 上市的前三個月,Windows NT 3.51 釋出,這是 Windows NT 3.X 系列中的最後一個版本,也是第一個支援全中文的 Windows 作業系統。

隨著這一版本的釋出,一個名為 Internet Information Services(簡稱為 IIS,網際網路資訊服務)的系統可選元件悄然到來。

由於 IIS 是在 Windows 作業系統平臺下開發的,這也限制了它只能在 Windows 下執行,但它是首個支援以 GUI 方式配置的 Web Server。

Apache 一樣,IIS 也支援 HTTP 協議及其衍生協議、FTP 協議、SMTP 協議等。

隨著 Windows 的流行,IIS 也不斷進行版本迭代,它曾一度接近 Apache 的市場份額,現在也是主流的 Web Server 之一。

諸神崛起:PHP、JSP 還是 ASP?

CGI 程式一般由 C、C++、Pascal 等語言編寫,並在目標平臺上編譯成二進位制可執行程式,這給開發維護工作帶來了很多麻煩。

為了簡化 CGI 程式的修改、編譯和釋出流程,人們開始探尋用無需編譯的指令碼語言來實現 CGI 應用的道路。

很快,第一個用 Perl 寫成的 CGI 程式問世。很快,Perl 在 CGI 程式設計領域的風頭就蓋過了它的前輩 C 語言。隨後,Python 等著名的指令碼語言也陸續加入了 CGI 程式語言的行列。不過隨著 CGI 技術本身的衰落,Perl 最終在其後續版本中移除了 CGI 的相關模組。

1994 年,丹麥裔加拿大人 Rasmus Lerdorf 用 Perl 編寫了一個簡單的程式,用於統計他的個人主頁的訪問者。後來,Rasmus Lerdorf 用 C 語言重新編寫了一遍這個程式,並在 1995 年以 Personal Home Page Tools(簡稱為 PHP Tools,個人主頁工具)的名義開源了 PHP 1.0 版本。

在這早期的版本中,提供了訪客留言本、訪客計數器等簡單的功能。以後越來越多的網站使用了 PHP,並且強烈要求增加如迴圈語句、陣列變數等新特性,在新的社群成員加入開發行列後,1995 年,PHP 2.0 版本順利釋出。在這個版本中,PHP 新增了對 MySQL 資料庫的支援,從此建立了其在動態網頁開發上的地位。

PHP 最早使用 CGI 的工作方式(即 php-cgi),後因為這種方式的效能損耗很大,所以又開發了基於 FastCGI 的版本(即 php-fpmPHP FastCGI Process Manager 的縮寫)。

但與早期 CGI 不同的是,PHP 首次將 HTML 程式碼和 PHP 指令合成為完整的服務端文件,Web 應用的開發者可以用一種更加簡便、快捷的方式實現動態 Web 網頁功能。

1996 年,Microsoft 公司在借鑑了 PHP 的思想後,在其產品 IIS 3.0 版本中引入了名為 Active Server Pages(簡稱為 ASP,動態伺服器網頁)的技術。

ASP 使用的指令碼語言是 JScript 和 VBScript。藉助 Microsot Office FrontPage、Microsoft Visual Studio 等開發工具在市場上的成功,ASP 迅速成為了 Windows 系統下 Web 服務端的主流開發技術。

需要說明的,Microsoft 在之後的 .NET Framework 和 .NET Core 體系中,還分別引入的名為 ASP .NETASP .NET Core 的技術。如果說後兩者還師出同門,只不過一個只在 Windows 上執行、一個能跨平臺執行;而 ASP 則和後兩者只有名字上得到了傳承,實際上已經沒什麼關係了。

當然,以 Sun 公司為首的 Java 陣營也不會示弱。1997 年,Servlet 技術問世。1998 年,Java Server Pages(簡稱為 JSP,Java 伺服器頁面)技術誕生。

其中 Servlet 類似於 CGI/FastCGI 處理;JSP 則類似於 PHP 的 HTML 模版。前者對於拼接 HTML 不是很擅長,後者對於運算和邏輯寫起來又很繁瑣,那麼有沒有可以把二者優勢相結合的辦法呢?

答案是肯定的,這也就是著名的 MVCModel-View-Controller)架構。雖然 MVC 架構早在 1978 年就在 Smalltalk 上提出,在 GUI 領域上也有 Microsoft 推出的 Microsoft Foundation Classes(簡稱為 MFC,微軟基礎類庫)豐富實踐,但這還是首次在 Web 領域得到應用。

這種 Servlet + JSP 組合的方式,後來也反過來影響了之前出現的 PHPASP,二者最終在後續版本中引入了類似的功能。

至此,擴充套件到 Web 領域的語言(如 Perl、Python),以及專為 Web 而生的語言(如 PHP、ASP、JSP),這些主流的指令碼語言已全部出現,它們最終引領了 Web 下一個時代的前進方向。

容器之路:WebServer 之 Apache Tomcat

上文提到,無論 Apache 也好、IIS 也罷,本身並不直接生成動態頁面,而是需要以 CGI/FastCGI 的方式將 HTTP 請求轉發給相應的處理程式,才能返回動態頁面。

PHPASPJSP 等指令碼語言的出現,雖然已經不需要 Web 開發人員手工編寫複雜的 CGI/FastCGI 程式來解析、封裝 HTTP 報文,而是專注於業務邏輯本身即可。但這種方式其實質還是 Web Server + CGI/FastCGI 二者獨立執行的方式。

那麼有沒有直接能生成動態 HTML 內容、無需 CGI/FastCGI 配合的 Web Server 呢?

1999 年,Tomcat 應運而生。Tomcat 既是 HTTP Web Server,也是 Java 執行容器,它由 Catalina Servlet 容器、Coyote 聯結器、Jasper JSP 引擎等元件組成,可以直接輸出動態 HTML 文件。

由於 Tomcat 也是 Apache 軟體基金會的頂級專案之一,所以也被稱為 Apache Tomcat

早期的 Tomcat 由於效能不佳(尤其是針對純靜態內容),通常還是要與 Apache HTTP Server 或者其他 Web Server 一起工作,除了用於開發過程中的除錯以及那些對速度要求很低的開發者,很少會將 Tomcat 單獨作為 Web Server。

這也給很多人造成了誤解,以為 Tomcat 是那些基於 CGI/FastCGI 技術的指令碼語言類似,是專門執行 ServletJSP 的程式。其實這也是一種誤解,無論是 Servelet 還是 JSP,它們都比 Tomcat 面世的要早;而 Tomcat 完全可以脫離 Apache HTTP Server 獨立執行,充當 Web Server。

但隨著 Tomcat 版本的不斷迭代,以及 Web Server 叢集技術的廣泛使用,正有越來越多的開發者將其單獨作為 Web Server。

為了和早期那種只支援靜態網頁的 Web Server 加以區分,我們把這類 Web Server 也稱之為 Application Server,即應用伺服器。

Tomcat 這種 Web Server + 執行容器的雙重身份的方式,後來也有越來越多的 Java 開源產品採用,諸如 JettyNettyUnderow 等等。

值得一提的是,2014 年,Microsoft 釋出了 ASP .NET vNext 首個預覽版,也就是後來的 ASP .NET Core,從這一版本開始,Microsoft 也實現了類似的產品,名為 Kestrel Server

風起雲湧:libevent、libev、libuv,C10K 的法寶

網路通訊,本質上就是對網路卡或網路虛擬裝置進行 I/O 操作。

早期的作業系統,基本都是阻塞 I/O(即 BIO),這種方式在面對大量併發時,會顯得力不從心。上文提到的各種 Web Server 都是基於這種實現方式。

在這一時期,很多 Web Server 都會遇到著名的 “C10K” 問題,即:當請求的併發數量達到一萬後,Web Server 的效能會隨之急劇下降。

為了緩解併發問題,後來又出現了非阻塞 I/O(即 NIO)、非同步 I/O (即 AIO)、I/O 多路複用等模型。例如 Unix 系統下的 pollselect,Solaris 系統下的 /dev/poll,BSD 系統下的 kqueue,Linux 系統下的 epoll,Windows 系統下的 IOCP 等等。它們各自的區別和優缺點我們這裡不做展開,感興趣的朋友可以自己搜尋相關資料。

2000 年,libevent 問世。這是一個由 C 語言編寫的、輕量級的開源高效能事件驅動程式設計庫。起初它只相容類 Unix 作業系統,在其他系統上效能並不高,後來在社群的推動下才慢慢支援 Windows 等作業系統的 IOCP 模型。不過因為它歷史悠久,社群活躍,很多出生較早的專案基本都會選擇它作為網路程式設計庫。

目前使用 libevent 的知名專案有:MemcachedGoogle ChromentpdTor(洋蔥路由)等等。

2007 年,為解決 libevent 多執行緒全域性變數不安全、元件質量參差不齊等問題,Marc Lehmann 決定精簡 libevent,去掉多餘的元件(如 HTTP 和 DNS),只專注於事件驅動,並最終形成了 libev。可以理解為 libevlibevent 的一個分支版本。目前這一分支作者已停止維護,而且 libeventlibuv 卻在社群推動下飛速發展,所以最後很多專案都不再使用 libev

目前 libev 使用它的知名專案有 ShçdôwSôcks(河蟹拼法)、Node.js 早期版本。

2011 年,在使用了 libev 作為內建 Web Server 僅僅兩年後,Node.js 社群意識到了一些問題。一是前面提到專案維護問題;二是因為 Node.js 的日益流行,迫切需要跨平臺支援。因此,由 Node.js 之父 Ryan Dahl 主導的 libuv 誕生。它也是由 C 語言編寫,提供對基於事件迴圈的非同步 I/O 的跨平臺支援。最終,在 Node.js 0.9 版本中,libuv 完全取代了 libev

目前使用 libuv 的知名專案有:Node.jsASP .NET CoreCMakeJulia 等等。

事件驅動程式設計的流行,給 Web Server 開發帶來來新的活力,很多程式語言都加入了對它們的封裝引用,可以很方便、快捷地搭建出一個簡單的 Web Server。但通常來說,都是用於快速搭建開發測試環境,目前還有沒有一款基於此的、獨立的 Web Server 產品出現。

後起之秀:WebServer 之 Nginx

2004 年,俄羅斯人 Igor Vladimirovich Sysoev 在經過了兩年的開發後,釋出了名為 Nginx 的 Web Server。

NginxEngine X 的縮寫,即“超級引擎”之意。在設計之初,Nginx 就被賦予了一個明確的目標:全面超越 Apache HTTP Server 的效能。

Nginx 同時支援 NIO、AIO 兩種 I/O 模型,在能支援大量併發連線的情況下,降低了記憶體佔用,並提高了系統穩定性,完美地解決了 C10K 問題。

雖然 Nginx 在 Windows 系統上不如 Apache 表現穩定,更遑論 Microsoft 的親兒子 IIS 了。但它的可擴充套件性和高效能,仍然吸引著大量開發者使用。

不過隨著雲平臺的興起,Niginx 又成為了很多雲廠商的首選。例如:

  • Kubernetes 選擇其作為 Ingress-Controller 元件的官方實現。
  • OpenRestry 選擇其作為公司旗下平臺產品的基礎元件。
  • 阿里巴巴集團選擇其二次開發,命名為 Tengine,是阿里雲負載均衡器產品的基礎元件,也是淘寶系統的重要組成部分。

截止目前為止,Nginx 已佔據了 36% 以上的 Web Server 市場份額,正逐漸蠶食著 ApacheIIS 的市場份額。

長江後浪:WebServer 之 Netty

2011 年,在從 RedHad(紅帽)公司獨立出來並開源後,Netty,這個脫胎於 JBoss 的專案,在被 RedHat 收購之後,才終於迎來了它的高速發展期。

由於誕生日期很晚,在吸收了早期其他 Web Server 的經驗教訓後,Netty 直接採用了 NIO 的 I/O 模型,實現了其更高的併發效能。

Tomcat 一樣,Netty 也是一個 Java 實現的 Web Server。這裡要指出的是,後來 Tomcat 也支援了 NIO,還新引入了 APR 技術,所以目前 Netty 帶來的效能優勢已經不是很明顯。

但與 Tomcat 是支援七層的 HTTP 等協議不同的是,而 Netty 是從四層開始支援 TCPUDP 等協議,除了充作 HTTP Web Server 外,還可以實現自己的高效能私有協議(如 RPC 協議)Web Server。


群星璀璨:其他知名 Web Server

本文著重介紹了早期的、和一些現階段流行的 Web Server。

實際上,Web Server 領域曾經有無數的優秀作用,也正興起著更多的、功能更強大的產品。

下面按釋出時間順序,列舉另外一批比較出名的 Web Server:

  • thttpd:1995 年由 Jeffrey A. Poskanzer 開源的專案,由 C 語言編寫。其得名於 Tiny HTTPd,意為“微小的 HTTPd”。因其功能簡單,且只支援類 Unix 系統,所以佔用資源消耗可以優化到很低,曾被視為是 Apache 的輕量級替代品,現在常被用於如路由器一類的嵌入式裝置。該專案目前仍在維護,最新一個版本是 2018 年推出的 2.29 版。
  • Jetty:1995 年由 Greg Wilkins 開發的專案。最初起名為 IssueTrackerMBServler,後在使用 Java 重構後更名為 Jetty。2009 年專案被移交給 Eclipse 基金會。隨著大資料技術的興起,Jetty 因被整合在 Apache Hadoop 專案中而得以名聲大噪,現在是 Eclipse IDE 和 Spring Boot 的內建容器之一。該專案目前仍在維護,最新一個版本是 2020 年推出的 11.0.0 版。
  • WebLogic:1997 年由 Oracle(甲骨文)公司推出的商業產品,由 Java 編寫。最初的產品名為 WebLogic Tengah,後更名為 WebLogic Server。它是世界上第一個成功商業化的 J2EE 應用伺服器。該產品目前仍在維護,最新一個版本是 2014 年推出的 12.1.3 版。
  • WebSphere:1998 年由 IBM 公司推出的商業產品,由 Java 編寫,同樣也是一款 J2EE 應用伺服器。該產品目前仍在維護,最新一個版本是 2018 年推出的 9.0.5 版本。
  • lighttpd:2003 年由 Jan Kneschke 開源的專案,由 C 語言編寫。其得名於 Lighty HTTPd,意為 “輕量級 HTTPd”。lighttpd 的原始碼十分簡潔精練,有著很多擁躉。Bloglines、Meebo、YouTube(油管)、Wikipedia(維基百科)等著名網站都使用過 lighttpd 作為 Web Server,也被如路由器等很多嵌入式裝置使用。該專案目前仍在維護,最新一個版本是 2020 年推出的 1.4.55 版。
  • Jexus:2008 年由 @宇內流雲(本名劉冰)推出的免費產品,基於 Mono 的 .NET 跨平臺 Web Server,可理解為 Linux 系統下的 IIS。支援 ASP .NET、ASP .NET Core、PHP、Node.js 等語言。搭配 Jexus Manager 可實現 GUI 化配置。該產品目前仍在維護,最新一個版本是 2018 年推出的 6.2 版。
  • Cherokee:2010 年由 Álvaro López Ortega 開源的專案,由 C 語言編寫。號稱比 Nginx 效能更高,但記憶體消耗會更大一些。功能豐富,支援 GUI 配置介面。該專案目前仍在維護,最新一個版本是 2013 年推出的 1.2.103 版。
  • Mongoose:2011 年由 Sergey Lyubka 開源的專案,由 C 語言編寫。除 HTTP 協議及其衍生協議外,還支援 MQTT 和更底層的 TCP 協議,所以現在常被用於物聯網智慧裝置中。該專案目前仍在維護,最新一個版本是 2020 年推出的 6.18 版。(注意:要與 MongoDB 資料庫中的 Mongoose 相區分,兩者沒有關係)
  • Underow:2013 年由 RedHat 公司開源的專案,由 Java 編寫。同樣是 Spring Boot 內建容器之一。該專案目前仍在維護,最新一個版本是 2020 年推出的 2.1.3 版。
  • Caddy:2015 年由 Matthew Holt 開源的專案,由 Golang 編寫。以開箱即用著稱,內建 Markdown 預覽功能,實現了 HTTPS 證照自動續約,支援豐富的擴充套件外掛。這是一款新興的 Web Server,目前還沒有得到大規模的企業級服務端應用,反倒在搭建私人網站、網路硬碟等方面受到了個人使用者歡迎。該專案目前仍在維護,最新一個版本是 2020 年推出的 2.0.0 版。

尾聲

本文以時間線為基準,談到了幾個流行的 Web Server 及動態網頁的發展。

其實無論是 Web Server,還是可用作動態網頁的程式語言,都遠不止提到的這些,但其他的都沒有這些流行,這裡也就不費筆墨。

下面我們再總結梳理一下時間線:

時間 事件
1990 年 Tim Berners-Lee 創造了 Common Library,又名 CERN HTTPd
1991 年 NCSA 提出 SSI 概念。
1993 年 Common Library 開源,更名為 libwww
1993 年 NCSA 仿 libwww 創造了 NCSA HTTPd,實現了 SSI,並提出了 CGI 概念。
1994 年 libwww 專案移交給 W3C,又稱 W3C HTTPd
1995 年 Jeffrey A. Poskanzer 開源 thttpd
1995 年 Rasmus Lerdorf 開源 PHP 技術。
1995 年 Microsoft 公司釋出 IIS
1995 年 NCSA HTTPd 的基礎上,Brian Behlendorf 領導產生了新的分支 Apache
1995 年 Greg Wilkins 開發了 IssueTracker,又名 MBServler
1996 年 W3C 開源 Jigsaw
1996 年 Microsoft 公司釋出 ASP 技術。
1997 年 Sun 公司釋出 Java Servlet 技術。
1997 年 Oracle 公司釋出 WebLogic
1998 年 Sun 公司釋出 Java JSP 技術。
1998 年 IBM 公司釋出 WebSphere
1999 年 Apache 社群開源 Tomcat
2000 年 libevent 程式設計庫問世。
2003 年 Jan Kneschke 開源 lighttpd
2004 年 Igor Vladimirovich Sysoev 開源 Nginx
2005 年 libev 程式設計庫問世。
2008 年 @宇內流雲(本名劉冰)釋出 Jexus
2009 年 IssueTracker 專案移交給 Eclipse 基金會,更名為 Jetty
2010 年 Álvaro López Ortega 開源了 Cherokee
2011 年 libuv 程式設計庫問世。
2011 年 Sergey Lyubka 開源了 Mongoose
2011 年 RedHat 公司開源了 Netty
2013 年 RedHat 公司開源了 Underow
2014 年 Microsoft 公司開源了 Kestrel Server
2015 年 Matthew Holt 開源了 Caddy

注:文章中的所有人物、事件、時間、地點,均來自於網際網路公開內容,由本人進行蒐集整理,其中如有謬誤之處,還請多多指教。


參考閱讀


首發於 Segmentfault.com,歡迎轉載,轉載請註明來源和作者。

RHQYZ, Write at 2020.06.29.

相關文章