Перепишите запросы изображений на URL-адрес CDN с помощью Varnish

У меня есть Varnish (3.0.3), работающий как балансировщик нагрузки/статический кеш перед двумя веб-серверами. У меня есть CDN, настроенный с использованием метода Original Pull. Если я возьму URL-адрес изображения на своем сайте вручную, укажу адрес CDN, я смогу убедиться, что исходное извлечение работает, и изображение загружается в CDN и обслуживается.

Мое приложение довольно сложное, и я тестирую этот CDN, чтобы увидеть, значительно ли он ускоряет веб-приложение, поэтому я пока не хочу переписывать какой-либо из моего 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 для такого перенаправления? Не лучше ли настроить nginx перед Varnish, чтобы переписывать запросы к cdn?

ОБНОВЛЕНИЕ. Используя оба приведенных ниже ответа, у меня работает перенаправление и установлен ACL, позволяющий CDN извлекать изображения напрямую, а не перенаправлять на себя. Однако, хотя я убедился, что ACL разрешает подключение с использованием моего собственного внешнего IP-адреса, CDN не загружает новые изображения с сервера. Он выдает ошибку 502 (нечетная‹) вместо того, чтобы загружать изображение с локального сервера в 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);
  }
}

person Jmichelsen    schedule 13.11.2012    source источник


Ответы (2)


Вы определенно можете сделать это с 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);
  }
}

Вы забыли «http://» в своем URL-адресе CDN, и вы можете опустить последнюю косую черту в имени хоста, поскольку все req.url начинаются с /.

Вы также должны убедиться, что код vcl_error является первым, который запускается в vcl_error(). т.е. если у вас есть несколько определений vcl_error, убедитесь, что ни одно из них не выводит никаких результатов до того, как будет достигнута проверка if (obj.status == 750).

Имейте в виду, что это решение заставляет все клиентские браузеры сначала запрашивать ваш сервер, а затем делать другой запрос в CDN после перенаправления 302. Это добавляет значительную задержку к загрузке каждого изображения и, вероятно, не лучший способ определить, улучшает ли CDN производительность вашего приложения.

Обновление: относительно ваших проблем с CDN, показывающей ошибку 502 при попытке извлечь контент из вашего источника. Полагаться на удаленный 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 никогда не будут перенаправлены.

person Ketola    schedule 15.11.2012
comment
спасибо за подробности здесь. Вопрос о 302 и задержке. Итак, типичный процесс для этой настройки: браузер нажимает на Varnish> переходит к любому из двух серверов> читает html> отображает html и изображение из исходного URL-адреса в html. С Varnish 302: браузер открывает Varnish> передает браузер на сервер для html и CDN для изображений> отображает html и изображения. Правильно ли я понимаю? Если да, то это должно быть лучше, чем писать перенаправление в httpd.conf или .htaccess, потому что это происходит раньше для браузера, а изображения/html должны поступать из двух источников параллельно? (CDN/локальный сервер) - person Jmichelsen; 15.11.2012
comment
и в ответ на мой вопрос с вопросом ... Использование mod_pagespeed и ModPagespeedMapRewriteDomain для перезаписи обслуживаемого html ... будет ли это менее или более эффективным, чем этот метод Varnish? Проблема с MapRewriteDomain заключается в том, что он делает все, а не только изображения, и я этого не хочу, но для испытаний производительности, где это упадет? - person Jmichelsen; 15.11.2012
comment
Кажется, это работает отлично, если не считать проблемы, которую решает @arober11. Когда я активирую этот vcl, все изображения отображаются как исходящие из CDN. Однако образы, которых нет в CDN, через нее уже не протягиваются. Я поставил предложенный acl на место, проверил, что он работает, добавив туда свой внешний IP, но CDN почему-то не загружает образы. 502 ошибки - person Jmichelsen; 16.11.2012
comment
Извините за долгую задержку с ответом на вас. Сначала я отвечу на первый вопрос: переписывание HTML — лучшее решение, поскольку оно сокращает количество подключений. Браузер немедленно запрашивает изображение из правильного источника (например, cdn.com/pic.gif). При использовании переадресации 302 каждый запрос равен 1) domain.com/pic.gif (ответ 302) 2 ) cdn.com/pic.gif (200 ответов). - person Ketola; 26.11.2012
comment
Что касается ошибки 502, вы должны определить отдельный источник для ваших изображений, который не перенаправляется. По крайней мере, для сервисов CDN, которые мы использовали, вы можете свободно определять URL-адрес источника для своих изображений. Это не должно быть публичным. Таким образом, вы можете настроить, например, static.domain.com, чтобы он служил источником только для вашей CDN, и пропустить перенаправление 302 для хоста, добавив && req.http.Host != static.domain.com к условию в vcl_recv() - person Ketola; 26.11.2012
comment
Не беда, это Праздник! Хорошо, я понимаю, что 302 добавит дополнительную нагрузку, однако метод mod_pagespeed технически переписывает HTML. В общем, вы считаете, что это нормальный вариант в качестве временного решения? - person Jmichelsen; 27.11.2012
comment
В качестве временного решения, я думаю, подойдет любой из них. У меня нет опыта запуска mod_pagespeed на действующем сайте, поэтому я не могу сказать, какое влияние это может оказать на производительность. Поскольку вы стремитесь проверить прирост производительности в реальном мире, я бы просто укусил пулю и изменил приложение, чтобы оно обслуживало изображения непосредственно из CDN. Когда-то мы создали специальную функцию cdnHost(pic.gif), которая выводит полный URL-адрес pic.gif, чтобы упростить нам переключение между нашим собственным сервером статических изображений и провайдером CDN и, таким образом, сравнить услуги. - person Ketola; 27.11.2012
comment
Спасибо за помощь Кетола - person Jmichelsen; 28.11.2012

Предполагая, что у вас есть 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;
        }
    }
...
person arober11    schedule 15.11.2012
comment
да, попробовал решение выше и начал получать 502 ошибки от CDN, потому что он никогда не мог попасть на мой сервер для исходного изображения. Сейчас я пробую смешанное решение... спасибо за это - person Jmichelsen; 15.11.2012