Олег Бунин

Дневник подготовки конференций ;-)

Previous Entry Share Next Entry
Метро 2033 / Архитектура - 1
HighLoad
oleg_bunin
Перейдем к обсуждению серьезных вещей. На картинке первое предложение непосредственно по архитектуре игре, логический уровень.



Пройдем всю схему вместе с запросом от пользователя, от flash-клиента. Вся статика (картинки, фоны, описания) отдается, естественно, с бинарных кластеров (их непосредственное устройство пока не обсуждаем). Динамика проходит через nginx'ы и попадает на фронтенды игры (абсолютно взаимозаменяемые).

Фронтенд проводит авторизацию в менеджере сессий, который, скорее всего, построен на memcached. Менеджер сессий превращает SID (куку) в GUID, который представляет собой глобальный идентификатор пользователя в системе. Дальнейшее развитие событий зависит от класса действия (на картинке - action), которых не так уж и много.

Допустим, мы выполняем самое распространенное действие - ping(), это подтверждение существования и запрос изменений с предыдущего момента. Как происходит сбор данных? Здесь самый интересный момент. Введем понятие контроллер - контроллер это некоторый активный объект, объект, у которого каждые пять секунд вызывается метод $object->run(). Метод совершает какие-то действия (сохранение на диск, переход на новых уровень, какие-то расчеты и так далее). Контроллер персонажа котролирует все воплощения этого персонажа, все прокси-объекты этого персонажа.

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

Вот как происходит информация о распротранении смерти персонажа в бою:


Например, начинаем бой, персонаж сообщает контроллеру сегмента, что он хочет начать в нем бой. Контроллер сегмента содержит в себе прокси-объекты всех персонажей, которые находятся в данный момент в нем, на этом куске карты. Контроллер сергмента создает контроллер инциндента и передает всем причастным контроллерам персонажей информацию о том, что начался бой. Контроллер персонажа на основе собственных свойств принимает решение, должен ли он провалиться в бой, если да, то вновь созданный контроллер инциндента получает указания создать у себя множество прокси-объектов персонажей. Теперь уже контроллер инциндента начинает свои расчеты.

Если кто-то умирает, то в соответствии с вышеозначенным рисунком прокси-объект персонажа передает информацию в свой контроллер, который затем распространяет эту информацию по всем прокси-объектам. И сохраняет эти данные на диск.

PS: Технология, с помощью которой поддерживается целостность информации - CORBA (подробнее у Сергея Федорова - zmij_r).

PSS: Голубенькие квадратики сделаны в PhotoShop программистом Newmedia Stars - Павлом Зеленовым (_pashok_). Напоминаем, что в группе открыты вакансии дизайнеров ;)

  • 1
Смотря как вы собираетесь строить распределение вычислений... очередью, раздатчиком или конвеером.

Для игры я бы предложил либо конвеер, либо очередь.

А корба - да, болото, поддерживаю... Слишком много врапперов + большие потери производительности.

Если бы писали на java, то можно было бы взять уже готовый J2EE сервер с поддержкой кластеризации (например JBoss). Там схема кластеризации реализованна невидимо для програмиста, связующими технологиями являются JCache (общий кэш объектов), JMX - раздача уведомлений и Hibernate + HQL как persistance для задач, с которыми не справляется JCache.

Но мы пишем не на Java, а на Perl/C/C++
Какие у нас варианты?

ну джаву никогда не поздно внедрить в качестве одного из бизнес-лэеров)
не вижу, например, никаких проблем, если вопросами кластеризации и нормированием нагрузки займётся тот же jboss, а бизнес-процесс будет вызывать процедуру, написанную на C или перле. Главное - это чтобы вызываемый бизнес-код работал линейно, в одной нитке, так-как тредами будет рулить тот же jboss.

К примеру, зачастую персистенс-функции у нас выполняют сторедпроцедуры в БД, написанные на С++ или на .Net, а не мы ими рулим через Hibernate. Так получается просто быстрее.

(Deleted comment)
:) ни в коем случае. Это мой личный взгляд на приложения. Ну и, естественно, этот взгляд через призму моего опыта написания таких приожений. А пишу я на джаве. Вот и предлагаю решения, которые близки и понятны мне)

Жуйбосс к играм? Это мне напоминает поднятие jboss ради jboss. Или поднятие jboss для использования его как сервлет-контейнера.

Если по делу, то практика показывает, что в таких случаях гораздо целесообразнее -- выделять серверную часть в отдельное AS-независимое Java-приложение, а кластеризацию реализовать собственноручно, используя в качестве фасада tomcat с mod_jk load-balancer'ом, если это нужно.

Но, как говорится, я не претендую на последнюю инстанцию :)

ну JBoss приходит в голову только первою мыслею) Если подумать, то целиком он нафиг не нужен:
http://ymik.livejournal.com/76563.html#cutid1

и тут обсуждение: http://oleg-bunin.livejournal.com/34042.html?thread=453370#t453370

например ice (начать можно отсюда http://www.zeroc.com/iceVsCorba.html)

Сам не использовал, но знакомый C++ девелопер попробовавший и корбу и айс, выбрал последнее.

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

Честно говоря, я не могу на своем опыте посоветовать вам что-то лучше для таких задач, но лично мне кажется, что REST-инфраструктура вполне может быть адекватной заменой CORBE. Это будет дешевле по трафику (потому что CORBA неоправданно «говорлива» по сети), будет более вменяемо по кешированию (кешировать HTTP запросы гораздо проще, чем непонятные бинарные) и т.д. и т.п. Почему я не могу вам этого посоветовать? Потому что я не знаю, как с этим обстоит дело в не-Rails мире, который вам актуален.



Почитал про REST.

Если я правильно понял, это набор принципов, под которые попадает в частности http-протокол, так?

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

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

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

Инфраструктура внутри проекта такова, что не подходят ни очередь, ни конвеер.
Нужна поддержка именно распределенной обработки объектов (а не распределенно-параллельной), то есть один объект на одном сервере в рамках одной задачи, второй объект на втором сервере в рамках второй задачи и т.д. (так называемая модель MPMD)
Здесь можно сделать либо на MPI (или функциональных аналогах, PVM например), но это будет более низкий уровень по сравнению с корбой. Либо собственно на корбе.
Другие варианты, лично я не рассматриваю, так как не верю в их должную производительность. Хотя конечно могу чего-то не знать.

А я не верю в производительность корбы, поскольку не знаю ни об одном настоящем реал-тайм приложении с большой нагрузкой, реализованном на корбе.

Все проекты, о которых я знаю, используют другие технологии удалённых объектов. Максимум для чего применялась корба в знакомых мне приложениях - это для обеспечения RMI между клиентом и сервером, но ни в коем случае не для обеспечения кластеризации.

Вот тут ( http://oleg-bunin.livejournal.com/34042.html?thread=460794#t460794 ) предлагают использовать SOA в качестве механизма связи между класерами. Это куда более приемлимое решение, чем монструозная и нестабильная корба.

Если вы не знаете о проектах, реализованных на корбе - это не значит, что их нет. Lokheed Martin использует корбу в аппаратуре навигации и контроля авиационного оборудования. Это RT и FT приложения. Таких примеров до хрена как минимум.
Монструозная - да, она большая. Но есть еще спецификации minimal CORBA и embedded CORBA. Никто не принуждает использовать все фичи и навороты. Футпринт ORB от omni около 800Кб. Есть приложения CORBA, непринужденно крутящиеся на наладонниках и в мобильниках. Оконные менеджеры под юникс (KDE, Gnome2) полностью построены на технологии CORBA.
Нестабильная? зависит от реализации.
Для сведения. Sun Soft использует CORBA в качестве транспорта для общения между Enterprise JavaBeans. (ссылка

так-так-так! Не стоит приписывать мне то, что я не говорил!)
Я говорил, что не знаю ни одного RT проекта на CORBA, про ORB я такое не говорил и не мог сказать. Собственно, тот же JMX и вэбсервисы являются частью стандартов ORB.

Теперь про minimal и embded CORBA. Кто сказал, что они подходят для попытки кластеризовать систему? Максимум, чего можно от минимальной корбы добиться - передавать (не очень часто) от сервера к серверу объекты, которые переходят из одной зоны локаций в другую. Но никак не использовать в качестве кластеризующего транспорта. Чисто производительности серверов не хватит.

По ссылке - "CORBA technology is an integral part of the Java 2 platform". Java2 поддерживает корбу в своём API, мало того, значительная часть пакета RMI пользуется классами из Корбы, но при этом не используют корбу как стандарт при передаче объектов.

Теперь про EJB. Так как EJB - это набор технологий (всё же технологией у меня язык не повернётся назвать этот зоопарк идей) прямо конкурирующая тому же CORBA, то как и CORBA EJB включает в себя всё что надо и не надо, ту же корбу например. (В свою очередь Корба последняя, кажись, включает EJB). Вот такой рекурсивный include получается)

Давайте внесем ясность в дискуссию :)
ORB является частью спецификаций OMA Guide и CORBA.
Для обеспечения отказоустойчивости применяется FT CORBA, спецификации CORBA глава 23.

Ок. Так какие конкретно задачи будет решать корба в вашем приложении? По диаграмме непонятно, какое отношение имеет отказоустойчивость ко всему этому делу.



Кстт, про отношение корбы к JMX - http://jcp.org/en/jsr/detail?id=70
про отношение корбы к джава: http://java.sun.com/j2se/1.5.0/docs/api/overview-summary.html (пэкаджи javax.rmi.* org.omg.*), ну а относительно JMS - корба может выступать транспортом его


CORBA будет транспортом для вызова методов удаленных объектов (Remote Method Invocation). Плюс будет использоваться набор CORBAServices и FaultTalerant CORBA (на диаграмме не показано, ибо на данном уровне анализа это излишне).

Какая имплементация (какой вендор) корбы будет использована?
Есть ли оценки требуемой производительности WL хотя бы по CMI (count method invocation)? Есть ли тесты производительности сетевых ф-ий корбы?

Вообще, как производительность оценивать думаете? Есть ли профилер? Или писать свой test suite?

имплементации на данный момент рассматриваем 2: omniORB и TAO ORB. Обе open-source, во втором есть реализация большинства CORBAServices, для первого их гораздо меньше, на уровне minimal.
оценка производительности по CMI будет сделана в ближайшее время. либо тупой бенчмаркинг на уровне кода, либо разничными профайлерами для С++.

Ок. Интересно будет увидеть правила синтетического теста и результаты бенчмарка.

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

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

Для масштабирования надо разделять данные, чтобы избавиться от синхронизации, а они шарят одни и те же данные между всеми сервисами.

Видимо, опыт Незнакомки их ничему не научил.

1. повежливей.
2. данные будут разделяться и проксироваться.

во-во, пошли знакомые слова. Сейчас я вам подолью дегтя.

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

Я с вами поделюсь не синтетическими тестами, а реальными. Причем на небольших нагрузках. Когда пошел разговор насчет обратных нотификаций с сервера к клиентом, пошли жуткие дедлоки в TAO. Когда пошел разговор об коннекте omniORB-ового клиента к TAO серверу, пошли ковыряния в бинарных пакетах, сырцах и прочем дерьме. Жуткие ощущения.

TAO в части бинарного маршалинга не соблюдает стандарт (в части выравниваний), поэтому есть расхождение между тем, что он генерит и тем, что должно быть.

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

А вроде сам ICE Zeroc не решает все эти многочисленные проблемы? насколько можно судить по API (в том числе нотификатор Storm, Box и т.п.), примерах реализации - уровень абстракции там высокий, инкапсулирует детали ORB - всё происходит на другом уровне. А писать можно и на С++, и на Java и .NET. Вроде как Skype его использовал вместе с Postgres - т.е. в системе реального времени.
Другое дело, что самая эффективная фича ICE стоит денег.
Если ближе к теме этой беседы, то скорей всего надо смотреть в сторону ICE как движка. Надо явно выделять быстро изменяющиеся данные на какой-нибудь memcached и отдельным рабочим поток андейтить периодически данные в какой-нибудь быструю БД типа MySQL (как я понимаю, основной траффик - апдейты) - игра вещь не такая гарантированная, поэтому отказ узла в кэшем не так критичен. MySQL образовать через партишинг данных (сделать мультимастера через разреженную инкрементаци ключа) и пробрасывать соединения через haproxy. на фронтенд можно поставить даже томкаты, опять же масштабировать апп-уровень через haproxy. бизнес-уровень (сервисный для фронтенд) реализовать на ICE и масштабировать (в основном CPU и RAM) её средстами (чаще использовать асинхронные коммуникации). этот уровень стыкует фронтенд и БД (часть через memcached, часть напрямую в БД). Кстати, всякие Хибернейте и т.п. лучше вообще не использовать.
Все элементы лучше сделать на Java (её тоже на уровне JVM, да и томкат, можно масштабировать через Терракота).

  • 1
?

Log in