ATF Jubilee Edition

作者:Reuven M. Lerner

欢迎来到“At the Forge”专栏的周年纪念版。这是自 1996 年初以来,我为Linux Journal(或为 SSC 短暂的 Websmith 杂志)撰写的第 50 篇专栏文章。在过去的几年里,我们探讨了大量与 Web 相关的技术、技巧和应用程序,从简单的 CGI 程序到使用 mod_perl 编写的复杂的数据库支持的应用程序。

本月,我想花一些时间预测一下 Web 应用程序开发的未来。一方面,对于 Web 应用程序开发人员来说,情况从未如此令人兴奋;技术继续以惊人的速度进步,使得创建复杂的应用程序变得越来越容易。与此同时,嵌入式编程语言、应用服务器和数据库适配器领域越来越拥挤,使得决定哪种技术最合适变得更加困难。

由于本专栏描述了我认为 Web 技术和应用程序开发在未来几年的发展方向,因此它也应该作为未来 ATF 专栏内容的某种指南。您可以将本月的专栏文章看作是指示我的咨询公司在专业领域的发展方向,以及您可以期望我在未来一年(或更长时间!)中建议和描述的内容。由于这里是 Linux Journal,而 Linux 是我公司的主要服务器平台,因此我将在此重点关注在 Linux 上运行的项目,最好是那些自由软件。

我们走过哪些路?

Web 应用程序开发始于 Web 本身形成之后不久。自从第一个动态生成的内容被发送到第一个浏览器——这一行为早于 CGI 标准,更不用说 Netscape、Internet Explorer 和 Apache——程序员们一直在设计越来越复杂的应用程序以供在 Web 上使用。

CGI,或“通用网关接口”,很快就出现在舞台上。CGI 得名于动态生成的内容最初是为非 Web 应用程序提供 Web 界面的手段。随着 CGI 的出现,突然可以创建可移植的服务器端程序。大多数 Web 应用程序继续使用 CGI 编写,因为它的简单性和极端的平台独立性,以及 Web 空间提供商可以在不危及服务器稳定性的情况下向其客户提供 CGI 访问权限。

您可以为任何 Web 服务器、任何语言、任何操作系统编写 CGI 程序,并且几乎可以保证它能够工作。但是,CGI 有许多缺点。特别是,它要求 Web 服务器为每个针对 CGI 程序的 HTTP 请求生成一个新进程。换句话说,一个每分钟接收 100 次点击的网站每秒钟会生成不止一个新进程。

就其本身而言,这不应该吓到您。毕竟,一个基本的 Linux 计算机应该能够处理每秒创建一个新进程,对吧?但是,新进程的大小以及它启动的速度都是重要的因素。

Perl,我在过去几年中选择的编程语言,已被证明是创建 CGI 程序的强大手段。CGI.pm 模块提供了惊人的一系列功能,几乎可以完成您对 CGI 程序的任何期望(以及许多我从不考虑做的事情)。此外,Perl 还包括一个强大的模式匹配引擎,以及处理大多数流行的 Internet 标准和协议的模块。DBI(数据库接口)模块已被证明是一个额外的福音,可以轻松地将 SQL 查询的输出包含在动态生成的页面中。

无论 Perl 多么强大、灵活和安全,CGI 标准的设计初衷都不是为了即时生成大量动态页面。每次调用用 Perl 编写的 CGI 程序都会迫使计算机创建一个新进程,将 Perl 加载到内存中,将您的程序加载到内存中,将您的程序编译成 Perl 的内部操作码,然后最终使用 Perl 运行时机制对其进行解释。这一切都需要时间,这意味着 CGI 程序从长远来看无法很好地扩展。实际上,不需要太多并发运行的 CGI 程序就可以使典型的服务器瘫痪。

与此同时,CGI 已经成功,因为它非常易于使用。没有其他 API 可以编写像下面这样简单的“hello, world”程序

#!/usr/bin/perl -wT    use strict;
    use CGI;
    my $query = new CGI;
    pring $querry->heder("text/html");
    print $query->start_html;
    print "P>Hello, world!</P>\n";
    print $query-> end_html;
嵌入式语言

在过去的几年里,高级 Web 开发已经成为一门专门的学科,要求程序员学习一些关于管理系统、网络和数据库的知识,同时牢记良好的编程和安全实践。

Web 开发领域目前有三个趋势,这些趋势开始为用户和开发人员显着改善情况。当这三者结合使用时,它们通常被称为“应用服务器”。

第一个趋势是架构上的,即从单次 CGI 程序转向在 Web 服务器或其他环境中缓存的程序。我们使用 CGI 程序创建动态内容的唯一原因是 Web 服务器本身无法即时创建我们的自定义 HTML 文件。从理论上讲,我们可以用 C 为 Apache 编写一个新模块,并将其编译到我们的配置中——但在大多数情况下,这工作量太大,并且节省的时间不值得。

但是,将自定义代码放在服务器内部和完全放在外部之间存在一个中间地带。如果我们将整个编程语言放在服务器内部,使我们有可能用该语言添加新功能呢?如果该语言是解释型的,那么我们可以修改和调试我们的新功能,而无需重新编译或重启服务器。

这就是 mod_perl 背后的想法,它在 Apache 内部嵌入了一个 Perl 副本。它为我们提供了 Apache 内部结构的 Perl 语言接口,使我们能够访问和修改与请求对象相关的任何内容。C 语言模块可以为 Apache 做的所有事情也可以在 mod_perl 内部完成,从创建自定义响应处理程序到更改身份验证的执行方式。

与 CGI 程序形成鲜明对比的是,在 CGI 程序中,Perl 编译程序一次,执行一次并退出,而 mod_perl 会缓存程序的编译版本,然后重复执行该版本。(这有时会导致极端的内存增长,并要求程序员格外小心。)

虽然 mod_perl 曾经是 Apache 唯一的嵌入式语言模块,但最近又出现了其他模块。mod_snake 为 Python 所做的事情与 mod_perl 为 Perl 所做的事情相同,使得可以使用 Python 编写自定义 Apache 处理程序。甚至还有一个 mod_tcl,它在 Apache 内部提供了嵌入式 Tcl,尽管我不知道有任何站点正在使用它的功能。

另一个开源 Web 服务器 AOLServer 长期以来一直包含一个嵌入式 Tcl 解释器。因此,Tcl 过程可以用于创建动态输出、连接到关系数据库以及使代码条件化——所有这些都在服务器本身内部完成,而无需转到外部 CGI 程序。

如果您更喜欢使用 Python 而不是 Tcl,那么 PyWX(Python Web Extensions)的 Beta 版本最近已发布。PyWX 为 AOLserver 通常提供的所有 Tcl 功能提供了 Python API。虽然这使得 PyWX 与大多数可用于 AOLserver 的 Tcl 代码不兼容,但鉴于 Web 上可用的丰富 Python 模块,它确实使执行某些功能变得更容易。

混合代码和 HTML

第二个趋势涉及将代码嵌入到 HTML 中。Microsoft 的 Active Server Pages 可能是这种实践的最佳示例,但也有很多其他示例。在 Linux 上,我们可以从各种不同的系统中进行选择,范围从 Java Server Pages (JSP)、HTML::Mason(与 mod_perl 一起使用)、PHP 和 ADP。

自从 Java 首次推出以来,我就断断续续地使用过它,并且很久以前就确信花一些时间使用这种语言会很好。像许多其他人一样,我对小程序 (applet) 的想法感到厌烦,它们速度慢、不安全且错误百出。然而,近年来,服务器端 Java 变得越来越流行。每个 Java “servlet”都是一个在 Java 虚拟机 (JVM) 内部运行的类。Servlet 可以完成我们在生成动态内容时可能想要做的所有事情——它们可以使用 JDBC 与数据库对话,它们可以检索和修改 HTTP 标头,并且它们可以生成内容取决于用户偏好的响应。

JSP 通过假设除了 <% 和 %> 中包含的内容之外,所有内容都是文字 HTML,从而使使用 servlet 变得更容易。当从 Web 浏览器调用 JSP 时,JSP 会即时编译为 Java servlet,然后 Java servlet 又编译为 Java .class 文件。此 .class 文件被加载到 servlet 引擎中,执行并保留以供将来调用。JSP 和 servlet 可以使用 Java “beans”,对象,可以用于对持久行为进行建模,并实现位于大多数现代三层 Web 应用程序中间的“业务逻辑”。

mod_perl 是一个非常强大的工具,用于创建 Apache 处理程序,但有时它可能会迫使您在过低的级别上工作。因此,存在相当多的 Perl 模块,允许您以某种方式将 Perl 代码和 HTML 混合在一起。HTML::Mason,我在今年早些时候的一系列文章中对其进行了剖析,是我首选的系统,因为它语法简单,并且允许模板相互合并。今年秋天在伦敦举行的 YAPC::Europe 会议上,我看到了 Template Toolkit 的演示,它在理念上似乎与 HTML::Mason 相似,只是它添加了“插件”的概念。

虽然 Java 和 Perl 是通用编程语言,非常适合服务器端 Web 编程,但 PHP 是一种专门为创建动态网页而设计的语言。PHP 包含大量用于处理各种不同类型的文件、数据库和 Internet 标准的函数。最新版本的 PHP 甚至允许您使用 Java 对象,并且预计在不久的将来会发布 CORBA 适配器。与此同时,每次更改包含的功能集时,PHP 都需要重新编译;系统中没有动态添加或删除模块的概念。如果您在决定要处理 PDF 文件之前安装了 PHP,您可能会发现自己需要重新编译它,仅仅是为了添加此类功能。

AOLServer 的用户可以使用类似的系统,称为 ADP (“AOLServer 动态页面”)。ADP 页面允许您将 Tcl 与 HTML 混合使用,其中 Tcl 可以使用 AOLServer 中定义的许多特殊过程中的任何一个。因此,您可以创建一个 ADP 页面,该页面从数据库检索信息,解释从另一个服务器返回的 HTML 页面的内容,或者仅根据用户的 HTML 表单输入执行计算。

连接池数据库连接

服务器端编程领域的第三个趋势是持久数据库连接问题。数据库服务器最初设计为每天处理每个用户的一次连接,而不是每分钟或每秒一次。考虑一下:如果 CGI 程序每秒连接一次关系数据库服务器,那么您使用的连接机制是最初预期的 86,000 多倍。在某些情况下,这并不意味着什么,但对于许多数据库来说,每次连接都是一项昂贵的操作。

因此,一种解决方案是在服务器首次启动时打开数据库连接,并在程序每次需要联系数据库时重用该连接。这大致是 Apache::DBI 模块在使用 Perl、Apache 和 mod_perl 时所做的事情。每次您使用 $dbh-->disconnect 断开与数据库的连接时,Apache::DBI 都会静默地忽略您的请求,并将连接保留以供将来使用。当您调用 DBI-->connect 时,Apache::DBI 会查看连接字符串,并尝试重用现有连接,然后再启动新连接。由于每个 Apache 进程一次只处理一个 HTTP 请求,因此每个进程只需要一个数据库连接。从这种连接/断开连接序列中节省的开销可能是巨大的。与此同时,这意味着每个子 Apache 进程都需要自己的数据库连接,这可能会导致负载较重的服务器上出现数十个或数百个并发连接。

AOLServer 通过使用多线程而不是多进程来减少数据库连接的数量。由于线程存在于同一个进程中,因此它们可以共享数据。AOLServer 利用这一点创建了一个小型数据库连接池,随机选择一个连接并根据需要将其交给处理 HTTP 请求的线程。数据库连接不专用于特定线程,并且可以根据需要共享,从而减少了服务器必须与数据库打开的连接数。

使用 Java servlet 和 JSP 需要完全不同的模型。Jakarta-Tomcat servlet/JSP 实现通常存在于 Web 服务器外部,这意味着它们始终位于 Tomcat 进程上,无论系统上有多少 Apache 子进程。在该 Tomcat 进程中,可能存在任意数量的并发执行的 servlet 线程。通常,servlet 和 JSP(以及 Java bean,JSP 和 servlet 可以使用它们来提供持久性和/或高级抽象)使用 JDBC 连接到数据库。但是 JDBC 不会自动提供连接池;虽然 JDBC 2.0 确实提供了此功能,但它不是完全自动的,并且截至本文撰写时,没有很多 JDBC 2.0 驱动程序。

其他语言采用不同的方法。例如,PHP 的数据库驱动程序允许持久数据库连接,但要求程序员请求它们。也就是说,您可以使用 pg_connect 连接到 PostgreSQL 数据库,也可以使用 pg_pconnect 创建到 PostgreSQL 的持久连接。责任在于数据库驱动程序的作者提供两个不同的访问函数,以及 PHP 程序员根据自己的需要使用适当的函数。

在这些方法中,我发现 AOLServer 的持久连接池技术是最优雅的,因为它适用于所有语言——尽管几乎总是 Tcl——并且扩展性非常好。mod_perl 的 Apache::DBI 是 Perl 程序的绝佳解决方案,尤其因为它意味着不需要更改单个 Perl 程序和模块即可利用持久连接。Apache::DBI 仅提供持久性,而不提供池化的事实是 Apache 多个进程的直接结果;可以合理地假设,支持线程和进程的 Apache 2.0 发布后将更接近 AOLServer 的模型。

JDBC 的池化很好,尤其是在似乎每个人都在编写自己的连接池类之后。但是,它仅适用于 Java servlet,并且对需要为多个服务(例如 mod_perl 和 JSP)提供池的服务器没有帮助。PHP 的系统可能最原始,因为它既没有提供标准的数据库 API,也没有为数据库驱动程序自动池化连接提供方法,也没有为程序利用这些连接提供方法。但是,持久性确实有效,并且肯定可以显着提高速度。

我们走向何方?

虽然我通常不喜欢“应用服务器”这个术语的歧义性,但很明显,这是 Web 的发展方向。您将不再通过编写一个或多个独立存在的程序来设计应用程序;相反,您将使用应用服务器提供的一组对象和模块编写程序,并且您的应用程序自然而然地融入其中。在许多情况下,您可以以最少的工作量创建相对复杂的应用程序,仅仅是因为其他人已经为您完成了大部分工作。

当然,这意味着我们越来越将操作系统视为应用服务器的底层,而后者才是真正重要的元素。正如客户端应用程序作者必须决定是为 Windows、UNIX 还是 Macintosh 编写代码一样,Web 应用程序开发人员必须越来越多地决定他们更喜欢使用哪个应用服务器。与操作系统一样,从一个应用服务器迁移到另一个应用服务器非常困难。不幸的是,这意味着选择一个不成熟、缓慢或难以修改的服务器在未来可能会很痛苦。即使是符合相同标准并使用相同语言的应用服务器,例如 Enhydra 和 ATG Dynamo,也提供不同的对象和功能,并且难以从一个迁移到另一个。

对于像我这样的自由软件爱好者来说,这意味着开源应用服务器至少与开源操作系统同等重要。幸运的是,有许多开源应用服务器可以从 Internet 下载。它们的操作和功能差异很大,但我必须承认,我只接触过以下每种技术中的一小部分。虽然我希望在未来几个月内更多地了解它们,但我提到它们是因为很明显 Web 开发人员需要更多地了解所有这些技术。

也许最著名的应用服务器平台是 Zope,它带有许多部件,但尚未被很好地理解。Zope 是一个对象数据库、一个模板系统,甚至是一个基本的内容管理系统。我还没有机会认真地玩 Zope,但我读到和听到的一些关于它的内容似乎非常令人印象深刻,特别是如果已经有一个模块可用于您需要的特定功能。

另一个备受关注的应用服务器是 ArsDigita 内容系统,它主要由 ArsDigita 咨询公司编写和维护,并根据 GNU 通用公共许可证发布。ACS 的一个主要问题是它依赖于 Oracle 作为数据库;虽然 Oracle 是一款出色的数据库产品,但它既昂贵且源代码也相当封闭。一个名为 OpenACS 的志愿者组织一直在努力解决这个问题,方法是将 ACS 软件移植为使用 PostgreSQL 作为数据库。该软件尚未完全完成,但确实包含大量功能,并且无疑会随着时间的推移而改进。

XML 在 Web 社区中已经成为热门话题多年,但直到最近六到九个月,我们才开始看到它的广泛采用。XML 在语义上描述内容,完全忽略了应该如何显示内容。

Enhydra 是一个基于 Java 的应用服务器,在许多方面似乎与 Zope 相似,只是它与 XML、Java servlet、JSP 和 Enterprise Java Beans 一起工作。Enhydra 看起来相当复杂,但也提供了一个大型框架,可以在其上创建应用程序。

如果您想使用 XML,那么您可能还需要查看 Cocoon 和 AxKit 项目。Cocoon 由 Apache 软件基金会赞助,正在开发一个基于 Java 的 XML 数据服务器。AxKit 使用 Perl 提供基于 XML 的内容生成,从而可以使用 XML、XSL 和 XSLT 以及 Perl 将程序与内容分离,并将内容与图形设计分离。

最后,我应该提到 Oracle 最新推出的应用服务器,即 Internet Application Server (IAS)。IAS 是 Apache 中的一个模块,它与 Java 运行时系统、Enterprise Java Beans、JSP 和 JDBC 以及 Oracle 一起工作。截至本文撰写时,该系统在很大程度上是新的且未经测试的。当然,Oracle 不提供对其源代码的访问权限。与此同时,IAS 在 Linux 下运行,很可能成为 Oracle 用户和管理员的热门选择。

我将走向何方?

到目前为止,我的大部分咨询工作都是使用 Perl 完成的,我仍然认为 Perl 是一种用于 Web 工作的强大语言。事实上,我过去常告诉人们,我的工作大约 80% 是使用 Perl 完成的,另外 20% 是 Java、Python、Tcl 和 C 的混合。

但是随着 Web 编程环境的近期爆发,以及向应用服务器的转变,我(和我的员工)不得不稍微改变方向。在许多情况下,我们将更喜欢使用 Perl,尤其是在与 mod_perl 和 HTML::Mason 结合使用时。但是,我们越来越多地为项目使用 Java servlet 和 JSP,尤其是使用 Tomcat servlet/JSP 引擎和 PostgreSQL 数据库。我们对 mod_perl 的熟悉自然而然地引导我们关注 AxKit,而 servlet 正在迫使我认真考虑 Enhydra。

我们已经开始将 ACS 用于一些大型工作,这在很大程度上是因为它附带了大量可工作的应用程序——而不仅仅是底层工具。此外,ACS 是自由软件并且可以在 Linux 上运行这一事实使其易于使用,因为我们可以依靠社区来提供功能、文档、测试和错误修复。

换句话说,市面上有许多技术,其中许多技术仅在过去一年左右才涌现出来。当我完成这第 50 篇 ATF 专栏并展望未来时,我看到了 Web 开发人员,特别是那些相信自由软件并使用 Linux 的开发人员,拥有充满可能性和机遇的世界。未来的几年对于 Web 开发人员来说注定是令人兴奋和有趣的——在未来的几个月和几年里,我希望与您分享我在使用这些工具方面的实验和经验,以及可以与它们一起使用的软件示例。

资源

ATF Jubilee Edition
Reuven M. Lerner 拥有一家小型咨询公司并担任经理,该公司专门从事 Web 和 Internet 技术。在您阅读本文时,他应该(终于!)完成了《Core Perl》的编写,该书将于今年晚些时候由 Prentice-Hall 出版。您可以通过 reuven@lerner.co.il 与他联系,或访问 ATF 主页 http://www.lerner.co.il/atf/
加载 Disqus 评论