Saturday, February 09, 2008

Yaws — веб-сервер на Erlang

В самом начале обещал рассказать про веб-приложения на эрланге. Наверное, пора сворачивать ближе к теме.

В качестве веб-сервера для Erlang-приложений лучшим вариантом является написанный на эрланге же веб-сервер Yaws. Чем он хорош — он довольно сильно заточен под высо­копро­изво­ди­тельные приложения, и динамические страницы там удобно генерировать на эрланге.

Сначала насчет производительности:

Картинка известная, подробнее узнать, как она получена можно тут.  По горизонтали это количество параллельных запросов  к серверу (очень медленных клиентов), по вертикали — сколько кб/с при этом параллельно может отдавать сервер одному быстрому клиенту. Красненькое это yaws, синенькое и зелененькое это Apache, который после нескольких тысяч тихо умирает.

Конечно, Apache сравнивать с yaws не очень честно — все-таки апач продукт сложный и намного более многофункциональный, с кучей дополнительных модулей и настроек, и, в общем-то использовать его для отдачи статических страниц не очень принято. Однако ж картинка все-таки очень показательна, возможность держать много параллельных соединений важна в любом случае, да и с динамикой дела у yaws должны быть тоже хорошо (см. например Erlang vs PHP на Computer Language Shootout).

Пару слов об установке Yaws — с линуксом проблем, конечно, нет, на винду поставить тоже можно из-под Суgwin, но чтобы избежать лишней головной боли, обратите внимание, чтобы в пути к эрлангу и директории home не было пробелов (а последняя по умолчанию в "Documents And Settings" находится). Еще пара полезных замечаний про процесс установки есть тут.

 

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

Простейшее приложение с использованием yaws:

<head><title>Hello world using Yaws</title></head>
<body>
<erl>
out(A) ->
   case queryvar(A, "name") of
      {ok, Name} ->
        {html, "<div style=\"font-size: 12pt;\"> Hello, " ++ Name ++"</div>"};

      undefined ->
        {html, "<b> Name parameter required </b>"}
    end.
</erl>
</body>

 

Сохраняем его как hello.yaws в root директории.

hello-yaws

.yaws файл, как уже видно, это просто HTML шаблон. Каждый блок между тегами <erl> и </erl> компилируется в отдельный Erlang модуль. Каждый такой блок должен содержать функцию out/1, которой в качестве параметра передается структура, содержащая параметры запроса. Есть много вариантов как можно возвращать ответ, наиболее интересны два:

использованный выше

{html, HtmlString}

Где HtmlString — просто кусок HTML в виде строки, как в примере выше.

И чуть более удобный

{ehtml, Term}

Где Term — тот же HTML в виде терма Erlang, где тэги представляются кортежами или списками кортежей. Например, вот такой терм

{p, [],
    [
        {b, [], "Hello World"},
        {a, [{href, "http://www.example.com"}], 
           "link"}
    ]
}

преобразуется сервером в HTML-строку

<p>
  <b>Hello World</b>
  <a href="http://example.com">link</a>
</p>

Выглядит немного жутковато, но быстро привыкаешь и работать с кортежами становится намного удобнее чем со строками.

Еще Yaws, кроме того что является просто веб-сервером, предоставляет немало дополнительных инструментов, таких как автоматическая поддержка сессий, cookie, механизмов удаленного вызова процедур на основе SOAP и JSON-RPC.

Для полноценного фреймворка — аналога Ruby on Rails и прочих, API Yaws, конечно, не дотягивает (для этого есть библиотека ErlyWeb), но для небольших приложений этого должно быть вполне достаточно.

25 comments:

blog said...

Спасибо, интересно. Шустро, однако, это всё работает...

Кстати, насчет компиляции - ерланг в нативный код компилируется?

PS. Добавь в CSS в pre.erlang "overflow: auto;"

lrrr said...

Оверфлоу поправил, спасибо )

Насчет компиляции: есть компилятор в нативный код под названием HiPE, по ссылке эрланг vs php именно его используют -- но при этом по отзывам "родной" интерпретатор зачастую быстрее (см. тесты тут).

david-m said...

Ну, на фоне Апача круто выглядеть — невеликий подвиг. Вот если на график добавить современные веб-сервера типа lighttpd или nginx…

У меня вот вопрос. Erlang — функциональный язык. Но почему-то почти все примеры реальных приложений, которые мне встречались (когда надо, скажем, страницу отдать, как тут, а не просто факториал посчитать) сводились к созданию одной функции, которая дёргалась в обычном процедурном стиле. Как ф-я out в данном посте, например.

Собственно, вопрос — реально-то на практике функциональность используется? Или только мешает?

lrrr said...

Согласен, против nginx было бы намного интереснее померить. Одно могу тут добавить -- в отличие от nginx, yaws изначально задумывался как сервер для отдачи динамического контента, и думаю что должен себя неплохо показать (к сожалению, даже локалки на десяток машин под рукой нету чтобы потестировать).

Что касается функциональщины. Она в эрланге присутствует совершенно не из любви к чистой науке. Основная идеология эрланга, как языка для параллельных и распределенных приложений -- "share nothing". Нет состояния, нет mutable переменных => нечего расшаривать между процессами. А функции высшего порядка, замыкания и пр. нужны тут просто для того, чтобы удобнее было программировать без состояний.

(Насчет процедурного стиля не понял -- ну да, одна функция дергается, а как иначе-то?)

semka said...

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

FX Poster said...

Да не за что. :)

Кстати, есть оффтопный вопрос - что ты думаешь о python vs ruby - что лучше, что перспективнее и почему на ruby сейчас такой ажиотаж?

lrrr said...

Руби он ближе к смолтолку, и поэтому более тру. То есть если абстрактно, то руби мне больше нравится -- но пугает то что у них там какая-то ерунда с производительностью и с юникодом.

Короче говоря, я для себя объективных причин не нашел предпочесть одно другому, но питон как-то привычнее.

А ажиотаж обычно влияет в том плане что появляется много библиотек хороших -- но руби до питона в этом плане все равно еще далеко.

lrrr said...

Да, насчет ажиотажа еще http://www.indeed.com/jobtrends?q=python%2C+ruby&l=

FX Poster said...

Ясно. Я сам питон просто учил и смотрел на руби... как-то синтаксисом мне руби не приглянулся и... какой-то он вообще очень для меня не привычный.

Хотя возможно это лишь первое впечатление.

joymax said...

А если какие фреймворки для erlang? Судя по твоим записям, язык прекрасно масштабируется, а как у него с рутинами и MVC?

lrrr said...

Не понял что имеется ввиду под рутинами, а по поводу MVC есть Erlyweb, оно как раз в стиле рельсов/джанго. Но это я не пробовал пока.

RumataEstor said...

Yaws можно установить в windows и без cygwin.
http://groups.google.com/group/erlyweb/web/erlyweb-erlang-windows-installation

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

alekciy said...

Очень это конечно интересная штука, и запросов вроде держит много. Но чаще ведь во что все упирается? В потребляемые ресурсы. И какие они для Yaws-а может кто-то ответить?

Как пример приведу Apache 2.2.x. на FreeBSD 6.x. В дефолтном prefork-е резидентно он жрет ~7МБ, всего ~17МБ. Каких то вшивых 10 одновременных коннектов, и только один апач отламывает от ОЗУ 70МБ. Пересборка в worker-е конечно может улучшить ситуацию, но не сильно. Тот же nginx резидентно занимает 1,2МБ и не fork-ется на каждый коннект.

Поэтому если к примеру я хочу получить HTTP Streaming, т.е. не закрывать соединение и постоянно в него досылать данные, то о большом количестве online клиентов на слабом железе (96 МБ ОЗУ) можно забыть.

Поэтому и интерисуют возможности Erlang и Yaws в частности. Может ли кто-то озвучить количество потребляемых ресурсов на коннект?

lrrr said...

alekciy> Yaws то точно не форкается, и, думаю, речь будет идти о десятках килобайт на коннект. Постараюсь на днях потестить, самому интересно, да вроде и приложение подходящее было где-то под рукой.

lrrr said...

Вообще, кстати, если представить что у авторов мегаграфика было 8 гиг памяти на сервере, то на 80000 соединений, это уже не больше 100 кб на соединение выходит.

alekciy said...

С нетерпением буду ждать результатов.

Много хорошего вижу в инете по поводу Erlang-а, но удивляет (я бы даже сказал настараживает) тот факт, что вроде приложения на нем и быстрые очень и ресурсом потребляют мало... Отчего же он не получает распространение? Только в инертность сознания (ну вот привык я к С-подобному синтаксису) я не верю...

В настоящее время мне пока много не нужно. Удержать на стрименге 200 юзеров онлайн (чат + канал с данными). Но даже на связке nginx+fpm-php для текущего VDS-а (96МБ ОЗУ) это не реализумо. fpm не форкается, дочерние процессы запускаются в статическом количестве, каждый резидентно весит 1,4МБ. А ведь еще СУБД, Shared Memory, система...

lrrr said...

Инертность основная не в сознании, а в том что не хватает библиотек, специалистов и готовых решений по установке и интеграции приложений. Тот же Apache (ну или lighttpd etc.), он хоть и толстый, но для большинства случаев вполне подходит, стабилен, и в случае чего можно найти как допилить его напильником.

Я вот, скажем, по требованию заказчика щас на питоне тоже делаю какие-то вещи, которые чуть ли не в разы быстрее мог бы сделать на ерланге (в плане времени на разработку). И я заказчика понимаю, потому что команду питонистов он себе легко нашел, и найдет еще, если надо будет, а с эрлангом этим разбираться после меня будет некому :)

alekciy said...

Да, но есть же проекты "для себя". Где ты и исполнитель и заказчик. Очего же там это не юзают...

P.S. Сижу ставлю Erlang (а после и Yaws накатаю). Не понял, с какого перепоя он тянет за собой Java (diablo-caffe-freebsd6-i386-1.6.0_07-b02.tar.bz2 и tzupdater-1_3_11-2008i.zip). В замещательстве.
Нашел, что можно поставить erlang-lite, тогда Java не нужна. Ставлю...

alekciy said...

Может кто в курсе, но я в Yaws не вижу директив подобных User-у Apache.

Неужели он запросы отрабатывает из под рута?!

lrrr said...

Да, вроде там ничего такого нет. Я его пускал из-под обычного юзера на 8000 порту, и iptables'ом перенаправлял 80<->8000

alekciy said...

Мда... это конечно создатели зря не предусмотрели. iptables конечно выход, но явно метод костыля )

Oleg said...

alekciy, метод костыля тоже метод =)

Anonymous said...

Спасибо за новост

tumikosha said...

Ну,во первых, не так уж прекрасен yaws как его малюЮт.
Он НЕСТАБИЛЕН!
Во вторых, какой смысл иметь 10k коннекшенов если байтики по ним еле идут? Все равно будешь кластерить и придешь к пресловутым 1k connections/instance.
а во вторых, хотелось бы увидеть таки больше 10k конекшенов.

Насчет мегатеста, у меня его повторить не получилось. У меня yaws падал на 7k.
Так что миф о суперстабильности erlang'a - всего лишь миф.

lrrr said...

@tumikosha
Смысл в том чтоб проверить как он себя ведет в случае "дофига медленных клиентов", это вполне жизненная ситуация.

Понятное дело, что при быстрых клиентах все быстро упрется собственно в ширину канала, или IO, или бизнес-логику и получится гораздо меньше на инстанс, естественно.