引言
本文是继《编程时间简史系列》的第二篇文章。
全系列索引:
- 《编程时间简史系列》JavaScript 模块化的历史进程
- 《编程时间简史系列》Web Server 编年史
互联网今天已经广泛存在于人们的生活中,人们的衣食住行等方方面面早已离不开互联网的支撑,这其中离不开 Web 技术的发展。
Web 是一种典型的分布式应用架构。Web 应用中的每一次信息交换都要涉及到客户端和服务端两个层面。因此,Web 开发技术大体上也可以被分为客户端技术和服务端技术两大类。
本文将会讲述 Web 服务端技术的萌芽和演进过程,旨在使读者能更清晰地掌握 Web 服务端技术的发展脉络。
Web 服务端技术的发展与客户端技术的进步是相辅相成的,本文虽是讨论 Web 服务端,在讲述过程中却不可避免地会提及一些 Web 客户端的有关内容,但不会过多深入。对此感兴趣的读者,可以自行阅读最下方的参考链接。
同样的,不谈具体代码,只聊历史故事。
P.S. 下一篇的选题还没有敲定,如果有朋友想了解某一方面的历史又苦于没有资料,可以在文章下方给我留言。
正文
广义上的 Web Server(Web 服务器),包含硬件和软件两方面。今天我们只谈及其中的软件部分,即能向客户端提供 Web 服务的程序。
现在大家耳熟能详的 Apache、IIS、Tomcat、Nginx 等等,都属于 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 Nelson 和 Charles 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. Goldfarb 的 GML/SGML 实现后,Tim Berners-Lee 于 1990 年发明了 Hypertext Markup Language(简称为 HTML,超文本标记语言)和 Hypertext Transfer Protocol(简称为 HTTP,超文本传输协议),并创建了一款最原始的 GUI 的 Web 浏览器。
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(1995 年)、Microsoft 1995 年发明的 JScript、Adobe 1999 年发明的 ActionScript 等诸多实现。在接下来的几年时间里,这一标准规范同样被 ISO(国际标准化组织)及 IEC(国际电工委员会)所采纳。
1997 – 1999 年,HTML 3.0、HTTP/1.1、HTML 4.0、CSS 2、ECMAScript 3 等标准先后被发布,并统治了今后二十余年的互联网。
终于,Web 时代降临。
开天辟地:CERN HTTPd 和 NCSA HTTPd
HTTPd,即 HTTP daemon 的缩写。
今天我们谈到这个名词,大部分人会把它认为是 Apache 的代名词。但这其实只是个误解,实际上来说,它应该是等同于 Web Server。
在类 Unix 的操作系统中,一个在后端周期性地执行某种任务或等待处理理某些事件的进程,往往被称为 “Daemon Process”(守护 / 幽灵进程)。HTTPd 即取此意,意思就是在后台处理 HTTP 请求的程序。
1991 年,Tim Berners-Lee 在一台运行着 NeXTSTEP 操作系统的 NeXT Computer 上完成了首个 HTTPd 程序的编写,起名为 Common Library。这是一个由 C 语言编写的组件,只能处理 HTTP 请求中的 GET 谓词,并不是一个独立且完整的程序。因其属于 CERN 项目的一部分,所以也被称为 CERN HTTPd。
1993 年,Tim Berners-Lee 将 Common Library 从 CERN 项目中独立出来,更名为 libwww 并开源。
同年,NCSA 在此基础之上扩展并开发出了 NCSA HTTPd。
1994 年,libwww 的开发维护工作转交给了 W3C,在此阶段,libwww 新增了很多特性,诸如兼容 HTTP/1.0、支持 CGI、虚拟主机等。此时它也被称为 W3C HTTPd。
1996 年,W3C 的工作重心已经不在 libwww 上,迟迟没有新版本发布,并最终于 2003 年宣告项目中止。
libwww 被广泛使用在包括 Mosaic、Lynx、Arena、MacWWW 在内的诸多早期 Web 程序中。
胎死腹中:夭折的 Jigsaw
上一小节提到,1996 年时 W3C 的工作重心已经不在 libwww 上,因为他们已经另有其他重点工作。
由于 libwww 只能被编译到类 Unix 的操作系统中,且只支持静态网页。随着 Web 技术的不断发展,以及 Windows 系统的广泛流行,W3C 亟需一种可以跨平台的的 Web 服务器。因此,W3C 将目光放在了 1994 年横空出世、并在两年后有了迅猛发展的一种跨平台编程语言 —— Java。
W3C 联合当时的拥有 Java 的 Sun(升阳)公司,开发了一个名为 Jigsaw 的程序。
这是一个由 Java 编写的 HTTPd 模块,起初只作为 JDK 1.2 版本的一部分发布,意图让开发者能快速搭建一个跨平台 Web 服务器项目。它采用了多线程的处理方式,兼容 HTTP/1.1,支持 SSL/TLS、WebDAV 等新特性,同时也是首个支持 JSP 和 Servlet 的服务器程序。由于 Java 的跨平台特性,它可以运行在 BeOS、AS-400、AIX、Unix、Solaris 2、OS/2、MacOS、Linux、Windows 95、Windows NT 等操作系统上。
但遗憾的是,W3C 组织内的大部分成员,都是 IT 巨头公司,随着它们各自分别发布了不同的 Web 服务器程序后,加之 Nginx 等开源产品的兴起,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 公司的 JScript、VBScript、Adobe 公司的 Flash、ActionScript 等等。另一条是试图从服务端、即 Web Server 入手,想在返回给客户端时就输出动态的内容。这两条路线都在未来有了十分迅猛的发展,我们今天按下客户端不表,只谈服务端这面。
1991 年,NCSA 首次提出了 Server Side Includes(简称为 SSI,服务端嵌入)的概念,并在之后发布的 NCSA HTTPd 中实现这一技术。
不过 SSI 的功能十分有限,通常用于实现网站页面的公共部分引用,比如在网页底部重复出现的版权声明等信息。它既不支持运算表达式,也不能根据逻辑条件判断是否输出特定内容。所以虽然早期的 Web Server 都支持这种技术,但它并没有被广泛使用。
1993 年,在 NCSA 发布 NCSA HTTPd 的同时,NCSA 又提出了 Common Gateway Interface(简称为 CGI,通用网关接口)这一概念,并在未来几年内先后制订了 CGI 1.0、CGI 1.1、CGI 1.2 等标准。
CGI 本质上来说,就是接受一个输入、并返回一个输出的程序。CGI 独立于 Web Server 存在,在收到特定请求后(这些请求通常以 /cgi-bin/
路径开头),Web Server 将 HTTP 请求的内容作为参数传递给 CGI 程序,并将 CGI 程序的返回值作为 HTTP 响应返回给客户端。所以 CGI 程序不能独立运行,需要配合 Web Server 才能工作。
早期通常是在 Web Server 接受到一个请求后,开启一个新的进程来执行 CGI 程序,这种方式在请求量稍微大一些时,就会严重拖累服务器的性能。
所以,FastCGI(简称为 FCGI)技术应用而生。简单来说,就是一个常驻内存的进程池技术,可以复用进程,使得 CGI 的性能大大提升。
在今天,由于 CGI 编写的复杂难度过大,已经很少有人再直接应用这种技术(间接的还有很多)。但它的出现,给其他编程语言带来了启发,诸如 FCGI、SCGI、WSGI、Servlet 乃至后来的动态脚本语言等技术不断涌现,它们都滥觞于 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 协议及其衍生协议,还可以通过插件的形式支持诸如 FTP、SMTP 等协议。
异军突起: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 应用的可行方式。
1995 年,第一个用 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-fpm
,PHP 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 .NET 和 ASP .NET Core 的技术。如果说后两者还师出同门,只不过一个只在 Windows 上运行、一个能跨平台运行;而 ASP 则和后两者只有名字上得到了传承,实际上已经没什么关系了。
当然,以 Sun 公司为首的 Java 阵营也不会示弱。1997 年,Servlet 技术问世。1998 年,Java Server Pages(简称为 JSP,Java 服务器页面)技术诞生。
其中 Servlet 类似于 CGI/FastCGI 处理;JSP 则类似于 PHP 的 HTML 模版。前者对于拼接 HTML 不是很擅长,后者对于运算和逻辑写起来又很繁琐,那么有没有可以把二者优势相结合的办法呢?
答案是肯定的,这也就是著名的 MVC(Model-View-Controller)架构。虽然 MVC 架构早在 1978 年就在 Smalltalk 上提出,在 GUI 领域上也有 Microsoft 推出的 Microsoft Foundation Classes(简称为 MFC,微软基础类库)丰富实践,但这还是首次在 Web 领域得到应用。
这种 Servlet + JSP 组合的方式,后来也反过来影响了之前出现的 PHP 和 ASP,二者最终在后续版本中引入了类似的功能。
至此,扩展到 Web 领域的语言(如 Perl、Python),以及专为 Web 而生的语言(如 PHP、ASP、JSP),这些主流的脚本语言已全部出现,它们最终引领了 Web 下一个时代的前进方向。
容器之路:WebServer 之 Apache Tomcat
上文提到,无论 Apache 也好、IIS 也罢,本身并不直接生成动态页面,而是需要以 CGI/FastCGI 的方式将 HTTP 请求转发给相应的处理程序,才能返回动态页面。
PHP、ASP、JSP 等脚本语言的出现,虽然已经不需要 Web 开发人员手工编写复杂的 CGI/FastCGI 程序来解析、封装 HTTP 报文,而是专注于业务逻辑本身即可。但这种方式其本质还是 Web Server + CGI/FastCGI 的方式。
那么有没有直接能生成动态 HTML 内容的 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 技术的脚本语言类似,是专门运行 Servlet + JSP 的程序。其实这也是一种误解,无论是 Servelet 还是 JSP,它们都比 Tomcat 面世的要早;而 Tomcat 完全可以脱离 Apache HTTP Server 独立运行,充当 Web Server。
但随着 Tomcat 版本的不断迭代,以及 Web Server 集群技术的广泛使用,正有越来越多的开发者将其单独作为 Web Server。
为了和早期那种只支持静态网页的 Web Server 加以区分,我们把这类 Web Server 也称之为 Application Server,即应用服务器。
Tomcat 这种 Web Server + 执行容器的双重身份的方式,后来也有越来越多的 Java 开源产品采用,诸如 Jetty、Netty、Underow 等等。
值得一提的是,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 系统下的 poll
、select
,Solaris 系统下的 /dev/poll
,BSD 系统下的 kqueue
,Linux 系统下的 epoll
,Windows 系统下的 IOCP
等等。它们各自的区别和优缺点我们这里不做展开,感兴趣的朋友可以自己搜索相关资料。
2000 年,libevent 问世。这是一个由 C 语言编写的、轻量级的开源高性能事件驱动编程库。起初它只兼容类 Unix 操作系统,在其他系统上性能并不高,后来在社区的推动下才慢慢支持 Windows 等操作系统的 IOCP 模型。不过因为它历史悠久,社区活跃,很多出生较早的项目基本都会选择它作为网络编程库。
目前使用 libevent 的知名项目有:Memcached、Google Chrome、ntpd、Tor(洋葱路由)等等。
2007 年,为解决 libevent 多线程全局变量不安全、组件质量参差不齐等问题,Marc Lehmann 决定精简 libevent,去掉多余的组件(如 HTTP 和 DNS),只专注于事件驱动,并最终形成了 libev。可以理解为 libev 是 libevent 的一个分支版本。目前这一分支作者已停止维护,而且 libevent 与 libuv 却在社区推动下飞速发展,所以最后很多项目都不再使用 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.js、ASP .NET Core Kestrel Server、CMake、Julia 等等。
事件驱动编程的流行,给 Web Server 开发带来来新的活力,很多编程语言都加入了对它们的封装引用,可以很方便、快捷地搭建出一个简单的 Web Server。但总的来说,目前还有没有一款基于此的、完全独立的 Web Server 产品出现。
后起之秀:WebServer 之 Nginx
2004 年,俄罗斯人 Igor Vladimirovich Sysoev 在经过了两年的开发后,发布了名为 Nginx 的 Web Server。
Nginx 是 Engine 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 市场份额,威胁着 Apache 与 IIS 的市场地位。
长江后浪: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 是从四层开始支持 TCP、UDP 等协议,除了充作 HTTP Web Server 外,还可以实现自己的高性能私有协议(如 RCP 协议)Web Server。
群星璀璨:其他知名 Web Server
本文着重介绍了早期的、和一些现阶段流行的 Web Server(又名 HTTPd)。
实际上,Web Server 领域曾经有无数的优秀作用,也正兴起着更多的、功能更强大的产品。
由于篇幅原因,这里我们不做更多的详细介绍,但会在下面按发布时间顺序列举一些比较出名的 Web Server:
-
thttpd:1995 年由 Jeffrey A. Poskanzer 开源的项目,由 C 语言编写。其得名于
Tiny HTTPd
,意为“微小的 HTTPd”。因其功能简单,且只支持类 Unix 系统,所以占用资源消耗可以优化到很低,曾被视为是 Apache 的轻量级替代品,现在常被用于如路由器一类的嵌入式设备。该项目目前仍在维护,最新一个版本是 2018 年推出的 2.29 版。 - Jetty:1995 年由 Greg Wilkins 开发的项目。最初起名为 IssueTracker、MBServler,后在使用 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,还是可用作动态网页的编程语言,都远不止提到的这些,但其他的都没有这些流行,这里也就不费笔墨。
下面我们再总结梳理一下时间线:
时间 | 事件 |
---|---|
1991 年 | 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 年 | Perl 语言开始支持 CGI 编程。 |
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 技术。 |
1998 年 | Sun 公司发布 Java Servlet 技术。 |
1997 年 | Oracle 公司发布 WebLogic。 |
1998 年 | Sun 公司发布 Java JSP 技术。 |
1998 年 | Python 语言开始支持 CGI 编程。 |
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.