Информация

Дата основания
Местоположение
Россия
Сайт
vdsina.ru
Численность
11–30 человек
Дата регистрации

Блог на Хабре

Обновить
Комментарии 22
Код выполняется асинхронно, не вмешиваясь в основной цикл событий Nginx

Это значит, что новый поток создается на каждый запрос?
Как понимаю, автотесты для такого кода не напишешь? Только отдельными утилитами, поднимая nginx в докере и кидая в него запросы.
Это значит, что новый поток создается на каждый запрос?

Это значит, что используются асинхронные вызовы. Прекратите уже путать асинхронность и параллельность. Это не связанные между собой понятия, и возможны все четыре варианта их комбинации.

Кажется это вы что-то напутали. Предлагаю наводящий вопрос: что произойдёт, если в lua-коде окажется вечный цикл?

То поток заблокируется. Какой именно поток — зависит от реализации, скорей-всего из отдельного пула. Само по себе суждение "используются асинхронные вызовы" не даёт информации о том, в каком потоке это будет происходить. И уж тем более из этого не следует, что на каждый запрос будет создаваться поток. Асинхронно можно делать и в одном потоке (см. javascript).

Мой наводящий вопрос был именно к тому, какой именно поток заблокируется.
Хотел бы уточнить куда более просто и прямо. В каком потоке будет исполняться lua? В потоке в котором идёт обработка соебинения, или в отдельном, дочернем потоке?
Кэширование с Upstream

Ничего не кеширует, просто будет держать соединения к апстриму за счет Keep-Alive.


serve_image.lua

мне кажется, проще будет это сделать на proxy_pass + proxy_cache*.


Но за статью спасибо, было интересно.


PS: На убунте, если не нужен весь openresty, а именно lua, достаточно ничего не компилируя поставить сам nginx (или нет, если у вас уже установлен) и доставить к нему модули. например, так:
apt-get install nginx
apt-get install nginx-extras

Там скорее всего просто lua, а не lua-jit, для высокопроизводительных решений это важно.

Зачем так сложно-то? Размещаем статику просто на поддомене без кукисов и всё.

Спасибо, я в курсе.

Извините, не помню источник, но суть вот в чем:
Use Cookie-free Domains for Components

When the browser makes a request for a static image and sends cookies together with the request, the server doesn't have any use for those cookies. So they only create network traffic for no good reason. You should make sure static components are requested with cookie-free requests. Create a subdomain and host all your static components there. If your domain is www.example.org, you can host your static components on static.example.org. However, if you've already set cookies on the top-level domain example.org as opposed to www.example.org, then all the requests to static.example.org will include those cookies. In this case, you can buy a whole new domain, host your static components there, and keep this domain cookie-free. Yahoo! uses yimg.com, YouTube uses ytimg.com, Amazon uses images-amazon.com and so on.

Another benefit of hosting static components on a cookie-free domain is that some proxies might refuse to cache the components that are requested with cookies. On a related note, if you wonder if you should use example.org or www.example.org for your home page, consider the cookie impact. Omitting www leaves you no choice but to write cookies to *.example.org, so for performance reasons it's best to use the www subdomain and write the cookies to that subdomain.


Сайт уже много лет работает, www не используется.
Альтернативный вариант — только отдавать статику с другого домена.

Собственно, вопрос по теме поста — программированию в nginx функционала по обрезанию кук на лету, а не «как избавиться от кук» в целом.
Если задача сэкономить трафик и облегчить жизнь проксям, то резать куки в nginx уже поздновато, разве нет?
это зависит от двух вещей:
1. что проще в реализации
2. насколько сильный оверхед добавит подобный функционал.

Я понимаю, ваши уточняющие вопросы вполне закономерны, но они и близко не отвечают на поставленный вопрос.
Судя по всему, никто не пытался. Остальное — просто флейм на тему.

Кусок из рабочего конфига:


header_filter_by_lua_block {
    local NewCookies = ngx.header['Set-Cookie'] -- get cookies
    <cut>
    ngx.header['Set-Cookie'] = NewCookies
}

Для очистки, вероятно, будет достаточно присвоить пустой table или nil.

хочу чтобы в конце было всё для докера чтобы быстро запустить этот Hello World и не копипастить кучу команд
Бонус! Примеры без использования Lua вообще

Какие-то каличные примеры. Приведу своих. Они может и не идеальны, но работают исправно без лишней нагрузки на мозг.
1) Раздача файлов через nginx с проверкой на доступ к загрузке, авторизация или еще что (auth_request)
nginx
server {
    root /var/www/example.com;
    location ~ \.(zip|png)$ {
        auth_request /auth;
        add_header Cache-Control no-cache;
    }

    location = /auth {
        internal;
        proxy_pass https://example.com/check_auth;
        proxy_set_header X-Original-URI $request_uri;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
    }
}


php
function user_check_auth()
{
    if (is_granted())
    {
        header('HTTP/1.1 200 OK');
        header('Status: 200 OK');
    } else {
        header('HTTP/1.1 403 Forbidden');
        header('Status: 403 Forbidden');
    }
    exit;
}



2) Подсчет кол-ва загрузок (X-Accel-Redirect)
nginx
server{
    root /var/www/example.com;
    set $counter /var/www/files/src/counter.php;

    location ~ ^/files/(?<g1>.*\.zip)$ {
        fastcgi_pass unix:/usr/local/var/run/php-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $counter;
        include fastcgi_params;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
        fastcgi_param REQUEST_URI /$g1;
        fastcgi_param X-File-Type arch_zip;
        set $_uri /$g1;
    }

    location @counter {
        root /var/www/upload.example.com;
        try_files $_uri =404;
    }

    location / {
        try_files $uri $uri/ =404;
    }
}


php
// /var/www/files/src/counter.php
<?php

header('X-Accel-Redirect: @counter');
header('Content-Type: application/octet-stream');

use Symfony\Component\Console\Input\ArrayInput;

if (!empty($_SERVER['REQUEST_URI']) && !empty($_SERVER['X-File-Type'])) {
    $filename = parse_url(htmlspecialchars(basename($_SERVER['REQUEST_URI'])), PHP_URL_PATH);
    $fileType = htmlspecialchars($_SERVER['X-File-Type']);
    require_once __DIR__ . '/../vendor/autoload.php';

    set_time_limit(10);
    $input = new ArrayInput([
        'counter:tick',
        'filename' => $filename,
        'type' => $fileType,
    ]);
    $app = require __DIR__ . '/app.php';
    require __DIR__ . '/../config/prod.php';

    /* @var \Symfony\Component\Console\Application $console */
    $console = require __DIR__ . '/console.php';
    try {
        $console->run($input);
    } catch (\Exception $exception) {
        return;
    }
}

// /var/www/files/src/console.php
<?php
// ...
$console->register('counter:tick')
    ->setDescription('Counter for download files')
    ->setDefinition([
        new InputArgument('filename', InputArgument::REQUIRED, 'File name'),
        new InputArgument('type', InputArgument::REQUIRED, 'File Type')
    ])
    ->setCode(function (InputInterface $input) use ($app) {
        $filename = $input->getArgument('filename');
        $fileType = $input->getArgument('type');
    
        /* @var \Uploader\Entity\FileType $type */
        $type = $app['repository.file_type']->findByType($fileType);
        if (!$type) {
            return;
        }
        
        /* @var \Uploader\Entity\File $file */
        $file = $app['repository.file']->findByTypeAndName($type->getType(), $filename);
        if (!$file) {
            return;
        }
        
        $file->incDownloadCount();
        $app['repository.file']->save($file);
    });

а что мелочитесь с функциями «безопасности»?
$filename = parse_url(stripslashes(htmlentities(strip_tags(nl2br(quoted_printable_encode(htmlspecialchars(basename($_SERVER['REQUEST_URI']))))))), PHP_URL_PATH);
Реинкарнация mod_perl?
Дурацкий вопрос — а зачем? Как только народ начнет накручивать логику на подобные сценарии, он наступит ровно на те же грабли, что возникали с mod_perl. Разве нет?
Лично я пользуюсь lua-resty-auto-ssl. Вполне удобный кейс.
Хорошая штука. У нас уже используется.
В связке с ngx_postgres — вообще бомба получается.
Отличная статья, спасибо. Обучаясь в одном иностранном колледже, писал простой учебный проект на OpenResty, REST сервис, работающий через Nginx+Lua с MySQL. Простейшие тесты показали огромную производительность на слабеньком учебном ПК.
На текущей работе используем связку OpenResty+PowerDNS в качестве распределённого по геозонам DNS кластера.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.