博客 / 詳情

返回

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

引言

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

全系列索引:

  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 了。但它的可擴展性和高性能,仍然吸引着大量開發者使用。

不過隨着雲平台的興起,Nginx 又成為了很多雲廠商的首選。例如:

  • 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

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


參考閲讀

  • 《Wikipedia - Hypertext》
  • 《Wikipedia - SGML》
  • 《Wikipedia - HTML》
  • 《Wikipedia - HTTP》
  • 《Wikipedia - URI》
  • 《Wikipedia - CSS》
  • 《Wikipedia - JavaScript》
  • 《Wikipedia - Web Server》
  • 《Wikipedia - HTTPd》
  • 《Wikipedia - PHP》
  • 《Wikipedia - ASP》
  • 《Wikipedia - JSP》
  • 《Wikipedia - libevent》
  • 《Wikipedia - libev》
  • 《Wikipedia - libuv》
  • 《Jigsaw - W3C's Server》
  • 《The C10K Problem》
  • 《維基百科:瀏覽器大戰》
  • 《Web 發展簡史》
  • 《上都(Xanadu)、網絡文化及其他》
  • 《萬法歸宗 —— CGI》
  • 《Apache 與 Nginx:80 端口爭奪戰》

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

RHQYZ, Write at 2020.06.29.

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.