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

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

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

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

Обходной путь, который я сейчас принял, довольно прост, но уродлив:

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

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

  1. В vcl_recv всегда предполагайте, что миниатюра существует и все запросы должны быть перенаправлены на nginx, если они не запрашиваются с какого-то специального хоста;
  2. В vcl_fetch перехватите HTTP-статус объекта, и если он 404, а ресурс миниатюрный, то перепишите хост на специальный и перезапустите процесс:

ВКЛ:

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-кода?


person WASD42    schedule 02.11.2011    source источник
comment
Пожалуйста, используйте тег лак-vcl вместо vcl, так как тег vcl уже популярен в сообществе Delphi. Сегодня мод изменил теги всех тегов VCL.   -  person Warren P    schedule 03.11.2011


Ответы (4)


ОК, если кого-то интересует решение, я нашел новое со встроенным 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

Работает как шарм.

person WASD42    schedule 02.11.2011
comment
Чары не работают. Но хорошее решение! Если вы пытаетесь уменьшить задержку, вы можете вместо этого использовать fstat() для файла, что, как я полагаю, выполняет меньше операций ввода-вывода на диске. На самом деле он не открывает файл, он просто подтверждает, что файл есть, из записи каталога: linux .die.net/man/2/fstat - person JasonSmith; 26.06.2015

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

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

person ivy    schedule 02.11.2011

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

person uknzguy    schedule 04.02.2012

Возможно, вас заинтересует 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;
        }
    }
}
person Doomsday    schedule 12.02.2014