通过Nginx架设灵活的网站静态化方案

鉴客 发布于 2010/06/11 13:10
阅读 5K+
收藏 12

最近在做一个网站项目,功能基本已经完成,目前主要的难点在于性能的调优上,其实网站第一期已经上线,目前正在进行第二期的改版中,而性能也归为第二期的 重点。

第一期的主要任务是功能的实现,因此并未在性能上进行过多的考虑,最终第一期上线就是直接lighttpd + fastcgi + django + memcached + mysql,只考虑了后台数据库缓存,web前端没有做任何优化,因此二期性能优化的重点在于页面缓存。

由于站点本身的业务比较简单,对于数据的实时性要求不是很高,因此网站性能可优化程度较高,而对于网站前端优化的主体方案,无非就是页面静态化,或者是反 向代理做缓存(如squid),经过多次讨论以及测试,页面静态化最终成为我们的首选方案。

决定使用页面静态化后,如何进行静态化策略就成了主要的话题,而在第一次请求时动态生成页面并进行静态化得到了小组内成员的一致的赞成。

我们第一期是使用的lighttpd作为WEB服务器,但是lighttpd却不能满足我们首次请求生成静态页面,因为lighttpd在请求一个无效静 态资源后,无法自动再进行一次有效的动态请求(也许是我不知道如何配置),因此决定在lighttpd前面再加一个针对于静态资源请求的nginx。

为什么选择nginx?原因太多了,nginx速度快就不用说了,而它的配置却更是灵活,相比lighttpd就显得相对单薄了,nginx还可以在配置 中嵌入perl脚本,更是大大增加了前端处理请求的能力。当然,nginx的缺点也是有的,总之没有最好的软件,只有最适合的软件。

Nginx最新版本0.7.52(非稳定版),也是目前我们正在使用的版本,选择这个版本的主要原因就是0.7版本以后,nginx才加入一个 try_files指令,而这个指令的作用就是可接收多个路径作为参数,当前一个路径的资源无法找到,则自动查找下一个路径,而这个功能正是我们所需要的 功能,既当第一次请求时,静态资源不存在,那么我们就将请求proxy到后台服务器上进行动态处理,返回响应同时生成静态文件,下次请求即可通过 try_files的第一个参数直接定位,而nginx的静态资源响应速度,相信不用我说,大家都清楚了,大致的配置如下:

Java代码
  1. location ~   / {   
  2.      root /.../.../...;  //设置根目录   
  3.      try_files /$filepath @to_other;  //第一个文件路径为root+/$filepath   
  4. }   
  5.   
  6. 上面第一个文件找不到,则跳转到@to_other  
  7. location @to_other{   
  8.      proxy_pass     http://127.0.0.1:8080;     //请求转发   
  9. }  


配置是否很简单?如此就可以满足我们的基本需求了。当然,这仅仅是一个简单的例子,我们还可以直接在配置中使用if语句,进行一些简单的判断,可惜目前的 版本所支持的if语句只能够做一次判断,不能and or。不过nginx也同时提供了嵌入perl的功能,所以我们实际可以在配置中做很多事情,比如,我们静态文件生成后,什么时候失效呢?因为当静态文件 生成后,我们的请求最终只会被nginx拦截,按照很多人的做法,那就是在服务器加上一个后台进程,该进程进行静态文件的失效判断,并删除,但是这种方式 的弊端很大,先不说其他的,单是在性能上就会有很大影响,当然,你可以在非高峰期做,只是这种做法效果其实并不好。

那如何通过nginx实现这一步呢?其实很简单,我们可以通过前面说的,在nginx里嵌入perl脚本,每当请求来的时候,根据请求获得静态文件路径并 读取文件更新时间,和当前系统时间进行对比,超过失效时间则算失效,而对于失效的文件最好的办法不是删除,而是通过更改上面try_files指令所指向 的文件路径,给一个假路径它,即可让请求直接转向后台,由后台重新生成一个相同的文件,并覆盖即可,配置内容大致如下:

Java代码
  1. perl_set $data_filename '   
  2. use nginx;   
  3. use URI;   
  4.   
  5. sub {   
  6.      my $r = shift;   
  7.      my $xmldatahome = "/.../.../"; //xml文件目录   
  8.      my $re = $r->path."xml"; //根据uri生成文件名   
  9.     if(-f $xmldatahome.$re){   
  10.         // 获得更新时间,并判断失效   
  11.         if(time() - stat($xmldatahome.$re)->mtime > 1800){   
  12.             return "";   
  13.          }   
  14.      }   
  15.     return $re;   
  16. }';   
  17.   
  18. location ~   / {   
  19.           root /.../.../...;  //设置根目录   
  20.           try_files /$data_filename  @to_other;   
  21.      }  


以上的配置就是通过perl代码生成文件名,如果文件不存在或者超过1800分钟,则请求跳转到@to_other,是否很简单很灵活?

看到这里,应该可以看出,nginx的配置可以有多灵活,可惜的是嵌入perl代码还只是在实验阶段,稳定性很难保证,因此不应该将过多复杂的判断通过它 来完成,而且也不赞成在前端web服务器做复杂的逻辑,同时嵌入perl脚本目前所能获取的请求的数据也比较有限,目前我们通过nginx所做的也仅仅是 一些简单的和静态化资源相关的判断。

现在我们的整体架构就是在原有的基础上前面增加了一层nginx作为静态请求过滤,后端lighttpd的压力被降至最低。

也许有的朋友会问,nginx也可以直接请求fastcgi,为什么后面还要加一个lighttpd?关于这个问题其实主要原因在于我们对于nginx的 稳定性有所顾忌,毕竟也是第一次用,所以并没有直接用nginx请求fastcgi,而是沿用了旧的方式,同时暂时也不想做太大的改变。

目前还没提交测试组进行压力测试,所以无法得知在性能上提升会有多大,我也在拭目以待。

加载中
0
范堡
范堡

在PHP方面~

我在 fastcgi 跟 Apache 之间考虑了好久.最后还是因兼容问题选择了后者.

没有最好的软件,只有最合适的软件.这真是真道理。

0
火星人
火星人

nginx+静态化=高效;perl来实现简单逻辑还是一个不错的效率+灵活的选择。

返回顶部
顶部