Pull to refresh

Comments 82

А теперь примеры, конфиги и т.д. (:
Продолжение, с примерами и конфигами, конечно следует, но, видимо, уже на следующей неделе. К сожалению, у меня остаётся не так много времени, чтобы писать тексты, но я постараюсь. :)
а можете осветить тему взаимодействия nginx + apache на примере хостинг-сервера? в интернете очень мало полезных статей на данную тематику, а для юнных администраторов тема очень актуальна :)
Да +1 к запросу, почитал бы обязательно
Заинтересованным также настоятельно рекомендую прочесть статьи Владимира Русинова «Веб-сервер nginx» в 41-м и 42-м выпусках «OpenSource».
Интересная статья, хотя в ней есть пара небольших неточностей. Собственно, вот что-то в этом духе я и имел в виду, когда говорил, что про общую настройку nginx уже написано довольно много, и я не хочу повторяться.
В начале статьи есть концептуальная ошибка где про «работает так быстро». Способен обслуживать большое число соединений и при этом шевелиться — да, но обычно raw-производительность именно по отдаче данных и выюзыванию канала в плешку у обычных серверов бывает выше, чем у асинхронных.

И еще я, как раработчик, посвятивший достаточно много времени (пара лет) асинхронщине, поспорил бы с некоторыми пунктами.

По ходу работы над поставленными задачами я, естественно, изучал чужой опыт и устройство nginx и алгоритм его работы знаю на уровне исходных кодов. Не знаю, как в самых свежих версиях (какое-то время назад я перестал следить за изменениями в них), но могу с уверенностью сказать что следующие два утвержения про «количество переключений между контекстами выполнения минимизируется» и «практически нет необходимости в синхронизации процессов или потоков» — неверны. И, если у вас достаточно нагруженные сайты, то вы можете заметить, как nginx грузит процессор — а ведь эту нагрузку можно уменьшить убрав то лишнее, чего в нем по ошибочному, с моей нескромной точки зрения, мнению не существует :)

Если быть более точным, то они верны только в том случае, когда nginx работает одним процессом, а когда дело доходит до SMP, то в нем используется и локинг и есть переключения контекста, которых Игорь, в принципе, может избежать, но пока он почему-то этим не занимался.

Да, он выравнивает размеры некоторых структур данных под пайплайн процессора, чтобы обойти проблема с обнулением кэша процессора, но это не главное.

nginx устроен так, что в нем сбор и предварительная обработка событий осуществляются одним потоком через одну очередь событийного механизма (kqueue и т.п.), когда же события преобработаны — они скадываются в общую очередь, которую, конкурируя между собой (в неопределенном порядке) с использованием локинга растаскивают рабочие процессы.

Таким образом установка соединения, прием/передача разных порций данных и последующий дисконнект с лингером для одного tcp-соединения (сессии) по очереди могут обрабатываться разными рабочими процессами. Таким образом данные из контекста одной серссии кидаются между разными cpu, что, в принципе, можно понять с какой-точки зрения. И пускай trylock не приводит к блокировке потока, зато он есть cpu.

Теперь, чтобы не быть совсем голословным о том, как это можно обойти.

Например, можно сделать так, чтобы сервер использовал не единственную системную очередь (kqueue), а отдельную для каждого процесса/потока (и соответственно cpu). При этом пусть слушающий сокет и будет только в одной из них, зато можно новые установленные соединения распределять между потоками не добавляя запросов на нотификацию событий о них в одну общую очередь, а наоборот — раскидывая их по собственным kqueue каждого потока.

Далее уже обработкой всех последующих операций по каждому конкретному соединению будет заниматься только один и тот же процесс/поток потому что нотификации о событиях будут приходить только в его приватную очередь. Естественно, при этом, поскольку только один поток работает с данными соединения, локинг уже не нужен.

Таким образом мы получаем немного другую внутреннюю кухню, где локинга (или другого оверхеда в зависимости от метода распределения задач между потоками) есть немного только на этапе распределения новых соединений между рабочими потоками, но где мы избегаем излишнего локинга при всех последующих операциях в рамках каждого установленного tcp-соединения. Взяв в руки калькулятор любой желающий сможет посчитать — сколько инструкций cpu можно сэкономить не используя локинг на каждом событии, а только на одном на сессию.

Хотя, конечно, и с таким решение можно поспорить и в нем найти недостатки :)

С другой стороны Игоря Сысоева тоже можно понять — ведь 1) «работает не трогай» и 2) нагрузить сервер так, чтобы разница между подобными подходами была сильно заметной сегодня практически невозможно из-за узкого места — производительности и пропускной способности современного сетевого оборудования — через сеть просто нельзя создать такой нагрузки, чтобы правильных софт основанный на асинхронной модели смогу утилизировать CPU на 100% ;-)

А так nginx — очень и очень хороший сервер.
>В начале статьи есть концептуальная ошибка где про «работает так быстро». Способен обслуживать большое число соединений и при этом шевелиться — да, но обычно raw-производительность именно по отдаче данных и выюзыванию канала в плешку у обычных серверов бывает выше, чем у асинхронных.

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

Это так, хотя бы потому, что переключение между единицами планирования в операционной системе не может знать всех подробностей о каждом из потоков, которые будут выполняться. Она может опираться только на статистику, если этот поток уже выполнялся ранее. А вот state-машина прекрасно осведомлена о состоянии каждого из обслуживаемых подключений, и может, основываясь на этой информации, более оптимально выбирать следующее обслуживаемое подключение. Собственно говоря, по той же причине, user-space треды менее надёжны, но зато в разы более эффективны, чем треды, которые обслуживаются ОС. Вам не надо переключать тяжёлые контексты вне основной единицы планирования, сбрасывать кеш процессора, и прочая, и прочая.

> «количество переключений между контекстами выполнения минимизируется» и «практически нет необходимости в синхронизации процессов или потоков» — неверны. И, если у вас достаточно нагруженные сайты, то вы можете заметить, как nginx грузит процессор

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

> Если быть более точным, то они верны только в том случае, когда nginx работает одним процессом, а когда дело доходит до SMP, то в нем используется и локинг и есть переключения контекста, которых Игорь, в принципе, может избежать, но пока он почему-то этим не занимался.

Ну, вероятно, потому, что у него есть основная работа, и её немало. :) А совсем без переключений контекста, даже в случае SMP-системы не обойтись. Мы ведь живём не в идеальном мире… :)

> Например, можно сделать так, чтобы сервер использовал не единственную системную очередь (kqueue), а отдельную для каждого процесса/потока (и соответственно cpu). При этом пусть слушающий сокет и будет только в одной из них, зато можно новые установленные соединения распределять между потоками не добавляя запросов на нотификацию событий о них в одну общую очередь, а наоборот — раскидывая их по собственным kqueue каждого потока.

Мне эта идея кажется неплохой, но её реализация, вероятно, потребует немало времени, поскольку придётся переписывать всё, включая API модулей. Да и, если подумать, блокировки пока не являются «бутылочным горлышком», поскольку всё-равно, большая часть времени сервера уходит на ожидание сетевого ввода-вывода,
UFO just landed and posted this here
Как именно и где?
UFO just landed and posted this here
Не совсем понял, о чем речь можно более подробно суть изложить?
UFO just landed and posted this here
Как вы это реализуете практически? можно пожалуйста поподробнее
UFO just landed and posted this here
Про методику все правильно поняли. В сервере, что мы писали для себя это реализовано уже относительно давно (более года), хотя и метод передачи инфы дочерним процессам незначительно отличается — здесь есть варианты.

Только я не подразумевал, что нужны будут потоки — запутался в терминологии =)

Если кратко, то сейчас в nginx все события касающиеся полной жизни tcp-соединения валятся в общую kqueue (epoll и т.п. в зависимости от системы). Из нее мастер процесс эти события вытягивает, преобрабатывает и складывает во внутреннюю общую очередь, из которой уже дочерние процессы используя локинг тянут себе задания и обрабатывают эти события.

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

Предложение в том, чтобы сразу после акцепта и получения нового fd — этот фд не добавлять даже в общую kqueue, а передавать их дочерним процессам и использовать индивидуальную kqueue для каждого процесса — тогда необходимость локинга для работы с остальными событиями отпадает — т.к. они всегда будут привязаны к одному и тому же процессу.
UFO just landed and posted this here
Локинг он ведь и без потоков есть (мастер процесс, несколько рабочих процессов и разделяемая память) :) Собственно на низком уровне это инструкции xchg или cmpxchg (ну и lock по необходимости) в зависимости от реализации — для того чтобы их использовать не обязательно нужно быть потоком, а для процессов ведь примитивы также необходимы.
UFO just landed and posted this here
А что мешает написать свой патч реализующий этот механизм и выслать Игорю для включения в ветку, если действительно в нем есть практический смысл, а не только теоретический. Я был бы вам очень благодарен.
для тех кто не знает что такое нгинкс или слышал про него мельком ) все понятно и по полочкам ). Сам както пытался одному верстальщику, который вычитал про него из книжки «Разгони свой сайт», обьяснить чем он так хорош )
Спасибо. Я старался уместить минимально необходимый объём инфы в короткую статью. Понятно, что для опытных разработчиков, бОльшая часть этой статьи представляет перечисление известных фактов. :)
А я уже привык, когда спрашивают о таких вещах, говорить про НЛО и Божью помощь.
не могу отказать в помощи нуждающимся )))
да и сам не люблю когда просиш человека о чем то ) он посылает курить маны хоть и знает ответ, я трачу свое время вынашивая план «жестокой мести» ) ну и его карма падает в моих глазах )
приятный пост, не то что истеричный треп об ифон и мвидео
>И даже средства для выполнения быстрых асинхронных системных вызовов появились в Linux, FreeBSD и Windows относительно недавно (я не имею в виду select и poll).
А какие средства вы имеете в виду? ну к примеру в Linux.
Я имел в виду epoll, kevent и kqueue для Linux и FreeBSD. Конечно же, «недавно» только относительно всей истории развития Unix-систем. Для сравнения — select, который существует уже с незапамятных времён. :)
>Я имел в виду epoll
Это всё же не средство для выполнения быстрых асинхронных системных вызовов, а «I/O event notification facility».
Асинхронные системные вызовы — это надо смотреть в сторону syslets/threadlets/итд.
ну и libaio работает через сигналы ;)
И я бы epoll назвал не быстрым, а масштабирующимся.

>У этого подхода есть и свои недостатки, главными из которых можно назвать необходимость очень тщательного подхода к программированию сервера, и отсутствие возможности использовать блокирующиеся операции ввода-вывода.
А можно как-нибудь сделать асинхронный вызов записи в лог из своего собственного модуля, а потом дождаться пока не произойдёт запись и продолжить работу в текущем соединении/клиенте? Если нет, то я бы назвал основным недостатком — отсутствие гибкости, так как приходиться жить в конечном автомате nginx'а и никуда не сворачивать :)
Хороший вопрос. :) Хотя, честно говоря, я не совсем понимаю, зачем может понадобиться контекст текущего соединения после асинхронной записи в лог. Если вы собираетесь записывать какие-то критичные данные, от результата записи которых зависит дальнейшее выполнение запроса, полагаю, вам всё-равно не обойтись без блокировки (хотя я уточню ещё), а если это действительно, «просто лог», то можно сделать неблокирующуюся запись в лог, и продолжить работу с соединением.

Должен признаться, что в написании модулей для nginx, я не вполне компетентен, так что лучше я, при случае, спрошу Игоря, возможно он сможет что-то более конкретное сказать. Но, полагаю, ему тоже понадобится более подробное описание ситуации.
Запись в лог — это самая примитивная задача, которой желательно выполняться синхронно.
В nginx'е насколько понимаю(а я плохо понимаю) такую задачу придётся выносить в отдельный процесс и использовать «upstream handler».
В случае с лёгкими userspace тредами всё решается просто и удобно(ну как в Plan9), но получаем большее потребление памяти для стека. Так что проблема с блокирующими вызовами — это проблема nginx'а, а не подхода в котором используется aio и треды ядра == кол-ву логических процессоров.
Я уточнил у Игоря Сысоева. Он сказал примерно следующее. Если вы попытаетесь сделать внутри вашего модуля асинхронный запрос на IO (например, через AIO write), то потом (если тот запрос, который вызвал этот write ещё цел), у вас всё-таки есть возможность добраться обратно до объекта запроса. То есть, то что вы хотите возможно, но я до сих пор не вполне понимаю, зачем это может понадобиться.
>но я до сих пор не вполне понимаю, зачем это может понадобиться.
Мне самому это не надо, так как всё это делаю в других процессах(чтобы не убить хттп сервер своими ошибками), но если уж перл внутри nginx'а крутится, то работа c IO вполне возможна и желательно чтобы она не мешала остальным клиентам.
На текущий момент работа с IO во встроенном перле (не скажу что невозможна) сложна. К тому же, это заметно скажется на производительности сервера. Однако, возможно, через некоторое время будет сделана более тесная интеграция, с возможностью использовать в интерпретаторе Перла «IO-движок» nginx-а. Есть даже предположения по поводу того, как именно она будет работать, но это дело не самого близкого будущего.
В любом случае спасибо за комментарии :) Это подтолкнуло меня к тому чтобы ещё раз взглянуть на модули nginx'а, и нашёл то чего мне так нехватало(из-за незнаний) в nginx'е, уже сел писать модуль для связки с erlang node'ами.
Танненбаум «Современные операционные системы» — эх помню заказал эту книжку в библиотеке, хорошо что сумка была с собою большая;)
2-е издание, 2007 год, 1040 стр., формат 17x23 см (70х100/16), Твердый переплет, ISBN 978-5-318-00299-1
неслабо.
Зато это действительно полное и качественное описание архитектуры современных операционных систем. Прочтение этой книжки даёт программисту плюс десять к сообразительности и повышает вероятность спасброска от багов при написании многопоточных приложений до 80%. :)
UFO just landed and posted this here
Давайте заодно и о недостатках поговорим, или точнее чего кому в nginx не хватает, вот например нам не хватает поддержки e-tag для корректного кеширования файлов на клиенте, может кто знает как можно решить данную задачу?
UFO just landed and posted this here
мне нужно для ветки 0.7.61
UFO just landed and posted this here
нет он для более новой ветки, и не факт что будет работать с веткой 0.7
UFO just landed and posted this here
нет, проблема в том, что ветка 0.8 недостаточно стабильна, и ее пока не рекомендует к использованию на реальных высоконагруженных проектах Игорь Сысоев
думаете патч подойдет для 7й ветки?
UFO just landed and posted this here
Честно говоря, мне кажется более простым, управлять кешированием при помощи заголовков, задающих expiration-time. Генерация и проверка ETag-ов — обычно требует какой-то нагрузки на сервер, а лучший HTTP запрос, с точки зрения высокой нагрузки, это запрос, которого не было. :)
Частично с вами согласен, но запрос ETag и ответ на него это все равно легче чем отдача картинки например в 30 килобайт, так как можно было обработать этот запрос и взять картинку это из локального кеша браузера.
спасибо, теория всегда хорошо
а вы nginx используете в единственном виде?
если отталкиваться от теории, на сколько я понимаю наиболее производительным решением будет связка nginx+apache, ведь nginx медленнее апача в статике (html) если я не ошибаюсь!?
UFO just landed and posted this here
если узнаете как решать данную проблему сообщите
Nginx гораздо быстрее апача в статике. :) А вот динамику под ним действительно генерить сложно. Поэтому, nginx обычно используется в качестве фронт-энда, который полностью выполняет запросы к статике, а также проксирует (и иногда кеширует) запросы к скриптам. В качестве бэкенда может выступать Apache + mod_perl (как в моём случае), или, например, FastCGI + что-угодно. :)

Отдавать статику апачем, довольно невыгодно по многим причинам. Например, в самом худшем случае, на запрос к однопиксельной гиф-картинке может произойти форк или создание треда, со всеми волнующими последствиями, типа старта mod_perl и его startup-хэндлеров. Поскольку nginx в процессе работы не форкается, такая проблема в нём исключена. :)
да, путаю, согласен

ну вот и интересовала бы как раз связка nginx+apache+ещё что-нить
А в чем проблема с динамикой?
Искренне не понимаю зачем все ставят сзади нгинкса апач.
Может это распространенное заблуждение?
Ну потому что скрипты, генерящие динамику должны где-то выполняться. Это может быть Апач с mod_perl/mod_php/mod_что-то-ещё, или FastCGI, или даже ваш собственный сервер на C/C++. Апач — просто одно из самых популярных, простых и надёжных решений.
Просто субъективно, nginx + phpfastcgi, работает быстрее nginx+ apach+modphp, потребляя меньше памяти примерно в 2 раза. Правда сервер не самый высоконагруженный.
Выше Вы озвучили некие «сложности с генерацией динамики» у нгинкса.
В чём именно они заключаются?
В том, что «произвольную динамику» в самом nginx можно генерить только встроенным перлом, который может существенно замедлить работу сервера. За другими видами динамики надо обращаться куда-то «наружу», например, хотя бы и к FastCGI. По-поводу выбора между Apache и FastCGI, могу только предположить, что это не апач плохой, а, скорее, mod_php. :) Хотя, вообще, дело вкуса. :)
угу, на выделенных веб-серверах (в количестве несколько сотен уже ) ) используем тоже nginx с php и cgi — все без проблем работает, намного эффективнее апача.
единственное неудобство для массового хостинга — нет поддержки .htaccess-а, все вручную в конфиг прописывать ))
а есть цифры факты замеры? которые подтверждают — «намного эффективнее апача»?
цифр нет, только опыт )
Серверы на Intel Atom, под апачем загибаться начинают на 10Мбит трафика и выше, под nginx все летает с LA под 0.1 при 20-30Мбит нагрузке
nginx+апач? на атоме?
нет, чистый nginx, без апача. с php и cgi скриптами.
апач вообще не вижу смысла ставить с nginx-ом.
Кстати еще есть такая штука как Litespeed, правда платный.
Понимает .htaccess-ы и во многом совместим с апачем (по mod_rewrite, mod_security и много еще по чему).
Используем на сервера под шаред-хостинг с CPanel, тоже в принципе неплохой вариант.
А чем cgi пускаете?
враппер на перле, найденный в интернетах и немного нами доработанный )
также встречал вариант на С.
UFO just landed and posted this here
А можно пруфлинки пожалуйста
а есть цифры факты замеры?
вы ошибаетесь. :) у людей обычно Nginx выдает самостоятельно статику и ергает через fastcgi приложения, если нужна динамика. fastcgi можно заменить апачем, только смысл? )
Я еще не встречал спаунер процессов fastcgi, хотя бы близко приближающийся к апачевому по гибкости и эффективности.
можно подробнее что такое «спаунер процессов fastcgi»?
Nginx не выполняет сам скрипты, он только проксирует запросы к бекенду по какому-нибудь протоколу, типа HTTP или FastCGI. Задача спаунера — запуск (spawn) параллельных процессов, обрабатывающих эти запросы.

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

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

В апаче для этого есть штука под названием worker. Принцип ее работы — тема отдельной книги. Можете погуглить что-то типа apache mpm prefork.

У lighttpd, есть свой собственный spawn-fcgi и многие используют его, даже без самого lighttpd.
UFO just landed and posted this here
смысл в простоте конфигурации апача для динамики
UFO just landed and posted this here
а добавить сюда настройку fastcgi+php+модули+ssl плюс отсутствие .htaccess
UFO just landed and posted this here
Ну собственно, никто и не спорит что под разные задачи нужны разные решения
UFO just landed and posted this here
почитайте наверное камменты выше и вы поймёте о чём идёт речь
UFO just landed and posted this here
Sign up to leave a comment.

Articles