2

我有 Varnish (3.0.3) 作为负载平衡器/静态缓存坐在两个 Web 服务器前面。我已经使用 Original Pull 方法设置了 CDN。如果我手动从网站上的图像中获取 URL,放入 CDN 地址,我可以验证原始拉取是否正常工作,并且图像被拉取到 CDN 并提供服务。

我的应用程序相当复杂,我正在测试这个 CDN 以查看它是否显着加快了 Web 应用程序的速度,所以我还不想重写我的任何 php 代码来使用 CDN 图像。

我想做的是将 Varnish 设置为重写接收到的图像文件请求,并通过 CDN 而不是直接从集群中的两个 Apache 服务器中提取它们。

我已经阅读了 Varnish 文档和一些关于如何做类似事情的在线指南,但我无法让它正常工作,需要一些帮助。

以下是我尝试执行此操作的几种不同方法(为简洁起见进行了编辑):

sub vcl_recv {
  #if request is image, redirect to CDN
  if (req.url ~ "\.(gif|ico|jpg|jpeg|png)$") {
        set req.http.host = "cdn.domain.com/";
        error 750 req.http.host + req.url;

    }

 }
sub vcl_error {
  if (obj.status == 750) {
    set obj.status = 302;
    set obj.http.Location = obj.response;
    return(deliver);
  }
}

那没有用。它导致到处都是损坏的图像,并且确实出现的任何东西都使用了 .webp 扩展名,所以它没有被上述条件处理。

所以我尝试了这个:

 backend cdn {
         .host = "cdn.domain.com";
         .port = "80";
}
sub vcl_recv {
  #if request is image, redirect to CDN
  if (req.url ~ "\.(gif|ico|jpg|jpeg|png)$") {

      set req.backend = cdn;
      return(lookup);
  }

}

这在页面上显示了一些图像,但是当查看它们的源时,它们看起来来自 Apache 服务器(域名不是 CDN 的域名),并且只有大约一半的图像显示......可能是浏览器缓存。

我想在这里提供一些输入,谢谢大家。

有没有办法使用 Varnish 进行这种重定向?我最好在 Varnish 前面设置 nginx 以重写对 cdn 的请求吗?

更新:使用下面给出的两个答案,我有重定向工作和一个 ACL 以允许 CDN 直接提取图像而不是重定向到自身。但是,尽管我验证了 ACL 允许使用我自己的外部 IP 进行连接,但 CDN 并没有从服务器中提取新图像。它会给出 502 错误 (odd<),而不是将图像从本地服务器拉到 CDN 并提供服务。这就是我的 vcl_recv 块现在的样子:

acl cdn {
     "ip.of.CDN";
}

sub vcl_recv {
  #if request is image, redirect to CDN
  if (req.url ~ "\.(gif|ico|jpg|jpeg|png)$") {
        if(!client.ip ~ cdn){
           error 750 "http://cdn.domain.com" + req.url;
        }
    }

 }
sub vcl_error {
  if (obj.status == 750) {
    set obj.status = 302;
    set obj.http.Location = obj.response;
    return(deliver);
  }
}
4

2 回答 2

3

你绝对可以很容易地用 Varnish 做到这一点——不需要设置 nginx 或任何东西。实际上,您的第一个解决方案非常接近成功。它只需要一些修改。

sub vcl_recv {
  #if request is image, redirect to CDN
  if (req.url ~ "\.(gif|ico|jpg|jpeg|png)$") {
        error 750 "http://cdn.domain.com" + req.url;
    }
}
sub vcl_error {
  if (obj.status == 750) {
    set obj.status = 302;
    set obj.http.Location = obj.response;
    return(deliver);
  }
}

您忘记了 CDN URL 中的“http://”,并且您可以省略主机的最后一个斜杠,因为所有req.urls 都以 / 开头。

您还需要确保vcl_error代码是第一个在vcl_error(). 即,如果您有多个定义vcl_error,请确保在if (obj.status == 750)达到检查之前它们都没有提供任何输出。

请记住,此解决方案会导致所有客户端浏览器首先查询您的服务器,然后在 302 重定向后向 CDN 发出另一个请求。这会显着增加每个图像加载的延迟,并且可能不是确定 CDN 是否可以提高应用程序性能的最佳方法。

更新:关于您在尝试从源中提取内容时显示 502 错误的 CDN 问题。依靠远程 IP 地址来确定重定向是非常冒险的,因为 CDN 可以很好地使用多个服务器来进行拉取,并且地址可能会随着时间而改变。这将使 VCL 维护起来非常费力且容易出错。

是否可以设置一个唯一的虚拟主机供 CDN 使用?例如originpull.domain.com并设置 CDN 以便从该地址而不是您的主www.domain.com地址中提取内容?

然后,您可以修改vcl_recv()如下:

sub vcl_recv {
  #if request is image and request is not made from CDN, redirect to CDN
  if (req.http.host != "originpull.domain.com" &&
      req.url ~ "\.(gif|ico|jpg|jpeg|png)$") {
        error 750 "http://cdn.domain.com" + req.url;
    }
}

这将确保来自 CDN 的请求永远不会被重定向。

于 2012-11-15T08:50:37.990 回答
1

假设您有 CDN 从站点中提取图像的副本,并且您没有手动将图像推送到 CDN。您是否错过了从重写或后端代理中排除 CDN 网络的简单内容?由于 CDN 需要能够直接从您的站点提取图像的副本以填充其缓存。

自从我玩 Varnish 以来已经有一段时间了,而且从来都不是专家,但是以下几行可能会起作用:

# Defnine the IP ranges of the CDN server.
acl cdn {
        "localhost";
        "11.22.33.0"/24;
}

...

    #if request is image, redirect to CDN, unless from the CDN
    if (req.url ~ "\.(gif|ico|jpg|jpeg|png)$") {
        if (!client.ip ~ cdn) {
            error 750 "http://cdn.domain.com" + req.url;
        }
    }
...
于 2012-11-15T14:09:21.257 回答