Вопрос по архитектуре приложений

308 views
Skip to first unread message

Дмитрий Макеев

unread,
Nov 14, 2013, 9:13:20 AM11/14/13
to erlang-...@googlegroups.com
Добрый день!

Не так давно начала изучать Erlang и возник вопрос по архитектуре приложений (application).

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

Так вот вопрос: получается, что на одном узле должны работать несколько приложений одновременно (и это будет правильная архитектура и я сам должен все разбить логически на отдельные приложения, как http сервер, TCP сервер, логика и прочее)? Но ведь по хорошему тогда должен быть супервизор, который будет следить за приложениями (вдруг ковбой упадет отдельно), но есть ли такое?

И почему не оформить все в одно приложение, где главный супервизор будет следить за супервизором (а значит за "приложением") ковбоя, TCP сервера и так далее?

Заранее спасибо!

Danil A. Zagoskin

unread,
Nov 14, 2013, 9:35:06 AM11/14/13
to erlang-...@googlegroups.com
У каждого приложения свой супервизор, который следит за всем тем, что происходит в этом приложении.

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

То есть, приложение-зависимость следует рассматривать как import в питоне или require в руби. Перед стартом вашего приложения запускаются все зависимости, после этого каждая зависимость предоставляет свой API.

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

Например:
Ваше приложение super_chat зависит от приложения super_http_server .
Приложение super_http_server зависит от приложения super_tcp_acceptor.

Что должно происходить на запуске:
1. Запускается super_tcp_acceptor, который создает пустой супервизор.
2. Запускается super_http_server, который создает пустой супервизор.
3. Запускается super_chat
3.1 Создается инстанс сервера super_http_server, который попадает в супервизор этого приложения
3.2 Создается инстанс акцептора super_tcp_acceptor, который попадает в супервизор этого приложения

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

В этой схеме если что-то и может упасть, то это всего лишь инстансы в зависимых приложениях. Сами приложения продолжат работать, а главное приложение или получит уведомление о сломавшемся инстансе http-сервера, или умрет вместе с ним.




14 ноября 2013 г., 18:13 пользователь Дмитрий Макеев <dire...@gmail.com> написал:

--
Вы получили это сообщение, поскольку подписаны на группу Erlang по-русски.
 
Чтобы отказаться от подписки на эту группу и перестать получать из нее сообщения, отправьте электронное письмо на адрес erlang-russia...@googlegroups.com.
Чтобы добавлять сообщения в эту группу, отправьте письмо по адресу erlang-...@googlegroups.com.
Настройки подписки и доставки писем: https://groups.google.com/groups/opt_out.

Дмитрий Макеев

unread,
Nov 15, 2013, 1:54:39 AM11/15/13
to erlang-...@googlegroups.com, da...@st-olen.ru
Спасибо за развернутый ответ!

Но все равно не до конца понял. (А все дело в том, что я не писал на питоне/руби, не могу до конца понять смысла инстанса).

Допустим у меня приложение super_chat и мне нужен в зависимости только super_http. Это значит, что сначала будет запущен super_http (ну обычный старт, супервизор, таблицы и прочее), а потом будет запущено мое приложение и я получу интерфейс к super_http? И в каком виде будет этот интерфейс? я по-прежнему могу слать сообщения процессам super_http? Т.е. мы с ним в одном "пространстве имен" работаем?

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

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

четверг, 14 ноября 2013 г., 18:35:06 UTC+4 пользователь Danil A. Zagoskin написал:

Sergey Prokhorov

unread,
Nov 15, 2013, 7:49:28 AM11/15/13
to erlang-...@googlegroups.com, da...@st-olen.ru


пятница, 15 ноября 2013 г., 10:54:39 UTC+4 пользователь Дмитрий Макеев написал:
Спасибо за развернутый ответ!

Но все равно не до конца понял. (А все дело в том, что я не писал на питоне/руби, не могу до конца понять смысла инстанса).

Допустим у меня приложение super_chat и мне нужен в зависимости только super_http. Это значит, что сначала будет запущен super_http (ну обычный старт, супервизор, таблицы и прочее), а потом будет запущено мое приложение и я получу интерфейс к super_http? И в каком виде будет этот интерфейс? я по-прежнему могу слать сообщения процессам super_http? Т.е. мы с ним в одном "пространстве имен" работаем?
Кто к кому получит интерфейс это уже детали.
На примере ковбоя - после старта ковбоя `application:start(cowboy)` тебе нужно вызывать `cowboy:start_http` - как раз обращение к API ковбоя.
"Пространство имён" да, общее - любой процесс может слать сообщения любому другому (в т.ч. самому себе). Но хорошей практикой является не рассылка сообщений напрямую, а использование интерфейсных функций, в которых уже описано будет это посылка сообщение или же просто чтение из глобальной ETS таблицы или БД, обращение к астралу и т.п.
 
Почитав help по ковбою, получается так: я для разных запросов указываю разные функции обработки, которые являются частями моего приложения super_chat, это значит что уже ковбой получил интерфейс к моему приложению, т.е. о моем существовании он тоже должен знать?
Да, должен знать. Но не о твоём приложении, а о callback-модулях этого приложения. 

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

Вообще советую запустить какое-нибудь erlang приложение и затем вызвать appmon:start() или observer:start() - это запустит гуёвое окошко, в котором более-менее наглядно можно это всё вживую понаблюдать.

Boris Timokhin

unread,
Nov 15, 2013, 8:02:21 AM11/15/13
to erlang-...@googlegroups.com
В релизе, если приложение не помечено, как temporary, то считается, что оно permanent и после падения оно будет перезапускаться. Если же оно будет падать вновь, то остановится вся нода. Если нода запущена с heart, то перезапустится и всё начнётся заново.


15 ноября 2013 г., 16:49 пользователь Sergey Prokhorov <seri...@gmail.com> написал:

Un Lexx

unread,
Nov 16, 2013, 12:26:29 AM11/16/13
to erlang-...@googlegroups.com
>Т.е. мы с ним в одном "пространстве имен" работаем?

в свое время я для себя определил ноду erlang:
   как единый процесс с нитями или потоками(одно адресное пространство много точек выполнения)
   с возможностью в "реалтайме" управлять vtable функций.
И для того чтобы программист не запутался в названиях функций и адресах входа в vtable (строго говоря не только для этого но и например для организации кода) введена система модулей - которая фактически позволяет экспортировать только часть функций в ту самую глобальную vtable скрывая вспомогательные функции внутри модуля.

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

 


15 ноября 2013 г., 19:02 пользователь Boris Timokhin <mathe...@gmail.com> написал:

Дмитрий Макеев

unread,
Nov 19, 2013, 1:49:09 PM11/19/13
to erlang-...@googlegroups.com
Всем спасибо за ответы! Ситуация немного прояснилась.

Запустил примеры, которые шли с Ковбоем, правда наверно неправильно (руками запускал ranch, cowboy и уже потом само приложение, хотя наверно все это должно было быть автоматизировано).

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

И вопрос немного не по теме, но близок. Как быть с "весом" потоков, т.е. если рассмотреть потоки на уровне ОС, то при равных приоритетах они получали пропорциональное время, а как быть тут?
Если у меня будет 1000 потоков (условно), которые работают с TCP соединениями и 1 поток, отправляющий пуши, значит ли это, что отправка пушей, может не поспевать за другими действиями? (отправка пушей тут тоже условно, здесь может быть запись в БД, отправка email, ну что угодно).

Max Lapshin

unread,
Nov 19, 2013, 2:29:38 PM11/19/13
to erlang-...@googlegroups.com
Я выделяю отдельные части приложения в отдельные приложения по мере органического роста.

Сначала становится неудобно гонять тесты всего приложения ради маленького куска, потом становится ясно, что этим куском пользуется кто-то ещё, потом становится ясно, что этот же кусок будет использоваться в других проектах.

Так код переползает сначала из apps/myapp в apps/mylibrary, а если нужно, то и в deps/mylibrary

Иногда это происходит в обратном направлении.

Danil A. Zagoskin

unread,
Nov 19, 2013, 2:58:57 PM11/19/13
to erlang-...@googlegroups.com
> Если у меня будет 1000 потоков (условно), которые работают с TCP соединениями и 1 поток, отправляющий пуши, значит ли это, что отправка пушей, может не поспевать за другими действиями?

Если при обработке данных будет много тяжелой логики (то есть, работа с TCP упрется в процессор) то да, пуши могут затупить.
Это можно лечить несколькими способами:
1. Вынести жадную до процессора часть обработки в управляемый пул воркеров
2. Поиграть с приоритетами (после прочтения всех предупреждений в манах)
3. Придумать что-то еще
Но если работа с TCP упирается в скорость TCP (как обычно и бывает), то не стоит волноваться – от пакета до пакета процессы не займут время в шедулере. У меня бывает по много тысяч вялотекущих TCP+SSL, очередь на исполнение нулевая (проблемы в синтетических тестах у людей в интернетах начинаются примерно с миллиона соединений). Другими словами, если не стоит задача быстро обсчитывать более, чем гигабит данных в секунду, можно почти не думать о том, чтобы все все успели сделать.

С другой стороны, слегка мониторить длину очередей сообщений и очередь процессов на исполнение не помешает.

19 ноября 2013 г., 23:29 пользователь Max Lapshin <max.l...@gmail.com> написал:

--

Дмитрий Макеев

unread,
Nov 21, 2013, 2:26:55 AM11/21/13
to erlang-...@googlegroups.com, da...@st-olen.ru
Спасибо.

Ну с TCP это был пример, понятно что TCP соединения не слишком требовательны к процессору.

Как я понимаю - пул воркеров самое нормально решение, т.к. играть с приоритетами кажется довольно грязной операцией.
 
Пул воркеров по сути имеет смысл (кроме долгих расчетов) в случае синхронных запросов (запись в БД/посылка данных по TCP, как я понимаю, они синхронные)?


вторник, 19 ноября 2013 г., 23:58:57 UTC+4 пользователь Danil A. Zagoskin написал:
Reply all
Reply to author
Forward
0 new messages