11 заметок с тегом

nginx

Апач vs. Энжиникс

Меня кто-то убеждал буквально недавно, что Апач уже давно отдаёт статику столь же эффективно, как и nginx. На реальном весьма нагруженном проекте опыт смены одного на другое такой:

Я поставил и настроил ngnix для отдачи статического контента. Это снизило нагрузку в 2 раза…

Речь идёт о сайте president2012.ru. Версия Апача — 2-2.2.16-6+squeeze4, nginx — 0.7.67-3.

«Парсер» студии Лебедева и nginx

Смог запустить Парсер на nginx. Поставил FastCGI-сервер SimpleCGI, он принимает на вход FastCGI-запрос и запускает по нему CGI-программу. Написан на Перле, который я хорошо знаю, поэтому мне сразу видно как его можно настроить. Настройки nginx получились следующие:

server {
        listen 80;

        server_name  parser.internal;
        set $root /var/www/parser;
        root $root;

        location ~ \.(p|cgi)$ {
            include fastcgi_params;
            fastcgi_pass unix:/var/www/cgiwrap-dispatch.sock;
            fastcgi_param  SCRIPT_NAME  $fastcgi_script_name;
            fastcgi_param  PATH_INFO    $fastcgi_script_name;
            fastcgi_param  PATH_TRANSLATED $root$fastcgi_script_name;
            fastcgi_param  SCRIPT_FILENAME  $root$fastcgi_script_name;
        }
}

SimpleCGI после запуска создаёт файловый сокет «cgiwrap-dispatch.sock» к которому и обращается nginx.

Причём, что интересно, с SimpleCGI спокойно работает и Парсер из пакета, на который я жаловался, что он падает из-под thttpd.

Добавлено позже: если нужно указать путь до auto.p, то можно добавить «fastcgi_param CGI_PARSER_CONFIG путь/до/auto.p».

«Парсер» студии Лебедева и thttpd

Сегодня потратил часть дня, чтобы выяснить, что Парсер не заработает с thttpd.

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

Что-то у меня с nginx в последнее время любовь как-то не складывается.

У меня Ubuntu 10.04, поэтому я всё поставил из пакетов, Парсер в том числе, пакет неофициальный, я его нашёл в разделе прислали пользователи.

После того как я всё настроил, ничего не заработало. Отладка через strace быстро показала, что Парсер падает. Я его перекомпилировал. Если будете перекомпилировать, вот мой рецепт.

Я поставил следующие пакеты (легко допускаю, что где-то поставил лишнего, так как ориентировался по названиям): libgmime2.1-dev libgmime-2.4-2 glibc-2.10-1 libgc1c2 bison.

В каталог /opt/pcre-8.12 я положил свежую версию PCRE, в /opt/pcre лежит скомпилированная версия. Строка компиляции получилась вот такая:

CPPFLAGS='-I/opt/pcre-8.12 -I/opt/pcre/include/' \
./configure --prefix=/opt/parser3/ --with-shared-gc --with-static-pcre=/opt/pcre
make
sudo make install

После того как я стал пользоваться собранным мною Парсером, что-то в браузер я получил, но всё было не то. Причём при запуске из консоли, я получал на экран результат работы скрипта.

Тут я догадался (поскольку в консоли не видел HTTP-заголовков), что Парсер имеет какой-то механизм, который должен его переключать из режима командной строки в режим CGI и обратно. Из вида протокола CGI понятно, что это какие-то переменные окружения.

Я создал небольшой shell-скрипт, в который накидал разных переменных окружения, необходимых по стандарту для CGI и подбором выяснил, что для Парсера критично наличие переменных GATEWAY_INTERFACE, SCRIPT_NAME, PATH_INFO и PATH_TRANSLATED. Вот небольшой пример:

if(cgi) {
                // few absolute obligatory
                const char* path_info=getenv("PATH_INFO");
                if(!path_info)
                        SAPI::die("CGI: illegal call (missing PATH_INFO)");
                const char* script_name=getenv("SCRIPT_NAME");
                if(!script_name)
                                SAPI::die("CGI: illegal call (missing SCRIPT_NAME)");
                // … ещё много кода …
        }

При помощи CGI, написанного на bash, я выгрузил все переменные окружения, которые предоставляет thttpd (у меня версия 2.25b), оказалось, что двух последних переменных в дампе нет. Причём в интернете эта проблема уже поднималась (правда без связи с Парсером) и была успешна разрешена авторами thttpd. Наверное в последней версии что-то сломали.

Добавлено: я что-то явно делаю не так. Я попробовал ещё сервер mini-httpd, там в changelog есть такая фраза: «Added PATH_INFO to CGI environment», но я опять же не вижу эту переменную в окружении. В исходниках так же упоминаются обе переменных «PATH_…».

Добавлено ещё позже: так, по коду выходит следующее: если mini-httpd или thttpd находит файл по URL на файловой системе сразу, то PATH-переменные не заполняется, но заполняется SCRIPT_NAME, если не находит, то алгоритм отрезает путь до первого слеша и кладёт орезанное в PATH_INFO, формируя PATH_TRANSLATED из этого пути, присоединяя к нему рабочий каталог.

При этом куда-то пропадает SCRIPT_NAME, в коде я ещё не нашёл куда и почему. Но, похоже, для Парсера mini-httpd и thttpd (у них один автор) не подойдут.

Чтобы понимать:

http://example.org/cgi-bin/test.cgi — формируется SCRIPT_NAME, но не PATH_INFO и PATH_TRANSLATED
http://example.org/cgi-bin/test.cgi/ — формируется PATH_INFO и PATH_TRANSLATED, но не SCRIPT_NAME

И ещё позднее: попробовал веб-серверы Boa, Bozohttpd и Cherokee. Парсер с ними не заработал, причина та же — нехватает переменных. Очень похоже, что Парсер сильно неправ в своей трактовке протокола CGI.

WebDAV

Пытаюсь настроить WebDAV, чтобы им можно было пользоваться на nginx. Пока не получилось. Модуль WebDAV из nginx не умеет обрабатывать OPTIONS и PROPFIND, из-за этого клиенты не видят листинг директории. Решение простое — дать nginx обрабатывать то, что он умеет, а OPTIONS и PROPFIND отпроксировать куда-то ещё.

Для этого я взял davserver — небольшой сервер, написанный на Пайтоне. У него два достоинства: он на Пайтоне и он есть в Debian-пакетах.

Выяснилось, что это плохая идея.

Во-первых, на PROPFIND что-то отдаётся, но это что-то клиент не понимает.

Во-вторых, оказалось, что когда формируется листинг PROPFIND, в качестве базового URL там используется имя хоста из параметров запуска (там у меня localhost), а не из заголовка «host» запроса. Это я починил, поправив код.

В-третьих (это выяснилось, когда я полез в исходники), сервер писали какие-то дикие люди и он мне однозначно изнутри не понравился. Я это использовать не хочу. Например, вот так они создают директорию:

try:
            os.system("mkdir '%s'" % path)
            self._log('mkcol: Created new collection %s' % path)
            return 201

Кажется, они даже не заморачиваются экранированием спецсимволов в path, правда я бегло смотрел.

Пока не решил возьму ли что-то другое (хотелось что-нибудь небольшое, а не Apache) или буду отказываться от идеи настроить WebDAV вообще.

JavaScript V8 и nginx

Игорь Сысоев написал интересную статью «Почему Google V8 пока не подходит для встраивания в сервера», краткая выжимка:

Поскольку V8 разрабатывается в первую очередь для Chrome, то это наложило на него существенный отпечаток и, перефразируя высказывание Генри Форда о цвете машины, можно сказать, что V8 будет хорошо работать в любой программе, при условии, что эта программа называется Chrome. (…) Подытоживая вышеописанное, можно сказать, что на данный момент (версия 2.0.6.4, февраль 2010 года) V8 не подходит для серьёзного встраивания в сервера.

nginx, IE и gzip

Моё исследование (проведённое для книги, которую мы пишем) по проблемам реализации сжатия в браузерах принесло счастье пользователям nginx:

0.8.11 Изменение: теперь директива «gzip_disable msie6» не запрещает сжатие для MSIE 6.0 SV1.

Списался с Игорем Сысоевым и с версии 0.8.11 nginx не отключает gzip-сжатие для MSIE 6.0, у которого в строке user-agent присутствует SV1. SV1 (Security Version 1) означает, что установлен Service Pack 2 для IE 6, в котором проблем с gzip нет.

HTML5 и IE

Оказывается, есть немного кривой, но способ заставить IE показывать незнакомые ему теги в глобальном namespace! В частности, это поможет уже сейчас использовать семантические теги из HTML5.

Решение основано на интересном хаке:

Btw, if you want CSS rules to apply to unknown elements in IE, you just have to do document.createElement(elementName). This somehow lets the CSS engine know that elements with that name exist.

Есть другое решение, но оно требует использования namespace. В IE есть всеми забытая технология custom tags. Когда появился черновик HTML5 я пытался использовать её, чтобы внедрить в документ новые теги:

<html xmlns:html5="http://www.w3.org/html/wg/html5/">
<head>
<style type="text/css">
html5\:footer {
    display: block;
    border: 1px solid black;
    padding: 10px; 
}
</style>
</head>
<body>
<html5:footer>This is footer!</html5:footer>
</body>
</html>

Не совсем то, что нужно, если не использовать сторонние средства. Если использовать, то для альтернативного браузера можно оставлять как есть, а для правильных — вычищать ненужное пространство заменой на уровне веб-сервера (делать это не нужно, так как современные браузеры и без этого поймут такой тег, но это как-то более аккуратно).

Далее дело техники. Например, если взять Nginx, в нём есть модули rewrite, browser и sub. Первый умеет выполнять условия, второй — определять браузеры, третий — заменять одну строку на другую. Получается что-то подобное:

modern_browser  msie  1.0;

if ($ancient_browser) {
    sub_filter 'html5:' ''
}

Надо сразу оговориться, что это не готовое решение, а намётки: кроме «html5:» надо так же вычистить «html5\:».

2008   html5   ie   nginx   программирование

Кривой веб-клиент от Motorola

Заинтересовало изменение в новой (0.7.0) версии nginx (это довольно хороший веб-сервер, если кто-то не знает): «теперь nginx разрешает несколько строк „Host“ в заголовке запроса». Решил узнать, что за клиенты отправляют несколько заголовков «Host», оказывается, это Java-машина на некоторых «Моторолах»:

Вопрос: А в каком случае клиент может послать несколько заголовков Host?

Ответ: В случае кривого клиента. Такие, к сожалению, есть — цитата из баг-репорта:

Так вот, Java-машина на ряде аппаратов Motorola (например, K1) имеет свойство указывать в заголовке HTTP-запроса два поля Host. Причём, один из этих заголовков корректный, а второй содержит значение localhost.

Тест nginx

Тестировал сегодня nginx. Отключил все ненужные модули (кстати, если будете компилировать под Linux-2.4.x не забудьте указать «—with-poll_module», иначе не собирётся), 100 workers, use rtsig. Сервер показал сравнимые с 0W-httpd (ZeroWait httpd) результаты (13-229ms) и лучшую стабильность.

Так или иначе, 0W лидирует по скорости и обладает более пригодным для моих задач возможностями. Но и nginx очень хорош, думаю, если будет развиваться, может стать достойным конкурентом остальным решениям.

Ранее Ctrl + ↓