【IT168 技术文章】
2008年,对于首都人民来说,没有什么比奥运会更大的事情了。如何买到一张称心如意的比赛门票,也成了很多人的一个梦想。然而,在奥运官网抢票购买的时候,这个梦想却轻易地被网上购票系统的瘫痪击成碎片,很多充满热情的老百姓们也因此郁闷无比。由于搜狐承担了奥运的官网,我又在那里工作过相当长一段时间,很多兄弟抢票失败,于是便认定是搜狐开发的系统太烂,而找我抱怨。其实当时我也很是郁闷:首先这个系统并非搜狐开发;其次我也不在搜狐了。虽然如此,和我同行的一些朋友,又开始问我如何解决类似问题。我也反反复复讲了很多次,为了让广大读者能够深入了解背后的原因和机制,写出来,大家一起讨论可能效果会更好。当然,这并不是我说的架构就一定能解决问题,仅仅是抛砖引玉而已。
在说架构之前,我先说一个老的技术,FastCGI。因为这个技术在后面的结构阐述中将起到非常重要的用处,原以为应该会有不少人会知道,但后来发现好像并非如此。
关于FastCGI的历史我就不再赘述,好像自1993年便有了。目前最热门的视频网站YouTube体系结构中,就有fast-cgi的模块。它支持很多httpd服务器,在官方网站上列了很多,如apache,aXesW3 ,Microsoft IIS,Zeus,近几年才出的lighttpd没写,其实这个新的httpd也支持,但我个人觉得,支持最好的,可能还是Apache。
FastCGI的原理
先讲讲FastCGI的原理,它和现在常用的运行请求不同,维基百科上有一个术语形容它,这里借用一下:
短生存期应用程序
长生存期应用程序
CGI技术的机制是:每次当客户请求一个CGI的时候,Web服务器就请求操作系统生成一个新的CGI进程;当CGI满足要求后,服务器就杀死这个进程。并且服务器对客户端的每个请求都要重复这样的过程。
而FastCGI技术的机制为:FastCGI程序一旦产生后,它可以持续工作,一直保持满足客户的请求直到自己被明确终止。如果你希望通过协同处理来提高程序的性能,你可以请求Web服务器运行多个FastCGI 应用程序。
由此CGI就是所谓的短生存期应用程序,FastCGI就是所谓的长生存期应用程序。
由于FastCGI程序并不需要不断产生新进程,可以大大降低服务器的压力。并且产生较高的应用效率。如今,流行的Java语言Servlet技术,在设计上就是参考FastCGI技术。
FastCGI 配置运行一般来说分三种,这三种都需要Apache的mod_fastcgi 进行处理。
1、Standalone FastCGI Server, 应该是独立的服务器。
首先是需要把fastcgi作为单独的守护进程:
$ script/myapp_fastcgi.pl -l /tmp/myapp.socket -n 5
以下是这个fastcgi的守护进程的参数:
-d -daemon #作为守护进程
-p -pidfile #管理进程的PID写入到到文件的名称
-l -listen #SOCKET的路径,机器名:端口, 或者端口
-n -nproc #起始接受请求的进程数
然后把下面的代码加入Apache的HTTPD.CONF:
FastCgiExternalServer /tmp/myapp -socket /tmp/myapp.socket
Alias /myapp/ /tmp/myapp/
# Or, 可以使用root的身份运行
Alias / /tmp/myapp/
# Optionally,(使用rewrite模块)
RewriteRule ^/myapp$ myapp/ [R]
然后重启Apache就OK了
2、Static mode:静态模式, 一般是用于单一确定的模式,就是在Apache 的httpd.conf 中间加上:
FastCgiServer /usr/local/apache/count/count.fcg -processes 1
Alias /c /usr/local/apache/count/count.fcg
此处建议再使用REWRITE的方式 重写整个的URL匹配, 使之看起来像一个静态页面。
RewriteRule read-(.+)-(.+)-(.+).html$ /c?id=$1&sid=$2&port=$3 [L]
3、Dynamic mode:动态模式,可以使用各种各样的fastcgi,加入到httpd.conf中间去,比如:
AddHandler fastcgi-script .fcgi
还有一个关键的设置:
<Directory /path/to/MyApp>
Options +ExecCGI
</Directory>
这个配置建议放在cgi-bin 这种类似的目录里面。
请注意第二种,服务器起几个进程,是由-processes 1 这个参数来控制的,所以起多少你可以自己来定,我们在下面的一个关键模块中将使用这个模式。
下面放一段FastCGI程序的C代码,来说明一下:
#include
#include
void main(void){
int count = 0;
while(FCGI_Accept() >= 0) {
printf("Content-type:text/html ");
printf(" ");
printf(" "
"
" "
" " "Hello world!
");
printf("Request number %d.",count++);
printf(" ”);
}
exit(0);
}
这是一个很简单的例子,就是简单的计数, 大家可以注意这一句:while(FCGI_Accept() >= 0)
这就是它和普通的短周期程序最大的不同,一般CGI都是运行完就退出了,这个FastCGI,在处理完一个请求完毕后,会回到初始状态等待下一次请求;如果这个程序被设置成为只能启动一个,那么无论是否访问这个页面,都是在前一个的基础上加一,而不会又产生新的进程;从而后来者是从零开始。当然,很多人也都注意到,此处就是一个死循环在不断处理;如果程序比较复杂,存在内存泄露的问题,此处产生的问题也要比普通CGI要严重得多,所以使用它对于程序员的要求也更高。
上述方案应该是所有的Web应用解决方案中,执行效率和速度最高的。官方数据是说比一般的高15倍左右,在我的机器上测试,基本上每秒能够处理大概2400次请求。
再回到我们说的正题:奥运订票系统的瘫痪,关于访问量,当时的说法是800万/小时,那么平均到每秒就是超过2200次。这对于订票系统来说,确实是一个非常大的考验。毕竟这种状况下,数据库是肯定承担不住这个量级的访问了。如何进行架构设计,是我们都需要面对的问题。