Логин:   Пароль:




Новости
Рассылки
Форум
Поиск


Java
- Апплеты
- Вопрос-ответ
- Классы
- Примеры
- Руководства
- Статьи
- IDE
- Словарь терминов
- Скачать

Мобильная Java
- Игры
- Примеры
- Статьи
- WAP, WML и пр.

JavaScript
- Вопрос-ответ
- Примеры
- Статьи

Веб-мастеринг
- HTML
- CSS
- SSI

Разминка для ума
Проекты
Книги
Ссылки
Программы
Юмор :)




Rambler's Top100

Статьи - разминка для умаВизуальные XML-редакторы

Опыт программирования

По мотивам этого обсуждения разработки игры "Metro2033":

Итак, дано: есть коллектив, который разрабатывает на C++, Perl и Flash. Задача написать систему реального времени с определённой фиксированной бизнес-логикой и максимально масштабируюмую "вширь" (т.е. при нехватке мощностей нужно всего лишь добавить ещё один вычислительный центр/сервер).

Перво-наперво, имея опыт в написании таких приложениях, я бы предложил людям не морочится и применить многократно опробованные, проверенные решения. Таких решений всего 3 - CORBA, Ice, JMX. Следующая вещь, которую я бы предложил - это отказаться от решений, с которыми чересчур сложно интегрировать программа на С++ и перле. Кроме того стоит отказаться от слишком сложных, громоздких систем, требующих тонкой настройки много сервисного кода. Тут отпадает стопудово Корба и остаются JMX и Ice.

Теперь посмотрим, какие механизмы уже есть под эти технологии. Тут обнаруживаем, что на Ice написано много всяких распределённых объектов, но они - сцуко - проприетарные, то бишь надо покупать и не протестировать их никак. А вот под JMX есть такой продукт, как JBoss - Application Server, который уже умеет кластеризоваться, т.е. уже имеет масштабиремость вширь. И JBoss, сволочь, бесплатный.

Но тут же натыкаемся на один огромный трабл: конфигурирование JBoss требует навыков и знаний, а в команде таких людей нет. Кроме того, документации по нему относительно мало, а та, которая есть она платная, причём книжки в России не купить - как минимум в Амазоне заказывать надо. Что делать? Корячится с объектами Корбы? Пытаться положиться на удачу и использовать относительно удобный Ice? Но тут приходит великолепная мысль - нам же не нужен весь JBoss! От него бы нам поиметь только механизм кластеризации или механизм хранения распределённых объектов. Эта замечательная мысль утыкается в одну из частей JBoss, вполне себе даже прикольно документированную и простую в настройке под названием JCache.

Итак, смотрим:

"JBoss Cache is a replicated and transactional cache. It is replicated since multiple JBoss Cache instances can be distributed (either within the same JVM or across several JVMs whether they reside on the same machine or on different machines on a network) and data is replicated across the whole group. It is transactional because a user can configure a JTA compliant transaction manager and make the cache operation transactional. Note that the cache can also be run without any replication; this is the local mode."

Т.е. если на русский язык - то программка умеет хранить объекты, умеет их реплицировать, поддерживает их версионность и транзакции. А кроме того доступ к объектам происходит через MBean, тобишь посредством JMX. А что такое JMX? Яндексируем и находим:

"Технология JMX (Java Management eXtensions) – это сравнительно новый стандарт компании Sun Microsystems, который позволяет Java-разработчикам интегрировать свои приложения с существующими решениями сетевого управления. JMX определяет стандарт для написания JMX-объектов, так называемых MBean’ов. MBean’ы «живут» внутри своего контейнера. Таким образом, любой JMX-клиент (в качестве которого может выступать, например, удаленное или локальное приложение) имеет возможность вызывать методы и получать доступ к атрибутам этим MBean’ов с помощью контейнера, в котором они содержатся. Кроме того, приложение также может получать специальные уведомления от MBean’ов, если это приложение зарегистрирует соответствующие “слушающие” MBean’ы."

Т.е., если по-русски - JMX - это такой RMI (Remote Method Invocation - удалённый вызов методов), который абсолютно невидимо для программиста позволяет пересылать объекты и вызывать уалённые методы. Т.к. сам его использую могу ответственно заявить - действительно API очень прост и удобен, никаих заморочек.

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

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

Ок. Едем дальше. Чего нам нехватает ещё для масштабируемой системы? Ага! Мы забыли о двух важных вещах:
* Первое - бизнеслогика-то у нас должна разрабатываться на перле и на С++, а объекты в джейкэше хранятся только джавовские. Т.е. вопрос интеграции.
* А второе - это то, что система работает в реальном времени, соответственно для системы постоянно выставляются новые задачи (tasks), которые необходимо решить, причём желательно при этом как-то балансировать нагрузку на разные кластеры и сделать так, чтобы два кластера одновременно не решали одну и ту же задачу.

Давайте тут определимся: для решения этих двух задач требуется, чтобы вся бизнес-логика, написанная на перле или С++ была линейной. Т.е. никаких multi-threading. Я выставляю задачу, нахожу процедуру, которая будет её решать, передаю в неё параметры задачи, жду завершения и получаю результат. На этих условиях хорошим решением для синхрониации процессов будет применение очередей. Т.к. JCache и JMX мы уже используем, нисколько не сомневаясь берём ещё одну жаба-примочку под названием JMS. Что такое JMS? И опять нам поможет Яндекс:

"Java Message Service (JMS) — стандарт промежуточного ПО для рассылки сообщений, позволяющий приложениям, выполненным на платформе J2EE, создавать, посылать, получать и читать сообщения. Коммуникация между компонентами, использующими JMS, асинхронна (процедура не дожидается ответа на своё сообщение) и независима от исполнения компонентов.

JMS поддерживает две модели обмена сообщения: «от пункта к пункту» и «издатель-подписчик»."


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

А теперь - завершающий штрих! Я беру свои N+1 модули системы, и говорю им, чтобы они подписались на письма этого почтового ящика - очереди. Причём подписка хитрая - если этот модуль обрабатывает только сообщения пользователей, то я подписываюсь на письма с меткой "сообщение пользователей", если этот вид модуль обрабатывает ходы пользователя - то искать он будет письма со своей меткой. И как только модуль системы подписался на определённый вид писем и в ящик положили письмо нужного вида - тут же модуль получит это письмо. А что делать, если на один вид писем подписалось, допустим, три модуля? Тогда первое письмо достанется первому слушателю, второе второму, третье - третьему, четвёртое - снова первому и так далее. Таким образом в каждый модуль будут поступать только разные письма и никогда не случится ситуация, что одно и то же задание одновременно выполняют два разных модуля. А как только модуль отработал, он спокойно может взять то же письмо, добавить к нему объект с результатом работы и положить в тот же самый наш "пчтовый ящик", но уже с другой меткой, например "шаг пользователя сделан", после чего новое выставленное задание поймает другой модуль и проделает с ним уже свою операцию. А может и положить результат работы в JCache - тут уж смотря какая задача.

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

В качестве JMS сервера можно взять апачевское решение ActiveMQ.

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

И вот, приехали: вся наша система связана с помощью двух технологий - JCache, как хранилище объектов, и JMX в качестве синхронизатора - распределителя нагрузки. Пора думать об интеграции с бизнес-логикой, написаной на другом языке. Всё, что до этого мы сделали требует минимального кода на Java - всё уже готово, нужно только написать рассыльщик писем, придумать, как будут выглядеть объекты-таски (задания), написать их (строчек 20 кода) и написать сам рассылатель-получатель этих писем (ещё строк 50).

Путей интеграции существует ровно два:
* первый из них - это системный вызов. Т.е. мы просто отдаём команду на запуск, например, sh скрипта как в консоли с передачей к нему строки параметров. Это самый простой путь интеграции, но при этом мы имеем одно существенное ограничение - вызванная таким образом процедура ничего достойного нам вернуть не может. Кроме того она не может воспользоваться в режиме реального времени объектами, сохранёнными в JCache - мы можем передать в качестве параметров лишь статические значения. Да и записать в JCache она тоже ничего не сможет. Но полностью отвергать этот путь мы не будем - всегда есть какие-то виды работ, которые не требуют ответа.
* второй путь - это вызов нативных (native) методов из джавы. Как это выглядит - создаётся специальный объект-прокси, имеющий определённые методы, помеченные, как native. Пишется библиотека на С/C++ (внеё включаются библиотеки интеграции джавы), после чего в джаве мы просто имеем новые методы, с которыми работаем точно так же, как и с любыми другими. И сишная аппликуха тоже может дёргать такие же методы джавы. Штука эта абсолютно стандартная, ещё спервой версии языка (а сейчас уже 6 вышла), называется JNI (Java Native Interface). Недостатком является достаточно большое количество прокси-кода как со стороны джавы, так и со стороны С++. Дело в том, что все передаваемые объекты (если они чуть-чуть сложнее, чем Integer) должны быть определённым образом описаны. Прочитать подробнее об этом можно здесь: JNI: взаимодействие Java с другими языками. В общем-то ничего сложного, но на каждый тип объекта, который мы собираемся хранить/брать в JCache или передавать по JMS нужно будет написать по своему прокси. Вот здесь-то как раз и будет больше всего интеграционного кода. Ещё одним недостатком явлется то, что этот вид интеграции отработан только для С/C++/Phyton, но не для Перла, но, думаю, этот вопрос решаем, наверняка уже есть модули для перла по интеграции с джавой.

Да, с интеграций придётся повозиться, но! Сколько задач было решено простым применением уже отлаженных технологий.

Я намеренно не коснулся тем ввода-вывода информации в систему (видимо тоже через какие-то модули с перловым фасадом), не коснулся persistance системы, потому что JCache решает только оперативное хранение данных и было бы глупо перекладывать на него хранение того же лога чата, видимо в системе должна быть ещё БД, доступ к которой будет производится уже из бизнес-логики написанной на перле или С++.

И в заключение - тоже немаловажное. Какие потенциальные проблемы у данной архитектуры приложения? В системе синхронизации есть узкое место: это JMS (сервер очередей). Если он выйдет из строя, то вся система развалится. Если нагрузка на него будет черезмерна, то вся масштабируемость системы тут не поможет. Выходом можежет служить создание разных очередей для разных видов работ, разнесение очередей по нескольким независимым JMS серверам, а их, в свою очередь, делать на разных тачках. Вторая проблема - довольно сильные нагрузки на локальную сетевую инфраструктуру. При достаточно большом количестве тачек проблема железа (а именно роутинга) может встать в полный рост. Сообщения будут копиться в очередях просто из-за неповоротливости роутеров, файрволов и т.д.. Тут уже надо смотреть на железо. Проблема резервирования. Те же очереди - если выключить сервер, то всё развалится к чёртовой бабушке. По этому нужно подумать над горячим переключением серверов очередей. Пока в голову ничего не лезет больше, дополняйте)

Автор: ymik



Дирк Льюис, Петер Мюллер
"Java 2"
Подробнее>>
Заказать>>


Эд Барнет
"Eclipse IDE. Карманный справочник"
Подробнее>>
Заказать>>

Узнай о чем ты на самом деле сейчас думаешь тут.


Опрос
Считаете ли вы целесообразным сделать аналог упражнений по Hibernate на базе вопросов www.sql-ex.ru?
Да, полный аналог упражнений
Да, но с реализацией основных конструкций объектной модели
Нет, Hibernate не актуален, использую др. технологии
Нет



Apache Struts 2.0.11
Apache MyFaces Trinidad Core 1.2.3.
Sun переводит мобильные устройства с Java ME на Java SE
Хакерская атака!