Хороший способ выбирать между серверными по Varnish в зависимости от наличия запрошенного файла

#apache #nginx #varnish #varnish-vcl

#apache #nginx #varnish #varnish-vcl

Вопрос:

У меня есть установка с Apache2, nginx и Varnish над ними. Varnish получает запрос, определяет, для какого бэкэнда он предназначен (статический отправляется в nginx, динамический — в Apache), извлекает ответ из бэкэнда и при необходимости кэширует его.

Среди прочего Apache генерирует эскизы. Он создает эскизы, используя определенную логику, и это довольно дорого для процессора. Таким образом, Apache сохраняет thumb на диск, чтобы в следующий раз, когда будет получен запрос на этот эскиз, Varnish мог перенаправить его непосредственно в nginx.

И вот в чем проблема: Varnish не имеет возможности проверить, существует ли файл где-то в файловой системе, и поэтому он не знает, можно ли использовать серверную часть nginx или Apache должен сначала сгенерировать эскиз.

Решение, которое я принял в настоящее время, довольно простое, но уродливое:

  1. Varnish получает запрос на миниатюру;
  2. Varnish отправляет запрос в nginx;
  3. Если nginx не может найти файл миниатюр, он выдает ошибку 404, и Varnish перенаправляет запрос на Apache.

Хотя этот алгоритм кажется простым, на самом деле это не так. В файле конфигурации VCL требуется следующая реализация:

  1. vcl_recv Всегда предполагайте, что эскиз существует, и все запросы должны быть перенаправлены на nginx, если они не запрашиваются с какого-либо специального хоста;
  2. В vcl_fetch catch object HTTP status и если он равен 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 поддерживает C в VCL, может быть, лучше проверить наличие файла с помощью C-кода?

Комментарии:

1. Пожалуйста, используйте тег varnish-vcl вместо vcl, поскольку vcl уже является популярным тегом в сообществе Delphi. Сегодня мод переназначил все теги varnish vcl.

Ответ №1:

Хорошо, если кто-то заинтересован в решении, я нашел новое решение со встроенным C в конфигурации VCL. Прежде всего, мы должны добавить функцию для проверки существования файла (добавьте где-нибудь в верхней части вашего файла вне какой-либо функции):

 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. Прелести не работают. Но хорошее решение! Если вы пытаетесь уменьшить задержку, вы можете вместо этого использовать fstat() для файла, который, я полагаю, выполняет меньше операций ввода-вывода на диске. На самом деле он не открывает файл, он просто подтверждает, что файл находится там из записи каталога: linux.die.net/man/2/fstat

Ответ №2:

Вы используете Varnish для чего-то, для чего он не был создан. Действительно, у него нет возможности проверить, существует ли файл, потому что он изначально не был создан для обслуживания файлов. Varnish просто временно кэширует ответы сервера в файле или в памяти.

Вам действительно нужен varnish в этой настройке? Разве не было бы гораздо разумнее, если бы nginx проверил, существует ли файл, или переслал его вашему процессору?

Ответ №3:

Почему бы не использовать директиву try_files от Nginx для автоматической передачи запроса Apache на 404? Это казалось бы более логичным, по крайней мере, для меня.

Ответ №4:

Вас, вероятно, заинтересует libvmod-utils. У вас будет доступ к тому, что предложил WASSD42, но непосредственно с помощью VMOD (более чистого, и должны применяться последние улучшения и советы) вместо встроенного-C.

Встроенный 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;
        }
    }
}