架構原理
Apache通常是開源界的首選Web服務器,因為它的強大和可靠,已經具有了品牌效應,可以適用于絕大部分的應用場合。但是它的強大有時候卻顯得笨重,配置文件得讓人望而生畏,高并發情況下效率不太高。而輕量級的Web服務器Lighttpd卻是后起之秀,其靜態文件的響應能力遠高于Apache,據說是Apache的2-3倍。Lighttpd的高性能和易用性,足以打動我們,在它能夠勝任的領域,盡量用它。Lighttpd對PHP的支持也很好,還可以通過Fastcgi方式支持其他的語言,比如Python。
畢竟Lighttpd是輕量級的服務器,功能上不能跟Apache比,某些應用無法勝任。比如Lighttpd還不支持緩存,而現在的絕大部分站點都是用程序生成動態內容,沒有緩存的話即使程序的效率再高也很難滿足大訪問量的需求,而且讓程序不停的去做同一件事情也實在沒有意義。首先,Web程序是需要做緩存處理的,即把反復使用的數據做緩存。即使這樣也還不夠,單單是啟動Web處理程序的代價就不少,緩存最后生成的靜態頁面是必不可少的。而做這個是 Squid的強項,它本是做代理的,支持高效的緩存,可以用來給站點做反向代理加速。把Squid放在Apache或者Lighttpd的前端來緩存 Web服務器生成的動態內容,而Web應用程序只需要適當地設置頁面實效時間即可。
即使是大部分內容動態生成的網站,仍免不了會有一些靜態元素,比如圖片、JS腳本、CSS等等,將Squid放在Apache或者Lighttp前端后,反而會使性能下降,畢竟處理HTTP請求是Web服務器的強項。而且已經存在于文件系統中的靜態內容再在Squid中緩存一下,浪費內存和硬盤空間。因此可以考慮將Lighttpd再放在Squid的前面,構成 Lighttpd+Squid+Apache的一條處理鏈,Lighttpd在最前面,專門用來處理靜態內容的請求,把動態內容請求通過proxy模塊轉發給Squid,如果Squid中有該請求的內容且沒有過期,則直接返回給Lighttpd。新請求或者過期的頁面請求交由Apache中Web程序來處理。經過Lighttpd和Squid的兩級過濾,Apache需要處理的請求將大大減少,減少了Web應用程序的壓力。同時這樣的構架,便于把不同的處理分散到多臺計算機上進行,由Lighttpd在前面統一把關。
在這種架構下,每一級都是可以進行單獨優化的,比如Lighttpd可以采用異步IO方式,Squid可以啟用內存來緩存,Apache可以啟用MPM 等,并且每一級都可以使用多臺機器來均衡負載,伸縮性很好。
實例講解
下面以daviesliu.net和rainbud.net域下面的幾個站點為例來介紹一下此方案的具體做法。daviesliu.net域下有幾個用 mod_python實現的blog站點,幾個php的站點,一個mod_python的小程序,以后可能還會架設幾個PHP和Django的站點。而服務器非常弱,CPU為Celeron 500,內存為PC 100 384M,因此比較關注Web服務器的效率。這幾個站點都是采用虛擬主機方式,開在同一臺機器的同一個端口上。
Lighttpd服務于80端口,Squid運行在3128端口,Apache運行在81端口。
Lighttpd的配置
多個域名采用/var/www/domain/subdomain 的目錄結構,用evhost模塊配置document-root如下:
evhost.path-pattern = var.basedir + "/%0/%3/"
FtpSearch中有Perl腳本,需要啟用CGI支持,它是用來做ftp站內搜索的,緩存的意義不大,直接由lighttpd的mod_cgi處理:
$HTTP["url"] =~ "^/cgi-bin/" { # only allow cgi's in this directory
dir-listing.activate = "disable" # disable directory listings
cgi.assign = ( ".pl" => "/usr/bin/perl", ".cgi" => "/usr/bin/perl" )
}
bbs使用的是phpBB,訪問量不大,可以放在lighttpd(fastcgi)或者apache(mod_php)下,暫時使用 lighttpd,設置所有.php的頁面請求有fastcgi處理:
fastcgi.server = ( ".php" => ( ( "host" => "127.0.0.1", "port"=> 1026, "bin-path" => "/usr/bin/php-cgi" ) ) )
blog.daviesliu.net 和 blog.rainbud.net 是用mod_python編寫的blogxp程序,所有靜態內容都有擴展名,而動態內容沒有擴展名。blogxp是用python程序生成XML格式的數據再交由mod_xslt轉換成HTML頁面,只能放在Apache下運行。該站點采用典型Lighttpd+Squid+Apache方式處理:
$HTTP["host"] =~ "^blog" {
$HTTP["url"] !~ "." {
proxy.server = ( "" => ( "localhost" => ( "host"=> "127.0.0.1", "port"=> 3128 ) ) ) #3128端口為
}
}
share中有靜態頁面,也有用mod_python處理的請求,在/cgi/下:
$HTTP["host"] =~ "^share" {
proxy.server = (
"/cgi" => ( "localhost" => ( "host"=> "127.0.0.1", "port"=> 3128 ) )
)
}
Squid的配置
只允許本地訪問:
http_port 3128
http_access allow localhost
http_access deny all
啟用反向代理:
httpd_accel_host 127.0.0.1
httpd_accel_port 81 #apache的端口
httpd_accel_single_host on
httpd_accel_with_proxy on #啟用緩存
httpd_accel_uses_host_header on #啟用虛擬主機支持
此方向代理支持該主機上的所有域名。
Apache的配置
配置/etc/conf.d/apache2,讓其加載mod_python、mod_xslt、mod_php模塊:
APACHE2_OPTS="-D PYTHON -D XSLT -D PHP5"
所有網站的根目錄:
<Directory "/var/www">
AllowOverride All #允許.htaccess覆蓋
Order allow,deny
Allow from all
</Directory>
基于域名的虛擬主機:
<VirtualHost *:81>
ServerName blog.daviesliu.net
DocumentRoot /var/www/daviesliu.net/blog
</VirtualHost>
這里明顯沒有lighttpd的evhost配置方便。
blog.daviesliu.net下的.htaccess設置(便于開發,不用重啟Apache):
SetHandler mod_python
PythonHandler blogxp.publisher
PythonDebug On
PythonAutoReload On
<FilesMatch ".">
SetHandler None #靜態文件直接由Apache處理
</FilesMatch>
<IfModule mod_xslt.c>
AddType text/xsl .xsl #防止對xsl文件進行轉化
AddOutputFilterByType mod_xslt text/xml
XSLTCache off
XSLTProcess on
</IfModule>
Header set Pragma "cache"
Header set Cache-Control "cache"
在blogxp.publisher里面,還需要設置返回的文檔類型和過期時間:
req.content_type = "text/xml"
req.headers_out['Expires'] = formatdate( time.time() + 60 * 5 )
經過這樣的配置,所有站點都可以通過80、3128、81三個端口進行正常訪問,80端口用作對外的訪問,以減少負荷。81端口可以用作開發時的調試,沒有緩存的困擾。
性能測試
由于時間和精力有限,下面只用ab2做一個并不規范的性能對比測試(每項都測多次取平均),評價指標為每秒鐘的請求數。
測試命令,以測試lighttpd上并發10個請求 scripts/prototype.js 為例:
ab2 -n 1000 -c 10 http://blog.daviesliu.net:80/scripts/prototype.js
靜態內容:prototype.js (27kB)
Con
Lighttpd(:80)
Squid(:3128)
Apache(:81)
1
380
210
240
10
410
215
240
100
380
160
230
可見在靜態內容上,Lighttpd表現強勁,而Squid在沒有配內存緩存的情況下比另兩個Web服務器的性能要差些。
動態頁面:/rss (31kB)
Con
Lighttpd(:80)
Squid(:3128)
Apache(:81)
1
103
210
6.17
10
110
200
6.04
100
100
100
6.24
在動態內容上,Squid的作用非常明顯,而Lighttpd受限于Squid的效率,并且還要低一大截。如果是有多臺Squid來做均衡的話,Lighttpd的功效才能發揮出來。
在單機且靜態內容很少的情況下,可以不用Lighttpd而將Squid置于最前面。