|
实战WEB服务器升级 |
|
|
|
2003-04-13 11:24 雪里弄剑/(天极商务应用) |
|
在服务器专区的前几篇文章里,我们谈到了一些影响服务器性能(特别是网站服务器)的因素,现在我们知道,通过升级底层的硬件结构和改病善上层应用环境,可以带来更佳的网站服务性能。下面我们就以一个现实的网站服务器升级案例来说明服务器构建的诸多考虑因素。这一切问题的焦点在于,网站的源动力何在?这个问题将在本文中得到回答,同时,你还可以从中获取更多的有关信息,从服务器端的角度逐步探知WEB站点的技术内幕。 |
对服务器的要求
让我们回过头来再说说这台新服务器。网站决策者在对购买服务器的各种选择方案作评估之前,就已经对即将要购买的服务器提出了若干要求。本文将把这些要求逐一进行粗略描述,然后再与各位探讨网站目前的这一新服务器是如何满足这些要求的。在开始之前,我将向各位交代一下那台旧服务器的情况,把它作为一个对比的例子,这样有助于加深对新服务器的认识。为了更好地将新旧两款服务器进行比较,我还要简要地介绍一下对比环境的负载条件。
目前,大量PC个人电脑的主频均已达到了2 GHz级别。对比这个数字,你也许会对那台只有一颗125 MHz的“芯”及400 MB/s总线的旧服务器嗤之以鼻,认为它根本不配成为一台服务器。事实上,即便是这台拥有一颗500 MHz CPU的新服务器,比之2 GHz这一数字也是相距甚远。主频数值上的比较轻而易举,但是为了能真实地测算一台服务器所能实现的性能级别以及它能支持的用户数量,你不得不根据应用程序的运行情况以及负载在系统组件中的分布方式对机器进行评估。
大多数情况下,在评估一台服务器时需要谨记一个衡量的尺度,那就是服务器支持的并发用户数量。系统上的每一用户均会消耗一定数量的内存、CPU时间、存储空间及网络带宽等等。因此,由单个用户的应用负载叠加而成的并发用户数量就构成了服务器的总占用率。在web服务器条件下,所谓的“用户”指的是浏览网站的人,而负载则应该用请求的数量来衡量。
那么,在这个网站上,如果要对用户提交的单个典型页面访问请求提供服务,需要满足什么条件呢?
1、 一个web应用服务器线程
(1)CPU执行时间
(2)存放线程(thread)和数据(data)的内存空间
2、一个数据库连接或会话
(1)CPU的执行时间
(2)存放连接(connection)、查询(query)和结果(result)的内存空间
(3)I/O:读取查询或写入查询的磁盘吞吐量
3、网络连接
(1)HTTP请求带宽
(2)HTTP响应带宽
正如你所看到的,若只有一个快速的CPU或一个高带宽的网络链接,那是远不足够的。如果服务器面对的最大并发请求数量超出了其内存空间所能支持的范围,那么,内存的容量就会成为系统的瓶颈,使系统的处理能力不能被充分利用。如果网络带宽不足够,那么它对服务器能够支持的用户数量也会带来影响。
下面,我很快将会与你更为详细地探讨应用负载。现在,让我们把视线转移到服务器硬件。先让我们对升级前后的硬件系统迅速作一个全面的纵览。
SPARCstation 20系统对比Blade 100系统

SPARCstation 20系统
网站一直都是通过一个比网站自身古老得多的系统来提供服务的。1994年,SPARCstation 20系统作为一款基于32-bit SuperSPARC存储缓冲器(Mbu)模组的高端多处理器工作站正式面世。该系统共支持2个存储缓冲器模组,每一模块最多支持2个CPU。也就是说,该系统共能支持4个CPU。网站所用的SPARCstation 20系统正好配置了4个CPU。该系统还有4个Sbus扩展槽和8个内存插槽(支持200-pin EDO DIMM内存)。该内存接口为64位,工作在50 MHz下。下表对Ace's Hardware网站旧的SPARCstation 20系统与新的Blade 100系统对应的规格作了一个比较:
|
系统 |
SPARCstation 20 |
Sun Blade 100 |
|
CPU |
4 个 125 MHz HyperSPARC处理器 |
1 个 500 MHz UltraSPARC IIe处理器 |
|
ISA |
32-bit V8 SPARC |
64-bit V9 SPARC |
|
L1 Cache |
8 KB Inst |
16 KB Inst, 16 KB Data |
|
L2 Cache |
256 KB |
256 KB |
|
物理内存 |
8 条64 MB内存 (共512 MB) |
4 条 512 MB内存 (共2 GB) |
|
内存接口 |
工作在50 MHz下的64-bit EDO |
工作在84 MHz下的64-bit SDRAM |
|
扩展槽 |
4 个Sbus槽 |
3 个32-bit/33 MHz PCI槽 |
正如你所见,这两个平台就硬件来讲具有很大的区别。虽然Blade 100属于一个比较低端的系统,只安装了一个单CPU,同时,只有3个PCI扩展槽位和3个内存插槽,但是,相对SPARCstation
20系统而言,它采用了更多的先进技术。尽管Blade 100系统的内存模组数量只是SPARCstation 20系统的一半,但其支持的内存容量却是后者的4倍。另外,Blade
100系统的内存接口还支持更高的带宽以及更短的响应时间。

Ross Rockets
就CPU方面来讲,Blade 100所用的500 MHz的UltraSPARC IIe处理器在单线程性能上比SPARCstation 20的125
MHz 的HyperSPARC处理器快了数倍。即使与4个HyperSPARC处理器的综合性能相比,UltraSPARC IIe处理器的表现仍要高出许多。这一新式的CPU还有一个优点,那就是它的低能耗。尤其是在与4个巨大的HyperSPARC处理器(采用了0.4微米的制程)进行比较的情况下,这一优点更加突出。
最后需要指出的是,Blade 100系统的磁盘接口得到了大大的改进和完善,用40 MB/s UltraSCSI接口取代了老式的10 MB/s
FastSCSI接口。附连在这个接口上的是一个IBM UltraStar 36LP硬盘,其存储容量是旧服务器硬盘组(2块硬盘,容量分别是2GB和4 GB)容量的6倍。
值得重视的是,在新旧两台服务器的比较中,虽然旧服务器看上去已经显得非常落伍(尽管实际上确实如此),但是自1999年6月安装运行以来,它的表现一直令人满意站点的运行格外良好,直到其面临的请求数量不断上升,并超出了系统的内存容量极限,情况才发生改变。实际上,在这一基于Java的新站点的研发过程中,网站决策者曾把这款新的web应用锁定运行在125
MHz的 HyperSPARC处理器上。除了编译时间略嫌冗长之外,web应用的代码在这几个低速的处理器上运行得极其流畅。毋庸置疑,那些与web应用相关的沉重的事务处理负载并不常常需要强劲的CPU运算能力。
在可靠性方面,旧服务器只发生了一次硬件故障(这一故障是去年夏天,系统在提供服务的过程中出现的),那就是内存出现了问题。
当时,数据中心内出现一个A/C运转中断,紧接着,系统开始变得过热,导致了问题的出现。内存发生故障又引起数以千计的“软”错误,由于内存带有ECC纠错功能,所以错误都被记录并修正了。
迄今为止,新服务器性能表现之优令人印象深刻,超出了网站管理员的预料之外。他们坚信,这个新系统将和旧的SPARCstation 20系统一样稳定、可靠。
接下来,我们将对服务器的存储容量展开讨论。
服务器的存储容量
这台旧服务器SPARCstation 20最大的局限在于存储容量。由于搭配了4个处理器和512 MB内存,它实际上已运行在其最高的配置规格下了。当年系统安装启用之时,此配置可算是极其豪华,但是随着网站的知名度和访问量不断上升,服务器已逐渐步履蹒跚,不堪重负。需特别指出的是,不管是使用运行在Apache
和PHP环境下的旧应用还是运行基于JAVA的新应用,该系统都会受到系统物理内存容量的限制。

SPARCstation 20系统的512 MB内存
在这款旧平台上,Apache和PHP搭配得不是很好,当系统对巨大的负载作出响应时,经常会耗尽系统的所有内存。也就是说,当人们最需要该服务器时,它却不幸地当机了。而在新服务器中,Java和Resin配合起来,就显得稳定多了,但是却需要容量高出许多的常驻内存。尽管每个Apache进程一般只消耗几兆字节的内存,但是新的web服务器程序和应用却需要用到200兆字节的内存空间(这个数字并不包括编译器占用的内存大小)。
由于网站仅数据库就占用了数量惊人的内存空间,因此,如果系统内存均被限制在512MB,那么,两种软件平台都不能真正地顺利运行。对此,我们可以作出两种选择:一是扩展硬件,二是更换新的硬件。如果选择扩展硬件,那么就需要再添置一台新机器,一台机器跑web应用,一台跑数据库。这样的话,就可以通过把数据库迁移到另一台机器上,将SPARCstation
20服务器50%的内存释放出来,全部供web应用单独使用。
但是,这种选择有几个缺点。首先,第二台机器的加入将会使得服务器的设置更加复杂。尽管额外的服务器有助于排除故障,增强站点的可靠性,但是管理员却不得不把网站的两个重要组件分离开来,放到不同的系统中去。如果其中一个系统出现致命错误,网站就会当掉。在这种情况下,额外的服务器不仅仅不能增强网站的可靠性,而且只会给网站带来又一潜在的不稳定因素。此外,附加的系统将使网站运行开销更加庞大,并增加运营的长期总成本。

2 GB 的 PC133 ECC SDRAM内存
第二种选择(也就是用一台全新的机器去取代SPARCstation 20)就显得更加具有吸引力,因为它没有上述的这些缺点。尽管在第一种选择中,两套系统如果被正确设置,也许能提供更大容量的存储空间,网站的决策者们最终还是认定:与一台使用了6年的老服务器相比,目前购买任何一款新的系统都能够带来系统性能以及存储容量的巨大提升。因此,他们能够实现网站在数据库和应用放在同一个系统的情况下运行,比在新旧系统一个跑数据库,一个跑应用的情况下运行,速度更快。
服务器的兼容性
网站决策者在崭新的web应用开发完成之后,才开始考虑选购硬件的问题。这表明,他们在采用全新的硬件平台这一问题上还是略嫌保守。尽管如此,他们还是对几种选择方案作出了评估。在考虑范围内的平台有二:一是SPARC平台;二是x86平台。SPARC处理器配合Solaris操作系统显然是最佳选择,因为该网站原来就是跑在此平台之上的,同时,该平台性能优越,并得到广泛支持。另一方面,x86平台由于具有极高的性价比,也颇为诱人。
网站决策者在考虑采用哪款SPARC平台的时候,比较了大量不同的机器。一开始,他们把目标定在:新的系统在存储容量和性能上,至少应是SPARCstation 20系统的5倍。满足这一条件的产品很多,那么接下来就是怎样缩小选择的范围。考虑到成本因素,他们认为有几款较老式的基于UltraSPARC
II处理器的系统(如Ultra 2系统)比较合适。这时,兼具成本低廉、存储容量高两种优点的Blade 100系统迅速进入了他们的视线。

Blade 100系统
在X86架构平台方面,网站决策者发现,大量价格便宜的x86硬件都定位在家用市场领域,因此,实际上并不太适合用来发布网站。OEM厂商基于Intel处理器的服务器产品在价格上与SPARC平台相比并没有太大的优势。而在DIY市场上,用OEM机器同样的价格,却能够获得意外的惊喜,买到更为高端的主板和其他一些他们想要的配件。先把系统硬件价格放在一边暂不讨论,平台的改变将会导致自身成本的增加,这是因为,过去在软件方面的投入将会由于新软件取代旧软件而付诸东流。
x86硬件能否挽回对比中的劣势不太明朗,究竟选择哪种操作系统平台就更是模糊不清。不用说,Windows在x86硬件平台上非常流行,但同样地,它也主要定位在单用户的家用PC电脑。Windows对单用户环境的过分强调就会导致解决方案平台在应用于服务器用途时远不能达到优化状态,特别是如果把安全的因素也考虑进去,就更是如此(尤其要注意Windows默认采用的可写性极好的文件系统)。即便没有这些缺点,Windows的兼容性问题和远程管理手段的缺乏也足以令其清除出网站决策者的视线之外。
考虑到该网站一直以来都在使用Solaris操作系统(虽然它运行在不同的硬件平台上),选择Solaris/x86解决方案顺理成章。但是,基于x86硬件的Solaris平台口碑不好,非议甚多——尤其是该平台的硬件支持太少。
Solaris/x86平台的市场占有率远比不上旗鼓相当的Windows平台和受到广大开放源代码开发商支持的Linux平台。它只有一组数量非常有限的驱动器(支持一个较小的硬件子集)。同时,商业软件厂商对Solaris/x86平台的支持程度,远远比不上基于SPARC处理器的Solaris平台。
选定服务器
最后要说明的是,在网站的发布中如果采用x86平台可能存在大量的问题,而获得的回报太少。如选择该平台,尽管能以大约相同的价钱搭建一个稍快的系统,但是相应的性能提升远不足以抵消因为切换平台和软件而付出的成本。考虑到新系统的性能和存储容量将会是旧系统的5倍(之前定的目标),网站决策者认为,再多投一些资金不会带来多大区别。

新服务器的内部结构
Blade 100系统在满足了网站决策者对性能和存储容量提出的要求之外,还对网站的所有软件或程序保持着良好的兼容性。重要的是,它的低成本是主要的吸引力。同时,该系统设计简易,并使用了标准的168-pin ECC SDRAM内存,这就更吸引人了。与旧服务器相比,这一新服务器的内存空间大小增加了4倍,存储容量扩大了6倍,另外,单线程运算性能更是提升了大约10倍。总体来说,该系统网站决策者希望的价格范围内,实现了他们的预定目标。
理论上的服务器(即软件意义上的服务器)
网站决策者对web服务器提出的目标一直都是非常清晰的,那就是:速度、效率、可靠性、可用性和可量测性。
“速度”是服务器赢得网站内容提供方和网站用户双方满意的关键因素(对于站点页面装载打开速度,前者比后者更敏感)。速度与可量测性是密切相关的,因为光有速度并不足以迅速地对一个访问请求作出响应——更何况,网站要迅速对上百万数量的访问请求提供服务。
服务器的硬件配置规格可以决定能在同一时间访问网站的用户的最大固定数量(主要是由最大可用内存空间大小决定)。你也可以通过执行web应用对该数值进行定义。因此,如要使网站支持更大数量的用户(或访问请求),关键是减少服务器处理每一请求所占用的时间。越迅速地结束处理当前这个请求,就能越迅速地开始处理下一个请求。
影响处理一个访问请求所需的时间和资源数量的因素有很多。这就是“效率”切入并发挥作用的地方。每一个访问连接(connection)将占用服务器一定大小的内存空间。具体占用多大内存,取决于HTTP服务器和web应用的执行情况。另外一个影响因素是建立一个连接需要耗用的时间长短以及此连接是用来传输单个文件,还是用来传输一个完整页面。
对web性能起最重要作用的一个因素也许就是应用的内容创建效率。对该因素的控制,主要是由应用开发商来完成的。比如:系统要对一个访问请求作出响应,会生成大批量指向数据库的复杂查询吗?如果是这样的话,这些查询可以存放在缓冲区吗?存入缓冲区的这一过程在动态的应用中是怎样进行的?是将数据存入缓冲区,还是就把HTML的单视图输出存入缓冲区?再强调一下,这里提到的大部分问题都是由应用开发商来具体实施的,只有他们才能回答。
相反,还有一个应用开发商难以调控的重要因素,那就是“网络”因素。你能够确保服务器高带宽地接入互联网,可是你却不能保证所有用户的客户端系统都能以同样的接入方式访问站点。客户机和“网络”因素也象内容创建一样,能够影响每一个访问请求的服务器处理时间长短以及web应用的总体效率。
谈谈用户用典型的modem(调制解调器)拨号上网方式。这种方式下,用户可以获得最大为5 KB/s的下载速度。如果当前用户试图下载大小约为200KB(以今天的标准来看,这个数字相当小了)的通用消息板块索引页面(general
mesage board index page),那么要完成这个单线程下载至少得用40秒的时间。这40秒钟主要是服务器端将所有和访问站点的连接有关的资源捆绑起来而占用的时间。在这种连接方式下,即便是一个体积更小、约35KB大小的HTML页面也将需要7秒的时间才能完成传输,正常打开。7秒比之40秒,显然算是比较快的了。如果有几百个用户同时访问,那么请把这个数字叠加起来,你会发现你的服务器在短期内将会迅速地耗尽资源。
HTML页面压缩比较
|
页面类型 |
字节数(byte) |
5 KB/s速率下的传输时间(秒) |
|
|
未压缩 |
41,665 |
8.14 |
|
|
经压缩 |
8,744 |
1.71 |
|
|
未压缩 |
168,353 |
32.88 |
|
|
经压缩 |
13,478 |
2.63 |
|
为了最大地提高网络效率,我们可以压缩站点的输出数据流,也就是压缩站点。HTML页面经常重复,因此,该类页面的压缩率常常很高。上文所述的200KB的访问请求在5 KB/s连接速率下需要40秒的连续传输。如果这个200KB的访问请求能被压缩成15KB,那么只需要3秒的传输时间。当然,要压缩输出数据流,服务器会消耗一些运算时间,但这显然是次要的,因为与几毫秒的压缩时间相比,我们能够为服务器和客户机节约37秒的时间。这还意味着,服务器能够在同一时间片内,支持更多的用户并节省带宽。另一相对较小的35KB页面也许可以压缩到3KB或者4KB,也就是说,modem的传输时间将从7秒锐减到1秒。
现实中的服务器
与新服务器配合的是一款新的基于Java servlets和JSP(Java Server Pages)的服务器应用。另外,Servlet容器(或者说web应用的运行平台)采用的是Caucho
Technology公司(http://www.caucho.com/)的Resin。由于Resin也直接处理HTTP请求,整个服务器应用除了数据库外,都跑在JAVA虚拟机(JVM)上。Resin是一个具有高性能的J2EE应用服务器,得到众多网站的广泛应用,包括Altavista和Half.com。由于Resin的可靠性和高性能,因此Resin/J2EE平台是站点的不二之选。

那么,这一新的web应用对新服务器来说,实际上意味着什么呢?为了测试网站软件部分的性能,这里搜集了大量的服务器运行数据。以下就是一个CPU占用率曲线图,标示了该网站web应用(Java)和数据库在5秒钟内的CPU占用率(每隔1分钟记录一次)。这些数据是在2001年10月16日从中午到午夜这段时间搜集的。当日,服务器处理了来自23979个不同用户发出的392526个访问请求。
由上图你可以看见,web应用和数据库的CPU占用率平均来说都很低。尽管可能缘于服务器运行了一些更为复杂,但不常作的查询操作,数据库对CPU的占用率存在几个高达30%和40%的峰值,但是,web应用和数据库两者对CPU的占用率均值都在10%到15%之间。需要注意的是,该曲线图实际上记录了大量的的测试数据(700个以上)。

这里还有一个有趣的曲线图,记录的是web应用的线程数量。该图标示了5秒钟内的并发线程数量(也是每隔1分钟记录一次)。
在该图中,你可以清晰地看到当天的线程总数是怎样随着负载的变化而变化的。其中,并发线程的最大数量为117。在晚上18时以前,线程的平均数量大概在90到100之间,随着时间的推移,线程数量降到了80多,到了午夜前后,最终减少到75左右。
Web应用(整个Java进程)占用的常驻内存大小全天保持在260MB左右(实际上并无远超这个数字的情况)。这一数字能保持相对稳定是因为系统的缓冲区大小是固定的,同时,web应用占用的内存空间也没有随着时间的推移而膨胀(也即没有发生内存渗露的情况)。数据库在初始化之后,获得了固定的内存空间(它被设置成占用512MB内存)。目前,该服务器报告仍有约1GB未分配的剩余内存空间。也就是说,新系统还有很大的扩展空间。
持久的web应用
改用基于Java的web应用是站点软件系统向前的一大飞跃。该网站原先在Apache /PHP平台上跑的应用仅仅是服务器应请求而解释运行的单独脚本,经更换平台后,这一新的站点自身就成为了一个完善的、运行流畅的多线程应用。当某个访问请求被提交后,web应用就会生成一个新的线程来处理这一请求。如果需要的话,数据库连接将从一个由该应用维护的共享连接池中被分配和指定。
在该网站原来的解释运行脚本情况下,程序是在一种空闲和无状态信息的情况下编译执行的。只有在对脚本发出请求的时候,脚本才会运行。同时,在线程或组件之间没有任何的通讯,也没有共享的资源。
网站的软件平台使它有可能建立真正有状态信息(stateful)的应用(能够创建和共享全球通用的资源)。比如,站点的消息论坛(message forums)使用了一个共享的消息索引缓冲区(shared message index cache),能够有目的地将数据库从几乎所有的“读”操作中释放出来。这一缓冲区在内存中对所有的线程都是共享的,同时,只有在对数据库作出一个“写”操作(如新的发贴、编辑或删除)时,该缓冲区才会得到刷新。在PHP或PERL等环境下,这样的缓冲区是很难实现的,因为不可能在某个解释运行脚本的不同实例(instance)中共享固定不变的对象(object)。
持久的智能缓冲区
站点还使用了另外一个为新的发贴操作、论坛消息、甚至是象本文一样的文章而准备的按需使用(on-demand) 缓冲区。当收到一个按特定规格查看特定文章、消息或新闻的请求后,该站点的web应用首先会查看这个缓冲区,看看是否有这个对象。如果它找到了这个对象,应用就会重新获取这个对象,并将该页面发往客户端,最后归还对象。这3个动作只需几毫秒的时间。如果该对象没有放在缓冲区内,那么系统就会指定一个connection对象并查询数据库。查询的结果将会储存在缓冲区内,以备下次需要它的时候使用。缓冲区有效期(cache expiration)是通过最近最少使用算法(LRU)来计算的,这就是为什么最不经常被访问的对象随着时间推移,会逐渐期满并退出缓冲区的原因。
这些类型的缓冲区真正的优点在于他们能在不牺牲站点动态特性的同时,最大地提高系统的性能。由HTTP服务器实现的更为传统的缓冲解决方案能够将某个特定请求的全部输出储放在缓冲区,但是它没有可操作性,因为在这种方案下,系统管理员需要根据用户指定的规格去具体定制输出。
在留言板系统(message board)情况下,颜色方案(color scheme)和索引显示长度(index display length)可由用户进行设置。系统还允许用户设置成将日期显示在其本地的时间区域(timezone)中。这确实可以做到的,因为系统是将数据自身(而不是输出)存放在缓冲区。最后要说的是,这一系统架构把两种优势都综合起来了:一是由缓冲带来的极佳性能;二是动态页面生成所具有的灵活性和可定制性。
进程和线程
进程是现代化软件的基本构成组件。本质上说,一个进程就是一个拥有自己的虚拟地址空间的单独运行程序。当操作系统改变当前的活动进程(active process)时,就会出现一个系统状态切换操作(a context switch)。由于每一个进程都有它们自己的虚拟地址空间,地址转换映射表(address
translation map)就会在上下文切换过程中相应地发生改变。
在一个进程内,也有可能存在多个执行线程。线程与进程是类似的,通过线程,软件开发商能够为他们的软件增添平行性。但是,和进程不同的是,线程没有独立的虚拟地址空间,而是工作在父进程的空间里,同时,能够访问父进程的所有资源。相应地,线程创建时间只是进程创建时间的一小部分,此外,也许更为重要的是,在线程之间产生的线程交互通讯(interprocess communication,IPC)比进程之间产生的进程交互通讯,速度要高出一大截。
那么在web应用实际运行过程中,线程的这些特点究竟意味着什么呢?当我们通过浏览器阅读web站点的输出内容时,我们一般会更多地认为web站点就是网页的一个集合,很少把它当成一种应用程序。实际上,像网页集合这样的描述只适用于早期的web服务器(美其名曰,仅仅就是一种基于HTTP协议进行通讯的文件服务器),而这样的服务器对今天的互联网来说,再也不会被广泛应用。
正如你能在下图中见到的那样,HTTP服务器仅仅就是现代化web应用服务器架构中的一个组成部分。此外,你还能找到一个应用层和一个数据库层。为了简化这些不同层级扮演的角色,你可以把数据库层看成是内容数据的存放空间,把应用层看成是客户端见到的输出内容的创建区域,还可以把HTTP服务器看成是处理客户端用户和主机应用之间通讯的层级。

你能想象得出,该图勾勒的这种关系可以通过多种方法来实现。这些任务中的每一个都可以分别指派给对应独立的服务器或者指派给某个通过TCP/IP协议连接的完整的服务器机群。另一方面,所有的这些任务都能在一台单机上分别通过独立的服务器进程来处理,或者所有的任务都能在一个单进程之内被处理。
以上所述的每一种实现方法都有其各自的优缺点。web应用的多服务器和单服务器运行方式与它的单进程运行方式相比,两者的真正区别在于通讯方面。在多服务器情况下,web应用每一个组件之间的通讯可以在所有系统共享的局域网环境下,通过网络socket来实现。事实上,运行在同一台机器上的独立服务器进程之间也都是通过socket来通讯的。尽管在局域网上的通讯和一台单机内的通讯相比,系统的反应时间显然要慢许多,但是使用多机方式来提高系统存储容量的方式比之单机处理方式,在系统的可量测性上存在着巨大的优势。]
Java平台的多线程模型与Apache/PHP平台的多进程模型比较
比较完线程和进程的区别并了解了构成现代化web应用服务器的基本组件之后,现在,让我们对网站新旧两种web应用模式作一个对比分析。
该网站的web应用原来是用PHP语言来编写的,跑在Apache平台上,Apache属于一款pre-fork(预分岔)多进程HTTP服务器。Apache是这样工作的:首先开启一个父进程,接着,父进程又分成若干子进程进行监听,并等待HTTP连接。接着,其中的每一个子进程将一次处理一个HTTP请求,此外,Apache还创建了一个进程“池”,对HTTP连接予以适时的处理。
这种处理方法的缺点在于进程数与请求数的比率为1:1,从而导致系统处理时间的大量消耗。尤其在HTTP keepalives(这是在同一连接下处理来自一个客户端的多个连续请求的一种特性,因为不用为每一请求创建新的连接,因而能节省时间,加速web服务)条件下,情况就更是如此。由于子进程在接受来自另一客户端的连接之前,要被迫等待特定的一段时间,这种浪费系统处理时间的缺点就暴露无疑了。如果HTTP的存活时限为15秒,那么每一个Apache进程在处理完来自客户端的最后一个请求之后,15秒钟之内将不能处理任何别的请求。
也就是说,使用了keepalives特性的Apache web服务器将需要运行比连接数量更多的子进程。根据具体的设置和传输量,这能够导致生成一个比并发连接总数量庞大得多的进程“池”。实际上,由于所有的那些被封锁的进程耗用了太大的内存空间,很多大型网站甚至干脆就把keepalives特性关闭掉了。
持久的数据库连接

关于数据库连接的分配,多进程模型(如Apache)还存在一个问题。这个问题与我以前讲过的PHP脚本的不持久特性是相伴相生的。请先看看下图。
你所见的这幅图从一个由数据库驱动的动态web应用的角度说明了Apache/PHP解决方案是怎样工作并处理访问请求的。你可能注意到了,正如上文提到的一样,每一个Apache子进程一次处理一个单独的客户端连接。由于PHP脚本是单独由处理访问PHP生成文档的请求的每一个子进程来解释的,每一个进程均必须建立其独立的查询数据库的连接。
由于PHP脚本没有持久性,数据库连接在每次脚本运行时都必须打开和关闭。尤其对于那些被频繁访问的站点来说,在连接上浪费的时间可能会导致巨大的性能损失
为了避免这种情况,PHP开发商也许会采用持久的数据库连接方式,使访问请求处理完毕和PHP脚本执行结束之后仍保持打开状态。
但是,在PHP环境中采用持久的连接方式和传统意义上的连接“池”方式并不相同。在PHP环境中,当一个持久的连接被子进程打开后,不需要再耗费额外的连接时间,就能够重用该连接。但是要指出的是,只有通过同一个子进程才能重用它。由于该连接是由特定的进程打开的,因此,即使打开它的子进程处于空闲状态,不用处理任何的请求,此连接也保持着对其的附着状态。事实上,即便是该子进程又继续处理另一个非PHP请求,该数据库连接也不会关闭。
在持久的数据库连接的情况下,我们观察到的实际上还是与前面所讲相同的子进程与HTTP keepalive 请求的1:1映射比率。但是,在当前情况下,数据库连接将会一直维持打开状态,并贯穿在打开它的子进程的整个生命期中。
这种情形会导致打开的数据库连接过剩,从而使得占用的内存空间大小超过实际负载的需要。在某些环境里,这种数据库连接过剩在高负载情况下会使数据库达到连接数量的极限。这时,服务器将不再对更多的请求作出响应。用户可以把这种情况看作是应用服务器或HTTP服务器对数据库执行了一次拒绝服务攻击,从而使自己当机。
多线程方式
多线程服务器的工作方式和多进程服务器比,有一些不同。首先,每一个HTTP连接都是由一个线程来处理的,在同一个进程和虚拟地址空间中,大量的线程可以处理大量的连接。由于所有线程都运行在同一个进程中,线程之间的通讯非常高效,同时,所有线程都能访问同样的资源。

在Java web应用服务器情况下,这意味着存在持久的对象。正如之前讨论过的,这样的持久性有助于建立智能的共享缓冲区,也有助于高效地管理数据库连接的中央“池”。接下来,让我们看看站点基于Java的web应用:
正如上述的插图所示,HTTP服务器和web应用都集中在同一个进程中。数据库连接“池”和缓冲区也都在同一进程中,并由web应用来维护。如果需要的话,web应用能够打开额外的连接或者将多余的连接关闭。
如果某个数据库连接需要查询一个对象,而这个对象在web应用的缓冲区中并未找到,系统就会从数据库连接池中指定一个连接。一旦查询结束,该连接就会返还连接池(在连接池中,它可以被指派给任一运行中的线程)。这种架构和我们先前讨论的PHP持久连接方式大大地不同。因为池内的数据库连接与单独的工作线程并没有关联,而是可供需要连接的任意线程使用。