根据请求的文件存在,选择Varnish后端的好方法

时间:2011-11-02 13:09:26

标签: apache nginx varnish varnish-vcl

我安装了Apache2,nginx和Varnish。 Varnish接收请求,确定它的后端(静态转到nginx,动态转到Apache),从后端获取响应并在需要时缓存它。

Apache生成缩略图的其他事项。它使用一些特定的逻辑创建缩略图,对于处理器来说它非常昂贵。因此,Apache将拇指保存到磁盘,以便下次收到此缩略图的请求时,Varnish可以将其直接重定向到nginx。

这是一个问题: Varnish无法检查文件是否存在于文件系统的某处,这就是为什么它不知道是否可以使用nginx后端或者Apache应该首先生成缩略图的原因。

我目前采用的解决方法非常简单但很难看:

  1. Varnish收到缩略图请求;
  2. Varnish向nginx发送请求;
  3. 如果nginx找不到缩略图文件,则回复404错误,Varnish将请求重定向到Apache。
  4. 虽然这个算法在现实中似乎很简单但事实并非如此。 VCL配置文件中需要以下实现:

    1. vcl_recv中始终假设缩略图存在且所有请求必须重定向到nginx 如果未从某个特殊主机请求;
    2. vcl_fetch捕获对象HTTP状态,如果它是404并且资源是缩略图而不是将主机重写为特殊的并重新启动该过程:
    3. VCL:

      if( obj.status == 404 ) {
          if(req.url ~ "^thumb/") {
              set req.http.host = "thumb_generator.site.com";
              set req.url = regsub(req.url, "/thumb/(filename)", "thumb_gen.php?filename=\1");
      
              restart;
          }
      }
      

      也许有更好的方法来解决这个问题?我知道Varnish在VCL中支持C,也许最好用C代码检查文件是否存在?

4 个答案:

答案 0 :(得分:4)

好的,如果有人对解决方案感兴趣,我在VCL配置中找到了一个带内联C的新版本。首先,我们必须添加一个函数来检查文件是否存在(在任何函数之外的文件顶部添加某个地方):

C{
#include  <stdio.h>
#include  <stdlib.h>

int exists (char *fname)
{
    FILE *file;
    if (file = fopen(fname, "r"))
    {
        fclose(file);
        return 1;
    }

    return 0;
}
}C

我知道有更好的方法来检查文件是否存在,但VCL中没有主要标头:/

然后在vcl_recv子例程中添加以下代码:

C{
    if( exists("/local/file/path") == 1 ) {
        VRT_l_req_backend(sp, VCL_conf.director[1]);
    } else {
        VRT_l_req_backend(sp, VCL_conf.director[2]);
    }
}C

像魅力一样。

答案 1 :(得分:2)

你正在使用Varnish来制作它不适合的东西。它确实不可能检查文件是否存在,因为它不是首先提供文件。 Varnish只是暂时缓存文件或内存存储中的后端响应。

在这个设置中你真的需要清漆吗?让nginx检查文件是否存在或者将其转发给您的处理器会不会更有意义?

答案 2 :(得分:1)

为什么不使用Nginx的try_files指令在404上静默代理Apache的请求?至少对我来说似乎更合乎逻辑。

答案 3 :(得分:1)

您可能会对libvmod-utils感兴趣。您可以访问WASD42建议的内容,但可以直接使用VMOD(更清洁,应该有最新的改进和建议)而不是inline-C。

Inline-C很好,因为你可以做任何你需要的事情,但有时候VMOD更干净,并且不会破坏你的VCL语言。

下面是一个实现您需求的VCL示例:

import utils;

sub vcl_recv {
    if(req.url ~ "^/thumb/") {
        if (utils.exists("/srv/www/static/" + req.url)) {
            set req.backend = nginx;
        else {
            set bereq.url = regsub(req.url, "/thumb/(filename)", "thumb_gen.php?filename=\1");
            set req.backend = apache;
        }
    }
}