• Lighttpd+Squid+Apache搭建高效率Web服务器
    时间:2009-01-05   作者:佚名   出处:互联网

    架构原理

    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的配置

    只允许本地访问:

    启用反向代理:
    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_pythonmod_xsltmod_php模块:
    APACHE2_OPTS="-D PYTHON -D XSLT -D PHP5"

    所有网站的根目录:
    <Directory "/var/www">
    AllowOverride All #允许.htaccess覆盖
    Order allow,deny
    Allow from all
    </Directory>

    基于域名的虚拟主机:

    这里明显没有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 )

    经过这样的配置,所有站点都可以通过80312881三个端口进行正常访问,80端口用作对外的访问,以减少负荷81端口可以用作开发时的调试,没有缓存的困扰
    性能测试

    由于时间和精力有限,下面只用ab2做一个并不规范的性能对比测试(每项都测多次取平均),评价指标为每秒钟的请求数
    测试命令,以测试lighttpd上并发10个请求 scripts/prototype.js 为例:
    ab2 -n 1000 -c 10 http://blog.daviesliu.net:80/scripts/prototype.js

    静态内容:prototype.js (27kB)

    可见在静态内容上,Lighttpd表现强劲,而Squid在没有配内存缓存的情况下比另两个Web服务器的性能要差些

    动态页面:/rss (31kB)

    在动态内容上,Squid的作用非常明显,而Lighttpd受限于Squid的效率,并且还要低一大截如果是有多台Squid来做均衡的话,Lighttpd的功效才能发挥出来
    在单机且静态内容很少的情况下,可以不用Lighttpd而将Squid置于最前面
    网友留言:

    这种搭配倒是可以 不过正文描述有些地方有问题

    light 可以自己加上cache支持 但从性能只考虑cache看比squid还好一点(平均每秒3000+线上实际数据)

    squid 那块说的不太对 处理静态优化到99.99%以上的hitratio后 基本上作用非常大

    对整体结构也很有好处

    light+squid+apache的结构过渡时期实际在线也跑过 当时是后端没做压缩支持

    实际上每一块都可以根据自己需要patch 没有最好 只有更合适 可管理性很重要

    lighttpd + php 访问量大的话经常会导致 php 死掉,然后 500

    不管是 local 还是 remote 方式

    无奈,换 zeus 了,很坚挺,商业的就是商业的

    His result looks weird, as a result, his conclusion is wrong.

    Squid does not boost dynamic page at all, the speed gain in his test is because his client is requesting the same page in paralell, and squid will return the same page for the concurrent requests. I also guess that he did not configure expire time for static content in his web server, Squid will try to refetch the file with If-Modified-Since header for each request. That's why squid performs poor in the static test.

    不太同意这一点,对Squid而言,动态页面和静态页面是一样的,只要设置好HTTP头,

    如果设置Expires,是没有缓存效果的

    如果不能Cache动态页面的话,那怎么起到加速效果?

    不好意思,英语不好,误导你了,上午在单位的机器没法输入中文

    动态页面除非正确设置HTTP的过期时间头,否则就是没有加速效果的.反过来说,静态页面也需要设置过期时间头才对.

    我说的设置 expire 时间是指的把过期时间设置到几分钟后或者几小时后,这样页面就在这段时间内完全缓冲在squid里面.

    你实际测试动态页面有性能提升,这有几种可能,一是你的测试用的是并发请求同一个页面,squid对并发的同页面请求,如果拿到的结果里面没有 non cache 头,会把这一个结果同时发回给所有请求,相当于有一个非常短时间的cache,测试结果看起来会好很多,但是实际因为请求同一页面的机会不是很多,所以基本没有啥改进,另一种情况是你用的动态页面程序是支持if-modified-since头的,他如果判断这个时间以后么有修改过,就直接返回not modified,速度也会加快很多.

    所以其实squid在实际生产中大部分时间都是用于缓冲静态页面的,动态页面不是不能缓冲,但是需要页面程序里面做很多配合,才能达到比较好的效果

    newsmth的 www 高峰时候是 600qps ,squid端还是比较轻松,瓶颈在后端.

    多谢你的详细解答!

    我文章中写了,每个请求都会添加 Expires 头为当前时间的后5分钟,即每个页面的有效期为5分钟,Squid似乎会根据这个时间来判断是否刷新缓存,无需服务器支持If-modified-since

    这个5分钟是根据页面的一般更新频率来确定的.

    如果是访问量很大的Web应用,比如newsmth的www,如果将php页面的失效时间设置为1-2秒,则这段时间内的请求都会用缓存来回应,即使在这段缓存时间内数据更新了,但并不影响用户的使用,1-2秒钟的滞后效应对用户的体验影响并不大,但换取的是更快的服务器响应尤其是访问量大但更新并不频繁的blog部分,这样做可能很有效

    当然,如果实现了If-modified-since接口,将更有效,但工作量太大

    看来是我没有仔细看你文章了, 确实没有注意到你文章里面提了 expire 头

    静态页面也可以设置 expire 头的,用 web server 的一个模块就可以

    这样基本就是全部用 squid 缓冲了.

    没有 expire 头的时候,squid就会每个请求都用 if modified since 去刷.

    smthwww的php 页面expire时间是 5 分钟还是 10 分钟来着,我忘记了.

    总的感觉多此一举阿,如果没有非常巨大的访问量,squid的解决方案就足够了

    如果真用了lighttpd, 基本上没有什么必要要apache了,

    除非是非常特别的应用, lighttpd基本上都能支持的.

    单机折腾这么多层,是不会有什么性能收益的.

    其实lighttpd的缓存功能很强大,你可以看看他的cml文档,能很好的解决动态内容的缓存问题而且如果是单机服务器的话在架个squid意义不大当然除非你要缓存的东西实在太多,squid的Bloom Filter还是非常有效的

    lighttpd有bug,内存泄漏比较严重我现在用nginx,正在lilybbs上测试效果其实把动态内容静态化才是最终出路那些点击量真想去掉

    目前lilybbs的架构:

    ------ nginx ---------

    |                 |              |

    Squid fastcgi proxy

    | (逐步迁移) |

    静态文件 Njuwebbsd

    (逐步迁移到fastcgi上)

    ft.不支持空格排版架构请看:

    另外我觉得单机搞三层没什么必要,你这个情况可以完全抛弃apache我现在的遗憾是nginx其他都很强,就是memcache没完善,所以必须弄个Squid

    我文中的那个方案只是在特殊场合才有用,呵呵

    主来还是用来玩玩

    点击其实可以通过分析log来离线做,或者单独放一些数据,用ajax来跟新这一部分,呵呵

    头一次听说NginX,感觉应该是跟lighttpd同一个层次的东西,相差不会太大如果要拼并发性能的话,估计平不过yaws,改天做个简单测试

    同意bianbian

    单机的话没必要搞这么复杂

    一般情况的话,使用squid+apache

    使用apache的expires设置好过期时间

    动态内容设置expireslast-modified等

    数据库部分多台的话使用balance基本上这样就很好了

    NginX是个跟Squid类似的东西,比它好;好似lighttod之于Apache

    Nginx跟Squid不同的,Squid强大之处在于缓存,而Nginx只有一个简单的memcache,不能缓存到硬盘上

    我现在是采用Lighttpd+mod_cache+mod_memcache做图片的缓存,效果非常不错

    网友留言/评论

    我要留言/评论