2

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

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

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

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

  1. Varnish 收到缩略图请求;
  2. Varnish 向 nginx 发送请求;
  3. 如果 nginx 找不到缩略图文件,它会回复 404 错误,并且 Varnish 会将请求重定向到 Apache。

虽然这个算法实际上看起来很简单,但事实并非如此。VCL 配置文件中需要以下实现:

  1. vcl_recv始终假设缩略图存在,如果不是从某个特殊主机请求,则所有请求都必须重定向到nginx
  2. vcl_fetchcatch 对象 HTTP 状态中,如果它是 404 并且资源是缩略图,则将主机重写为特殊主机并重新启动进程:

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

4 回答 4

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

奇迹般有效。

于 2011-11-02T15:02:40.870 回答
2

你正在使用 Varnish 来做一些它不是为它做的事情。它确实不可能检查文件是否存在,因为它最初不是用来提供文件的。Varnish 只是在文件或内存存储中临时缓存后端响应。

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

于 2011-11-02T19:28:38.227 回答
2

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

于 2012-02-04T11:39:41.987 回答
1

您可能会对libvmod-utils感兴趣。您将可以访问 WASD42 建议的内容,但可以直接使用 VMOD(更干净,并且应该应用最新的改进和建议)而不是内联 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;
        }
    }
}
于 2014-02-12T20:51:13.590 回答