Как стать автором
Обновить

Комментарии 271

Так родился сервер

Где исходники? Где примеры? Где GitHub? Где это всё?

Зачем эта статья?
Ответ на ваши вопросы даже не под хабракатом.
Исходников, очевидно, нет — проект коммерческий и с огромным уровнем конкуренции.
Расскажите пожалуйста, в чем доход, и почему такой уровень конкуренции? Если такие проекты, как вы описали в статье, настолько рентабельны, то я (и не только после вашей статьи) сейчас как зохаваю весь рынок…
Что уж там, может вам сразу мою квартиру отдать? На счёт конкуренции достаточно погуглить по рунету Minecraft и увидеть, какое количество серверов существует.
Я понимаю, что их много, но на чем же тут зарабатывать? Рекламой? Насколько я знаю внутри игры нечего продавать… Или вход платный?
Я не буду отвечать на этот вопрос.
Да ладно, это что, секрет? Вы не рассказываете своим игрокам, за что они платят деньги? :) Может я интересуюсь, что я могу у вас купить?
В таком случае, вы прошли бы на сайт любого сервера и посмотрели. Да и мой сервер найти не так сложно даже простым поиском по нику в гугле.
Ок, доеду до дому, обязательно погуглю :)
greencubes.org/?cat=shop#t — оно?

    При смерти инвентарь не опустошается
    При входе на сервер нет надписи «Попробуйте через 3 секунды»
    Вторая точка /home (Как пользоваться вторым домом?)
    Нет задержки между телепортациями домой
    Нет отключения по тайм-ауту
    (Временно) Увеличенный радиус видимости на 3 чанка от стандартного
обычно продают разные випки на игровых серверах.
Да там карьер-монтаж!
Удаление кубов(пластов породы, мусора): 4 рубля за каждую 1000 кубов. Учитываются только кубы, отличные от воздуха.
За +50% можно дать все ресурсы из очищаемой зоны в GreenBox. В GreenBox помещаются производные от кубов, получаемые при их выкапывании, например: булыжник из камня.
Перенос объектов: 8 рублей за каждую 1000 кубов.
При переносе сбиваются защиты сундуков и прочего, регионы, конечно же, остаются на старом месте. Содержимое сундуков остается в сундуках. Поворот не возможен.
Засыпание полостей не ценным кубом (земля, булыжник, камень): 5 рублей за 2048 кубов. 
Заполнение ценным кубом: 3 рубля за каждые 2048 кубов + цены кубов из магазина.
Осушение воды: 5 рублей за каждую 100 кубов воды
Заливание водой: 9 рублей за 128 кубов воды.
Заливание лавой: 26 рублей за 128 кубов лавы.
Такая вещь есть на почти каждом Bukkit сервере, но не все продают её функции. А сама вещь называется WorldEdit'ом
А почему сразу нельзя было сказать? Не секретная информация же, и за рекламу никто не посчитает, если спросили.
Вход бесплатный. Но есть же премиум-услуги и предметы/блоки, которые трудновато получить в игре, но легко за донат. Данная схема в последнее время стала популярной во множестве многопользовательских игр.
Стандартная схема микроплатежей. Не думал что она применима к Minecraft…
Практика показывает, что схема вполне применима. Чтобы удостовериться в этом, достаточно погуглить рейтинги серверов Minecraft и посетить несколько сайтов, входящих в «Toп-5», «Toп-10», «Toп-20». У некоторых ссылка на донат видна невооруженным глазом, у других функционал доната появляется только в личном профиле. Но практически везде донат есть. Ибо довольно накладно содержать сервера Minecraft на голом энтузиазме, на своём домашнем компьютере, надеясь на онлайн хотя бы в 30 человек. Ибо не каждый домашний компьютер выдержит то, что описано в данной обсуждаемой статье.
НЛО прилетело и опубликовало эту надпись здесь
Некоторые сервера даже админку продают. При чем, как ни странно, даже за рубежом, я раньше думала, что это чисто русский уровень адекватности. Важен баланс же.
Ну просто вы в каждой бочке затычка, а даже прочитать два первых абзаца не можете, прежде чем вставлять свои комментарии.
Есть такой эмулятор WoW — MaNGOS, и его форк TrinityCore (С++). Когда я начал свой OpenSource проект JMaNGOS на Java, некоторые личности на русскоязычном форуме комьюнити TrinityCore начали утверждать, что Java для таких целей ну никак не годится, и в пример приводили сервер Minecraft.
Я не был знаком с Minecraft сервером, но теперь все стало на свои места %)
Я вас уверяю, Java одна из лучших платформ для разработки серверов, и это подтверждают множество крупнейших IT-компаний мира, которые делают огромные Enterprise проекты на Java.

Java не лучшая платформа для создания клиентских графический приложений, т.к. большинство библиотек для 3D и физики, созданных игровой индустрией, на неё не портированы.
Я то это знаю, вы еще раз прочтите мой коммент %)
Я — Java евангелист, если что.
Проблема в том, что нужно хоть немного уметь писать на Java. А то наберут хардкорных C-программистов (которые даже от C++ нос воротят всю жизнь) и заставят их писать код. А потом «у нас Garbage Collector тормозит» или ещё какая ерунда.

В последнем таком проекте, который я видел, чуваки написали свой кэш — клали в HashMap объекты на 5-60 секунд, а потом клали туда новые на их место. Размер YoungGen маленький, survival ratio тоже. Такой ужас начался… Как будто специально писали чтобы «убить GC».
Кэш в яве уже давно не нужен. Ещё, кажется, с 1.5 отпала необходимость в подобного рода решениях, потому что быстроживущие объекты создаются на стеке… Короче да, надо знать что ты делаешь, и язык становится отличным.
Быстроживущие объекты создаются на стеке только с 1.6 или 1.7! И все равно ключевое слово struct не помешало, есть места где подтормаживает.
Не могли бы пояснить, что вы имеете ввиду (я не смог нагуглить)? У нас стек не порвется, если мы создадим там огромный объект, пусть и быстроживущий?
1. Гуглите Escape analysis.
2, Не во всех версиях он включен. В 1.6 надо было включать, в 1.7, вроде бы, включен по-дефолту.
3. В описанном выше случае «чуваки написали свой кэш — клали в HashMap объекты», стек вряд ли поможет, т.к. кеш обычно используется в нескольких потоках.
Верно говоришь… А потом еще скажут переписать всё на С или на Эрланг :)
Да я не против. Просто я последнюю неделю читал код сам-знаешь-какого-проекта. И количество реальных facepalm'ов было ого-го. Самый большой я тебе ещё расскажу. Я думаю это даже тебя удивит.
Так всё-таки, насколько реальна проблема с GC? Лаги из-за него есть? Или никто даже не мерял?
Ни разу не встречалась с проблемой зависания из-за GC, при занятой памяти в 10GB он работает пару миллисекунд, при том у меня огромное количество объектов, которые быстро умирают…
Не верьте, тем кто вас минусует, проблема с GC очень даже реальна! Известно, что чем больше памяти вы отдаете Java процессу, тем дороже становится Full GC. Причем он может доходить аж до 5 секунд и больше. Конечно, проблема несколько преувеличена, потому что существуют JDK (Azul), которые справляются даже с ТБ памяти на ура. Но таких алгоритмов пока нету в OpenJDK. Была очень хорошая статья на хабре про JVM.

Дам краткий совет: тестируйте приложение пока не достигните Full GC, например проверяйте большое количество юзеров и т.п. Вы всегда должны знать этот момент по результатам нагрузочного тестирования. Как только вы достигли этого предела (а он далеко не всегда равен OutOfMemory), думайте что вам делать с этим :)
2 варианта: 1) оптимизировать память — не всегда возможно и часто дорого 2) Запустить еще одну jdk (конечно если приложение вертикально масштабируемо) — что дешево, но требует больше памяти
Full GC не нужен. Если вы дошли до Full GC, у вас память утекла, тут уже на лицо не шататная работа сервера.
Не всегда. Если у вас много потоков и они переключаются постоянно, то общей памяти может не хватать, хотя она будет освобождаться своевременно.

Я наблюдал стабильную(!) работу системы с пиковыми нагрузками и со стабильным Full GC (каждые 15 секунд), но запросы обрабатывались и система работала, хоть и медленно.
Не всегда. Если у вас много потоков и они переключаются постоянно, то общей памяти может не хватать, хотя она будет освобождаться своевременно.
Количество потоков тут роли не играет, я могу и одним потоком засрать так, что у меня будет каждые пару секунд память ворошится под yg и скапливатся все в og.
Full GC не нужен
Full gc хоть и зло, но увы, практически не избежен. Даже если поиграться с настройками jvm, то мы можем многократно увеличить время до полной сборки (путем увеличения yg), но полностью его исключить — увы, я не верю в столь оптимистичный сценарий. Но правда это все бессмысленно потому что избавится от Minor gc в сотни раз сложнее (привет doEscapeAnalysis, который давно уже по дефолту включен), а в некоторых случах не возможно вовсе.

Если вы дошли до Full GC, у вас память утекла, тут уже на лицо не шататная работа сервера.
Когда вы станете чуточку более опытнее, к примеру поработаете с несколькими высоконагруженными серверами, которые архитектурно разные, то вы не будете делать такие громкие заявления*

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

* в не совсем высоконагруженном игровом проекте, с небольшим хипом (допустим ±2гб) и не совсем сложной разветвленной стуктурой классов full gc (если мы говорим о параллельной сборке мусора) может занимать совершенно небольшое время (я сейчас про STW), которым можно пренебречь.

Ну я поэтому и спрашиваю насчет лагов GC, что эти самые лаги как минимум квадратичны по количеству объектов (иначе не выяснить, где же мусор), а существенно улучшить алгоритм Дийкстры вроде как до сих пор не сумели. То есть грабли вылезают именно на хай-лоаде.
Насчет минусующих как-то фиолетово, я тролль сотого уровня.
Проблема GC происходит только если у вас память кончилась. Но если у вас память кончилась, GC для вас не самая большая проблема.
Если у меня кончилась память, я воткну еще памяти. Терабайт ОЗУ, если он обоснован — сегодня не проблема.

PS. И да, именно из-за GC я пишу (командую писать) серверные части строго на плюсах. Тотальный контроль над всем + столь не любимые авторшей этого топика очереди сообщений между потоками + неблокирующие структуры данных решают.
Если вы не забили память, то и о GC вам нечего волноваться. А вот поволноваться о том, что вы забыли в C++ удалить объект, а выясните вы это только через 3 недели работы сервера, когда 1TB памяти уже забьётся… вот это уже проблемка.

Очереди сообщений и неблокирующие структуры есть и Java. На счет структур, они там вообще почти все не блокирующие. А необходимость тотального контроля мнимая, но это уже срач ассемблер против высокоуровнего языка. На самом деле, компилятор и JIC гораздо умнее ваших программистов и знает как лучше делать вещи.

Кстати, на плюсах тоже реализуют сборку мусора, и не спроста.
В-общем, не буду холиварить насчет языков.
На старте моего проекта в 2006-2007 гг. пробовали и сишарп, и джаву. Обе версии стабильно держали порядка 500-1000 соединений, потом ой. Переписанная практически один-в-один прога на плюсах держала порядка 50000 соединений. На этом вопрос был закрыт.

Преимущество С++ в том, что сборку мусора можно организовать очень по-разному. И никакой компилятор/VM никогда не догадаются, какой способ самый правильный в данном конкретном случае.

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

Автоматический GC не решает всех проблем и не позволяет «кодить не думая». Меня пугает тот факт, что в гугле ответов на вопрос «java memory leaks» в 10 раз больше, чем про «C++ memory leaks».

В-общем, еще раз, не хочу спорить. Я просто хотел узнать мнение тех, кто пишет нагруженные серверные части на джаве насчет проблем с GC, может за пять лет что-то изменилось.
можно поинтересоваться, на чем была сделана сетевая часть? boost.asio, libev, ..?
libev в те годы еще из пеленок не вышел, так что пришлось писать ручками на ::select
Пока вы будете писать свою сборку мусора в мире уже будет написан десяток серверов которые по скорости и стабильности работы будут работать так же как и ваша поделка с супер адаптивной сборкой мусора.

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

На старте моего проекта в 2006-2007 гг. пробовали и сишарп, и джаву. Обе версии стабильно держали порядка 500-1000 соединений, потом ой.
Два разных проекта (архитектура, геймплей) правда на одной платформе под популярным сетевым фреймворком в яве, один на 200 уже умирает выжирая все ресурсы до которых может дотянуться, другой 25 тысяч держит и жрет скромненько процессора и нормально так памяти (25 тыщ игроков, как никак в онлайне).

И да, насчет «почти всех неблокирующих структур данных в джаве» — можно пруфлинки?
Боюсь ошибиться, уж не говорим ли мы про разные вещи. Но из блокирующих структур я знаю только BlockingQueue, все стандартные и не стандартные списки, сеты, мапы и прочее не блокируемые.
«Стандартные» структуры не threadsafe.
Под «неблокирующими структурами» я имею в виду такие, что если два/три/десять потоков полезут одновременно скажем добавлять элемент в конец структуры, ни один из них не окажется заблокирован мутексом/семафором/WaitFor*Object/Synchronize/YouNameIt.

Подобные структуры в первую очередь нужны для организации очередей сообщений между потоками. Но все (известные мне) реализации работают сильно медленнее традиционных (блокирующих) структур (зато имеют константный worst-case и исключают дедлоки).
java.util.concurrent, да. Я не очень в нём разбираюсь, но вроде там используются атомарные синхронизации и работает это всё довольно быстро. Меня же пока полностью устраивают стандартные структуры… то есть не то чтобы стандартные, я их не использую потому что стдлиб почти всегда хуже альтернатив, но не threadsafe.

Я ж не харкорный бородатый программер, я меньше двух лет пишу на яве, а это мой самый серьёзный проект)
Что вы конкретно хотите? Добавление в конец какой структуры? Если очереди, то, например, вот. Вообще, concurrency framework на java предоставляет отличный базис для имплементации подавляющего большинства задач, связанных с многопоточностью.

Кроме того, если душа лежит к message-oriented программированию, то есть несколько реализаций Actors model на джаве.
Я хочу узнать, возможна ли на современной JVM реализация многопоточного сервера, который не будет уступать по производительности по порядку коэффициента перед О() аналогичному серверу на С++, работающего по модели конечного автомата (FSM).
Пять лет назад всё утыкалось в GC с его О(n2). Как сейчас — вот это я и хочу узнать.
Сейчас есть JIT, есть разные реализации GC, некоторые из них параллельные и неблокирующие. В целом можно сказать, что джава сейчас почти не отстает от си в производительности. Можно нагуглить уйму статей на эту тему.
Правда, я не совсем понимаю, что вы имеете в виду в данном случае под конечным автоматом. Насколько я понимаю, реализация простого конечного автомата не требует GC.
Ну вы вообще представляете, что такое конечный автомат? Состояния, события и всё такое? Если нет, то вам курить учебник по формальным грамматикам.

Если да, то вот пример по теме статьи:

Юзерский клиент присылает пакет «я пошел налево».

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

Теперь нарисуйте весь автомат для всех возможных состояний пакетов.

И запустите обработчик каждого состояния в отдельном потоке. А переходы между состояниями оформите в виде очередей сообщений.

Если у какого-то потока пустая очередь, то он просто передаёт управление другим потокам (т.е. запускает #ifndef _WIN32 || _WIN64 nanosleep (1); #else sleep(1); ).
Скорее всего, потоков у вас будет сильно больше, чем процессорных ядер.
Но это плюс, потому что ОС сама разбалансирует нагрузку между вашими потоками.

Единственная проблема — та самая очередь, в которую попадают сообщения для потока. Для внутренних стадий (запрос базы, отправка ответа клиенту и т.п.) там возможна серьезная конкуренция.
Это — не конечный автомат, а конвейер. В конечных автоматах события обрабатываются только один раз.
по-моему вам стоит вместо плюсов брать эрланг.
UPD: реализация FSM, описанног выше, как раз-таки требует изощренного GC, способного эффективно работать между потоками.
Я почитал ваши комментарии выше. В современных высоконагруженных системах горизонтальная масштабируемость идет перед вертикальной. Ок, ваш сервер на C будет держать 100000 коннекшнов против 20000 на джаве. А что если у вас завтра будет 10кк? И тут уже выплывают совершенно другие узкие места, такие, как взаимодействие с БД, синхронизация и транзакции между разными нодами в кластере. А тут уже необходимо писать максимально простой и высокоуровневый код. И чем больше задач ложится на «стандартные» хорошо протестированные фреймворки, тем лучше.
Я считаю, что система, где с нагрузкой справляется один сервер, не является highload.
Если вы написали нормально откуда GC? Если вы поставили нормально памяти в чем проблема.

Приведу вам пару примеров из жизни:
— Тестирую программу 100 параллельных пользователей (запросы достаточно емкие), все работает Young GC каждые 5 секунд по 0.2- все ок. Работает часами
— 200 users — Young GC каждые 2 секунды по 0.1, работает часами.

— 1000 users — Young GC каждые 1 секунды по 0.2, Full GC каждые 15 секунд по 4 секун ды, работает часами.

Утечек памяти нету все работает стабильно :) Знайте как ведет ваша система и не допускайте Full GC и все будет линейно и предсказуемо.

P.S.: чем больше памяти вы дадите Java тем больше риск что она загнется от Full GC! И Young GC станет дороже. Так что не давайте более 8Гб и масштабируйтесь независимыми JDK.
Загуглите java.util.concurrent.
Пошла серьёзно загугливаться в эту тему, может почерпну что-нибудь очень полезное.
Кажется, я должна вам выразить свою признательность, в первом же мануале я нашла очень интересную для себя вещь, которую без условно должна попытаться использовать в сервере и вообще взять на заметку в дальнейшем.
Не за что. Советую прочесть книжку Java Concurrency in Practice (Brian Goetz & Kº). Если будут вопросы — обращайтесь.
Видела, но не нашла, где взять нормальную версию. По этому, в начале работы пришлось изобретать велосипед… в принципе, велосипед едет.
Например, тут.
В таком случае купите/скачайте Java Concurrency in Practice
Там еще много интересного!

Повтор. Добавлю, что после прочтения книги, возможно появится желание переписать все с нуля. не сопротивляйтесь =)
>>На самом деле, компилятор и JIC гораздо умнее ваших программистов и знает как лучше делать вещи.
Как интересно, можете детальнее раскрыть свою мысль?
Я бы не сказал, что умнее, но JIT компилятор всегда ставит подсказки предсказания перехода. Он ведь компилирует не только код, у него ещё есть статистика по исполнению этого кода 10000 раз в интерпретируемом режиме. Предсказание переходов — это только пример, но уже только это позволяет CPU намного реже сбрасывать конвейер. И выдавать большую производительность.

Грубо говоря, чтобы написать код на C, который будет производить такой же по производительности машинный код, надо всегда-всегда ставить эти макросы LIKELY/UNLIKELY. Как в ядре Linux.

А на ASM ещё лучше оптимизировать можно. Вот только на Java (когда знаешь что делаешь) код такого качества пишется быстро и легко. Легче, чем на Asm, по крайней мере :)
Вы очень прямолинейно восприняли мой вопрос :-) он в прочем был адресован не Вам, но так как видимо «ответа» от автора статьи я уже не получу, можем подискутировать с Вами.
Я очень часто в юности слышал фразу: компилятор большой — ему видней. Так обычно оправдывались самые темные уголки кода или просто нежелание разбираться в вопросе. Иногда это оправдано, иногда — нет.
Грубо говоря, чтобы написать код на C, который будет производить такой же по производительности машинный код, надо всегда-всегда ставить эти макросы LIKELY/UNLIKELY. Как в ядре Linux.
Я правильно Вас понял что Ява обгонит по производительности аналогичный код написанный без LIKELY/UNLIKELY на С?
C — это понятие низкоуровневое. Его код по-умолчанию самый быстрый (условно), и управлять им можно очень хорошо. В C++ с этим гораздо хуже. Но тем не менее, я утверждаю, что ДА, с теми же трудозатратами большой и сложный код на Java будет скорее всего быстрее. Бенчмарки вам тут не помогут, потому что мерить производительность огромных проектов написанных на C++ и Java нельзя, потому что, хотя бы, никто не пишет большие проекты сразу на двух языках. В простых кусках кода скорее всего выиграет C/C++, но и то не всегда, отработав некоторое время, код в JVM может перекомпилиться в более эффективный.

На самом деле, срач о производительности бессмысленен. Можно спорить лишь о трудозатратах на написание качественного кода на Java и на C++ в соотношении к средней мифической производительности. Java выиграет.
Сравнить нельзя, но скорее всего быстрее :-)
Я всегда стремился отличать Веру от Знания, чего и Вам желаю.

Дело не в вере, а в коде. Rena4ka все верно говорит. Представьте себе разработку проекта на С++. Все шло хорошо, до какого-то момента… потом заказчик захотел вместо заднего колеса велосипеда гусеницу, а вместо переднего — лыжу. Представте себе, чего будут стоить подобные изменения в С++. Код начинает обрастать костылями. В джаве же подобные изменения относительно дешевы, и можно переписать все правильно, без костылей. Вот тут нас и спасает синтаксический сахар.
Если бы в конечном итоге С++ проект был бы написан так-же, как и джавовский, он был бы быстрее. Но в реальности так он написан никогда не будет, слишком много человекочасов нужно на постоянно изменяющиеся требования. Не рентабельно. Поэтому в большом энтерпрайзе сейчас рулят джава и C#.
В С/С++ слишком просто выстрелить себе в ногу, а синтаксический сахар это лишь сахар. Профессионалы сделают все на ура и на том и на другом языке, только профи на С++ более редкое явление и стоят дорого, а не профи обходятся еще дороже, поэтому в больших системах бал и правят Ява и С# — порог вхождения низок, за тебя приберут где надо, позаботятся в меру сил, людей найти и оплатить проще.
На счет изменений — вы в это верите или знаете? Хорошая архитектура что на Яве что на С++ это хорошая архитектура, а плохая… ее сахар не спасет :-)
Вообще нет смысла сравнивать Си/Си++ и Яву это разные инструменты под разные задачи, и сравнения в скорости выполнения кода меня лишь умиляют, даже спорить нет смысла, только улыбаться, это разговор не о фактах, это разговор о вере.
Но даже с Явой или C# не стоит лениться, не стоит надеятся на всемогущий компилятор, думать надо, познавать, проверять и не циклиться на одном инструменте, часть большого проекта можно сделать на яве, часть на Си, часть на асме, но говорить что мы сейчас весь дом одним молотком построим потому что он удобен в руке и вообще я его так люблю это наивно.
Вы можете сделать GUI на яве, доступ к базам данных и прочее прочее, но ведь Вам и в дурном сне не привидится писать энкодер H.264 на яве, не будете Вы так же писать серьезный трехмерный движок на C#, не подходящие это инструменты.
Почему все меряют только скорость выполнения кода? Не забывайте, вас кормит не ваш код, а бизнес, для которого вы пишете ваш код. Поэтому, делая подобную оценку, необходимо учитывать «хотелки» этого бизнеса.
Вы что, станете со мной спорить, если я скажу, что на Java выполнить глобальный рефакторинг или даже переписать отдельный модуль системы будет в сотни раз проще, чем сделать то-же самое на С++?
Быстро работающий код на С++ получится только тогда, когда заранее известны все моменты, и все четко распланированно. Но в реалиях появляются изменения плана, сроки уменьшаются, и еще куча всего происходит. И оказывается, что переписать нет времени, но можно заткнуть костылем. Здесь костыль, там костыль… И вся система — уже костыль. Костыль на С++ не будет работать быстрее, чем нормально написанный код на Java.
Не воспринимайте на личный счет, я ничего не имею против Явы, хороший язык, делает свое дело, масса людей ни испытывают с ним сложностей и вовлечены в индустрию, с С/С++ такой фокус не прошел — за свою гибкость и скорость люди платят серьезными ошибками, а производители — высокими ЗП своим инженерам.
Но нужно помнить что и С/С++, С#, Ява лишь инструменты со своими плюсами и минусами и принимаясь за дело нужно их выбирать правильно.
Вы что, станете со мной спорить, если я скажу, что на Java выполнить глобальный рефакторинг или даже переписать отдельный модуль системы будет в сотни раз проще, чем сделать то-же самое на С++?
Спорить не буду и уж тем более обсуждать цифры «в сотни раз» :-) Я работаю в компании которая разрабатывает свою электронику для кодирования видео, хранения и прочего прочего. В разработке задействованы и ява и C# и С и С++ и ассемблер, все на нужных местах, хорошее проектирование позволяет легко рефакторить код С++ модулей и проектов, плохое проектирование превращает рефакторинг в ужас на любом языке если это дело запустить.
Предлагаю завершить эту ветку дискуссии, меньше всего я хочел поучавствовать в священной войне :-)
Хотел лишь узнать мнение людей на счет заданных мной вопросов и я его узнал.
Мы друг друга не верно понял. Статься о server-side приложении на джаве, все вышесказанное мной я аттачил именно к такого рода приложениям. Боже упаси писать декодеры или драйверы на джаве %)
Фраза «драйверы на яве» звучит как «реалтайм сервер на PHP» =)
Похуже) Реалтайм на ПХП попробовать можно, но ничего не выйдет. А драйвер на джаве… насколько я знаю, невозможно)
Вообще, реализуемо. Вспомнить, Singularity от MS — драйвера там были вполне себе managed. Правда, для этого придутся втащить в ядро JVM, но это уже так, мелочи. =)
А, еще нагуглил JNode. Welcome писать дрова на Яве уже сейчас. =)
рилтайм на php — dune2d.com :)
Это не реалтайм в классификации «пакетная обработка/интерактивная обработка/реалтайм»
Я бы сказал, что некоторый код на Java на некоторых архитектурах обгонит аналогичный код на C без LIKELY/UNLIKELY на той же архитектуре. Чтобы это произошло, нужно достаточно много потоков, выполняющих разный код — чтобы кэша кода в CPU не хватало на всё. А ещё нужно чтобы на этом коде не очень хорошо срабатывала встроенная в CPU система предсказания переходов.

Полагаться на компилятор оправдано, когда знаешь как он работает. Ну то есть все же спокойно пишут MSECONDS_IN_HOUR = 1000 * 60 * 60; зная, что любой компилятор посчитает константу во время компиляции. Так же и с другими оптимизациями. На них можно полагаться, если видел их код.
В джаве можно использовать sun.misc.Unsafe для выделения памяти вне кучи. Как раз для тех, кто «знает, что он делает».
В джаве можно объявить byte[] heap, выделить туда столько гигабайт, сколько нужно сразу, а дальше все точно так же, как в C.
И то и другое совершенная бессмыслица на Java, применимая только в узких вещах и JNI.
Не стоит судить так категорично. Поищите java off heap storage
Все больше и больше новых для себя вещей открываю в данном обсуждении. Спасибо, для расширения кругозора полезно.
ehcache.org/documentation/bigmemory/index
это про бессмыслецу
BigMemory's in-process, off-heap cache is not subject to Java garbage collection, is 100x faster than DiskStore, and allows you to create very large caches. In fact, the size of the off-heap cache is limited only by address space and the amount of RAM on your hardware. In performance tests, we’ve achieved fast, predictable response times with terabyte caches on a single machine.
Да-да, и поверх этого написать свой C++ STL на Java.
Очень привлекательно.
При чем тут алгоритм Дейкстры? Выявить мусор можно и за линейное время.
В одной онлайн-игре с сервером на Java оные лаги раньше были обычным делом под конец суточного цикла, разработчики грешили именно на GC.
Да и сейчас время от времени случается regression, когда в очередном релизе накосячат чего-нибудь.
Буду признателен если поясните в чем плюс явы для высоконагруженного игрового сервера?
Не сточки зрения евангелизма, а с точки зрения здравого смысла. Почему был выбран этот инструмент?
Потому что это чертовски удобный язык. Ну а вообще выбор был прост — оригинал был написан на Java и я почерпнула очень много опыта из работы с первоисточником, а так же очень удобно писать свой код и видеть как работает то, что я пытаюсь сделать.
Спасибо, упустил из виду что Minecraft был разработан на яве.
А что можете сказать относительно питона — как у него с «большинство библиотек для 3D и физики, созданных игровой индустрией»?
Судя по минусам — питон совсем не предназначен для написания 3D-игр? Или что этим хотели сказать? Я просто никогда с ним не работал, но не на пхп же, который я знаю, писать игры :)

Если питон вообще не подходит, то какой язык для быстрого вхождения в процесс можно использовать? С/С++ я вряд ли смогу быстро освоить, чтобы внятно писать задания программистам и проверять работу.
Спасибо!

Теперь хоть есть от чего отталкиваться и куда смотреть! На пайгейм раньше наталкивался, а вот панды не видел :)
эмулятор WoW
Почему проходят годы, но эмули вовки по-прежнему далеки от оффа?
Потому что иначе Blizzard было нечего кушать.
Думаете они саботируют процесс разработки эмулей?
Они делают обновления.
… которые нравятся не всем. Многие и сейчас с удовольствием поиграли бы на предыдущих дополнениях, особенно если админы их постоянно улучшали.
НЛО прилетело и опубликовало эту надпись здесь
TrinityCore отнюдь не один человек разрабатывает… и там ситуация сильно отличается в лучшую сторону от того-же проекта L2J, и тем не менее эмули не дотягивают по _содержанию_ мира, а не по прямоте и производительности кода, потому что опенсорсерам очень трудно конкурировать с армией людей, занимающихся наполнением такого богатого мира как WoW.
Так что качество ПО и качество содержимого мира — это разные вещи
Я вынужден с вами не согласиться. Контент комуниздится прямо у близов. А вто реализация сервера MaNGOS/TrinityCore мягко говоря оставляет желать лучшего. Абсолютно не масштабируемая архитектура, ни вертикально ни горизонтально, плюс куча пробелов в реализации, поскольку оригинального сервера ни у кого нету.
Алгоритмы работы скриптов, боссов, данжей, формул… всего этого нет в открытом доступе.
> Алгоритмы работы скриптов, боссов, данжей, формул…
Это и есть контент.
Подмена понятий.
synchrone говорил о армии людей, которые что то там выдумывают. Но тут нечего выдумывать, потому что сама идея — украсть контент у близов.
Остается только проблема архитектуры и отсутствие формул и алгоритмов.
Контент в данном случае — модели, текстуры.
А «алгоритмы и скрипты» по сути просто эмулируются «наугад».
Целая куча причин. Основная в том, что реверс-инжиниринг. Кроме снифов, кэша, и данных на вовхеде ничего нет.
Простите что вклиниваюсь. Тоже принимал некоторое участие в проекте MaNGOS, ещё когда был БК. Даже предложил ряд патчей, которые впоследствии приняли в ядро (обёртки для вещей, почта с фирменными подложками, формула опыта открытия территорий, имена и статы петов лока).

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

Так что получается что в этой гонке у близзов все козыри на руках. И им вовсе не обязательно закрывать неугодные проекты.
А что такое сниффы?
Результаты анализа трафика между клиентом и официальным сервером. Разбор пакетов и т.д.
Не знаете, почему у той же Линейдж 2 с фришками ситуация лучше?
Извините, только WoW эмуляции касался, много лет назад.
Потому что периодически сливаются официальные сервера со всеми скриптами, конфигами, AI и прочим. Потому что есть официальная база знаний со многими раскрытыми параметрами.
Cливаются официально или воруются?
Тайна, покрытая мраком. Официально ничего не выкладывается, но как минимум 4 разные версии за все время появилось в паблике (практически по утечке в год). Сначала сервер есть у ограниченного числа лиц (они получают огромную прибыль за счет уникальности сервера на рынке фришардов), потом появляется еще у кого-то, потом начинаются продажи, потом цена падает с десятков тысяч долларов до сотен долларов, а в конце концов файлы становятся общедоступными. В промежутках между утечками идет разработка экстендеров.
А на чем зарабатывают владельцы серверов? Донат с рекламой?
Только донат. Реклама была бы каплей в море.
Как сказал Hint, офф сервер ла2 утекал в сеть. К тому же эмуль написан на джаве, что упрощает процесс фиксинга, рефакторинга и прочего в разы, когда становится доступна очередная порция информации…
У мангоса и тринити ситуация печальная, команде приходится вклиниватся в рамки, которые они сами себе создали и громоздить костыли, о глобальном рефакторинге уже никто и не задумывается — слишком сложно будет…
Дополню Ваше сообщение. Так же проблема рандомных опкодов, начиная с Каты.
Писал немного об этом тут.
Нотч. Но тому есть веские причины, да и свет тут очень простой: от 0 до 15 на блок.
А можно чуть поподробнее про причины для человека, не игравшего в minecraft?
В темноте спавнятся мобы, на свету нет. Это первое, что на ум приходит.
От уровня освещения зависит скорость роста пшеницы, к примеру.
Ещё деревьев, травы, цветов, выцветание травы. А ещё таяние снега и льда…
Освещение обсчитывается в пределах чанка?

И вообще — не подскажете толковое описание игровой механики?
Всё просто, монстры (мобы) появляются в зависимости от уровня освещения. Например, для большинства враждебных мобов должно быть очень темно. Поэтому требуется просчёт освещения на сервере.
А от освещенности чего это зависит? Блока, множества блоков etc.
Блока.
Как вы решаете проблему синхронизации, если у вас отдельные потоки для мобов и для стрел?
С помощью synchronized при доступе к одним и тем же данным.
Почитайте о транзакциях. Начните с JMS, посмотрите в сторону Apache Camel, activeMQ, Hadoop
Я посмотрю, вы тоже самый умный. Я обо всё этом прекрасно знаю, но меня устраивает то, что я использую.
В таком случае, вы языком ошиблись :)
Я ведь просто посоветовал, да и другим может полезно будет. Зачем же так грубо.
Это ваше мнение, и я рекомендую держать его при себе. Это мой выбор не использовать сообщения, а синхронизировать данные вручную, что бы вы не утверждали, а это гораздо эффективнее, но если у вас не хватает скилла, чтобы самостоятельно обеспечивать синхронизацию данных без дедлоков, долгого ожидания и прочего, то это ваша личная проблема.

Можете весь свой рейтинг потратить на слив моей кармы, мне пофиг.
Я принципиально воздерживаюсь от оценок, карм, и так далее, простите :)
С какой стати я должен держать свое мнение при себе? Да будет вам известно, комментарии придуманы, что бы выражать свое мнение.
А вопрос в скорости разработки и удобстве рефакторинга. Синтаксический сахар, есть такое понятие.
Выше вы же сами упоминали о корпорациях, которые гребут деньги на этих технологиях. Вы сами себе противоречите. Вы используете один язык с приемами, характерными для других языков.
Вам ниже ответили. Такой метод «синхронизации» потоков не применим на реал-тайм приложениях. Если буду делать что-нибудь, где это более к месту, обязательно не буду изобретать велосипед.
А почему он должен держать его при себе? Вроде он никого не принуждал, а у нас официально свобода слова.
Потому что он предлагал синхронизировать потоки обменом сообщений. Я не обязана искать скрытый смысл и догадываться, что овтет был не на то сообщение.
Открою вам небольшой секрет — то как вы передаете сообщения («с помощью synchronized при доступе к одним и тем же данным») — тоже можно трактовать как передачу сообщений. Если вы при этом еще используете notify(All) — то наверняка.
Не похоже, по-моему. И нет, не использую.
НЛО прилетело и опубликовало эту надпись здесь
Потому что можно извращаться и обмениваться сообщениями между потоками… а можно нет.
А профайлер что на это говорит?
Дедлоки бывают?
Пардонте, похоже я с телефона не заметил, что это два разных треда. Выше говорилось про кластеризацию…
Только ниже, а не выше. Принято.
Слова прекрасные, но ни одно из них не подходит к приложениям, которые хотят быть хоть немного реалтаймовыми. Эти технологии играют совершенно в другой лиге.
Ну хоть вы понимаете, в чем соль.
Почему? Например, в ВоВ каждая игровая локация может быть на своей, отдельной, ноде. И прекрасно при этом все работает. Реалтаймово.
Потому что вы не в том треде, опять же. Опуститесь пониже в комментариях и не путайте людей.
Чорд %)
Это шовный мир и так сделать намного проще, чем размазать бесшовный мир. Впрочем, к Хадупу это всё равно никакого отношения не имеет.
Я не против наличия отдельных нод под локации, но для этого совершенно не обязательно использовать столь тяжёловесные технологии. Сколько у вас будет латентность в связке camel-activemq? Миллисекунды? Десятки миллисекунд? А у вас всего 50ms на все вычисления. Про хадуп вообще молчу.
Стоп, зачем? Что там синхронизировать? Просто передавать секьюрную инфо типо ключей при смене игровой локации.
Это не я предложил использовать транзакции и JMS вместо synchronized ;-)
К тому же в Minecraft, как я понял из статьи, «локаций» нет (могу ошибаться).
Каким образом вы сможете использовать synchronized в разных JVM, на разных машинах? Я имею ввиду, что там не такой уж большой объем данных, которые надо синхронизировать. Передавать чаров с локации на локацию, синхронизировать инфо для статистики, ну и так далее…
Если вы хотите реалтайм и при этом кластеризацию, вам не подойдет архитектура где нужно синхронизировать много данных между нодами.
Я не собираюсь использовать synchronized для синхронизации между разными JVM (хотя в каком-нибудь Hazelcast есть распределённые локи реализующие стандартный джавовский интерейс Lock).
Мало того, я вообще не собираюсь использовать synchronized. У него есть свои преимущества, но есть и более удобные средства обеспечения потокобезопасности — как в java.util.concurrent, так и в сторонних вариантах типа Akka. Последняя, к тому же, может обеспечить относительно прозрачную кластеризацию.

А придрался я именно к рекомендации заменить synchronized на транзкции и JMS. Перечитайте первые три сообщения этой ветки, в них нет ни слова о распределённости:
Как вы решаете проблему синхронизации, если у вас отдельные потоки для мобов и для стрел?
С помощью synchronized при доступе к одним и тем же данным.
Почитайте о транзакциях. Начните с JMS, посмотрите в сторону Apache Camel, activeMQ, Hadoop
А, да это я уже понял, я спутал треды) Я думал речь идет о распределенности.
Когда мне нужно будет сделать кластер, я всё-таки разделю мир на части, которые буду плавно связаны и передавать между собой объекты или их состояния в зависимости от того, на сколько объект с одной ноды ушел на другую. Потому что так проще и я смогу вручную контролировать, что делают мои сервера, а не класть это на либу, а потом получать терабайты трафика, когда 99% вещей вообще не нужно передавать…
Кстати, а в протоколе Minecraft реализован second connection дя прозрачного смена ноды? Или там есть возможность изменять протокол по своему усмотрению?
Например, в ВоВ такое есть, отдельным пакетом можно попросить клиент установить коннект с другим адресом и после успешного соединения закрыть првый коннект, тем самым менять ноды на лету.
Что доказывает, что у близзард именно такая архитектура.
О чем вы, гспди? Minecraft не предназначен для нормальной игры на одном-то сервере, не говоря уже о нескольких…
А как тогда его кластерезировать? Туннелирование и тому подобное не очень удачный вариант…
Как я уже говорила, мир должен быть бесшовный. Сделать мир со швами проще простого было бы, хоть сейчас. Как — вопрос уже другой, будет нужно — решу.
Почему туннелирование — неудачный вариант? Используются же балансировщики нагрузки в вебе и т. д.
Потому что по хорошему балансировщик должен принять клиента, передать его на ноду и забыть о нем (закрыть коннект). В чем смысл пропускать весь траффик все равно через одну точку? Рано или поздно упремся в производительность канала/памяти/ЦПУ/открытых файловых дескрипторов (сетевых потоков) именно этой точки.
Stack Overflow — веб ресурс, а мы говорим о реалтаймовых играх. Как отразится на прформанс (пинг) лишний слой (узел)?
К сожалению не могу сказать про игры.
Вот статистика по SO:
— 800 http requests per second
— 55 mbit per second
Можете охарактеризовать нагрузку в real-time играх?

Почему пинг должен сильно возрасти? Балансировщик и игровые сервера будут находиться в одной сети и интерфейсы могут быть достаточно быстрыми.
Пиратский сервер ВоВ, данные пару лет назад, так как сейчас этим не занимаюсь. Онлайн 2к человек, 4к активных сетевых соединений (не ESTABLISHED, а именно используемых) обмениваются данными 20 мегабит в секунду.
В играх отклик должен быть мгновенным. Потеря даже 50 милисекунд уже очень существенна.
Самый обычный сервер спокойно может держать десятки тысяч подключений.

В любом случае, никто не мешает добавить второй балансировщик, третий и т. д. Не надо даже велосипед изобретать, добавьте несколько записей в DNS. А если хотите, чтобы клиенты соединялись с самым свободным на текущий момент сервером, то достаточно централизованно собирать статистику и выполнять сначала запрос с клиента к серверу статистики с целью получения IP наименее нагруженного балансировщика.
Так именно про такой тип балансировщиков я и говорю! Клиент посылает запрос на балансер (который вы назвали сервером статистики), в ответ получает сервер, к которому нужно подключится.
Надеюсь вы знаете, что synchronized — это ой как дорого и с java 1.5 (+1.6) есть атомарные синхронизации. Если вас так заботит масштабируемость посмотрите en.wikipedia.org/wiki/Amdahl's_law и вы поймете что даже 5% синхронизированного обсчета приносит большие проблемы масштабируемости.

Почему вы назначаете потоки на конкретные задачи? Не проще ли сделать одну очередь заданий и потоки будут чисто worker, так система будет гораздо устойчивее и адаптивнее. Вы можете мониторить очередь отдельно и сортировать в соответствии с циклами. Думаю можно так отсортировать очередь, что вам не надо будет синхронизировать, так как один тайл не сможет обрабатываться разными потоками.

Хотя если вас устраивает текущая производительность — это все излишне.
Synchronized не так уж и дорого. Структура такова, что синхронизация происходит лишь при доступе к общим коллекциям и ни как иначе.

В принципе, раскидывать те же Entity на сервере можно как угодно, все потоки их обработки работают практически одинаково. Разделение просто по удобству. А ещё есть вещи, которые можно допустить лагающими — например, предметы, лежащие на земле. Их стандартная скорость 5 циклов в секунду, если немного просядет, не страшно. А вот тележки должны делать идеальные 20 циклов, и делают… Так удобнее просто.

Атомарные синхронизации годятся для доступа к переменным, но сложны или не применимы к коллекциям. Я думаю о реализации системы на Read-Write Lock'ах, но она очень сложная, т.к. встают большие проблемы с дедлоками и нужно очень сильно прорабатывать систему…
Присоединяюсь к вопросу про очередь. Я конечно против одной, но у вас их как-то многовато. Не получился так, что некоторые будут простаивать, а другие тормозить. При том что ресурсы машины будут полностью не задействованы. Собственно и их жесткая привязка к количеству, как я понял из статьи, тоже может мало способствовать гибкости приложения.

И спасибо за статью, и за комментарии. Познавательно получилось.
Дедлоки тут не причем, они появляются от некорректного проектирования, а от техники реализации (synchronozed или read-write lock) — не зависят (ну, почти).
Synchronized не так уж и дорого. Структура такова, что синхронизация происходит лишь при доступе к общим коллекциям и ни как иначе.
А насколько коллекции общие и как часто к ним происходит обращение и со скольки потоков. Хотя думаю что в данном случае это самое «дорогое» что у вас есть.
Synchronized с 1.6 неплохо продвинулись в скорости, подойдя к j.u.c.ReentranceLock.

Оно при старте вообще biased lock, т. е. почти ничего не стоит, пока работаешь с объектом в одном потоке. При попытке захвата лока из другого потока переходит в thin-lock, который использует CAS (оптимистичный подход). Если оптимистичный подход работает плохо, то lock разувается до thick (fat) lock'а с использованием примитивов OS.
Разве? По-моему, synchronized в общем случае работает на порядок шустрее локов из util.concurrent. Я это утверждаю на основе своих личных тестов. Synchronized также меняет имплементацию в зависимости от использования.
Пока он в biased lock — да
Если быть более точным, то biased lock используется не совсем при старте, а через какое-то время после старта. Также есть проблема в том что после сваливания в fat lock практически не происходит обратного возвращения к spin/thin-lock-ам, хотя может в последних версиях jvm что-нибудь с этим сделали.
Т.е. получается что на старте synchronized работает довольно шустро, но чем дольше сервер работает, тем больше вероятность на конкретном локе получить блокировку и соответственно раздуться в fat lock.
Хотелось бы уточнить… после перехода в fat lock все synchronized становятся фат локами, или только тот кусок кода, который туда свалился? Или только этот кусок пока он не закончится?

Просто я использую очень короткие синхронизации в 90% мест…
Блокировка происходит на объекте который указан в synchronized. Т.е. все синхронизации на этом объекте станут «fat».
Большое спасибо, очень полезная информация. Вообще я уже решила смотреть в CopyOnWrite коллекции и прочее.
Они также используют внутри примитивы синхронизации (synchronized, wait/notify, AQS)
Вообще относительно проблем производительности рекомендую посмотреть видео со встречи jug.ru:
jug.ru/archive/-/blogs/11484
и конкретно про synchronized vs ReentrantLock рекомендую почитать статью www.javaspecialist.ru/2011/11/synchronized-vs-reentrantlock.html
Нет, только конкретный монитор становится fat.
Biased lock используется при первой синхронизации на данном объекте. Он CAS'ом выставляет threadId в специальном поле объекта. Если там уже есть threadId, то блокировка раздувается до thin lock.

А вероятность получить fat lock сильно зависит от contention rate.
Боюсь у Вас немного неправильное понимание работы biased locking. В случае biased lock в этом спец поле всегда лежит thread id, и вход в критическую секцию этим тредом просто приводит к увеличению счётчика вложенности локов без всяких CAS операций. Т.е. biased locking это оптимизация CAS, в расчёте что блокировку в основном использует один поток. Если приходит другой поток, и видит чужой thread id, то тогда он с помощью всяких хитрых штук проверяет счётчик и если он равен нулю, то производит re-biasing, заменяя thread id. И только если счётчик > 0 тогда уже лок раздувается до thin/fat лока.
А также на jug-ах инженеры Оракла говорили про то, что эта оптимизация включается не сразу после запуска jvm, а через некоторое время, чтобы избежать ненужных rebiasing.
В случае biased lock в этом спец поле всегда лежит thread id, и вход в критическую секцию этим тредом просто приводит к увеличению счётчика вложенности локов без всяких CAS операций.


Я и не утверждал обратного. Я лишь сказал, что при первом monitorenter на данном объекте в одно из полей заголовка объекта пишется threadId (CAS-операцией). Если поток видит в этом поле не свой threadId, то lock раздувается до spin/thin lock'а.

Насколько я понимаю, CAS там необходим для гарантии видимости значения threadId.
В том-то и дело, что если там чужой thread id, то раздувание происходит не всегда. Посмотрите внимательно мой комментарий.
P.S. вы точно не путаете biased lock со spin/thin lock?
Уточнил, спасибо. По какой-то из старых статей неправильно понял работу biased lock'а. Сейчас поискал и прояснил для себя этот момент, в том числе и rebiassing.

Учитывая, что переход между разными типами локов довольно дорогой, понятна и полезна опция -XX:BiasedLockingStartupDelay. Особенно при использовании всяких прелестных DI framework'ов, которые инициализируют объекты в своем потоке.
Для HotSpot есть опция -XX:BiasedLockingStartupDelay=xxx которая указывает после какого времени после запуска можно начинать использовать оптимизацию.
Ещё добавлю линк на этот тест, выглядит довольно интересно:
java.dzone.com/articles/biased-locking-osr-and
Надеюсь вы знаете, что synchronized — это ой как дорого и с java 1.5 (+1.6) есть атомарные синхронизации.
synchronized в яве разный бывает (а точнее может быть одним из трех). JVM очень хорошо умеет его оптимизировать, но увы, если мы постоянно дергаем монитор из разных потоков то мы несчадно тратим ресурсы и на синхронизацию тоже
странно что вы не реализовали кластеризацию. Которую используют абсолютно все для масштабирования.
Привет вовкорам если что )
И дельфинам ))
Шестиядерный Core i7 справляется с нагрузкой лучше чем надо, пока это не нужно, но если дойдём до момента, когда будет нужно, то будем двигаться в этом направлении. Идеи уже есть.
Но идея очень интересная, я очень давно о ней задумалась. Если будет свободное время или необходимость, обязательно постараюсь сделать игровой сервер, распределённый по разным машинам. Только цель в том, чтобы все игроки были в одном мире без швов :)
это лишь вопрос коммуникации между кластерами.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Наверное, я всё-таки злая и жестокая, раз даже случайные люди это говорят. Бывает иногда…
программерский максимализм — первый опыт многопоточной разработки, чувство, что знаешь и можешь все
это проходит =)
Ни когда не было такого. Но человек выше действительно ошибся и вызвал у меня когнитивный диссонанс… А я не очень люблю это чувство.
Вы знаете, в какой-то момент понимаешь, мир большой. И вполне может допускать существование многопоточной архитектуры на базе JMS. Я, когда читал, подумал о чем-то эрланго-подобном, например, в духе actors из близкой к джаве скалы. Быстрое гугление подсказывает, что я не далек от истины — тут предлагают и JMS решения.

Именно поэтому я написал о максимализме — мир достаточно большой для того, чтобы могла случиться любая, самая удивительная вещь (еще один пример в тему — джава приложение с одним потоком обработки данных, которое совершает 6млн операций в секунду), поэтому не стоит резко отвергать идеи.
Не очень люблю оправдываться… Но я занаю о возможности работы многопоточной системы на обмене сообщениями, поэтому и не заметила подвоха, но это практически не применимо в моём случае, ведь мне нужно иметь доступ к огромным общим коллекциям, или не огромным… и это все, где необходима синхронизация в моём сервере.
>> ведь мне нужно иметь доступ к огромным общим коллекциям
А можно и здесь поподробнее? Я не совсем понял, откуда берутся большие объемы shared данных.
перекрытие чанков?
НЛО прилетело и опубликовало эту надпись здесь
Так вот что с ними случается!
Вообще сразу на CUDA все расчеты переводить.
Когда-то у меня крутилась такая мысль. Когда в уме строил архитектуру игрового сервера. Но совершенно не ясна куча вопросов. В частости:
-Объем оперативной памяти (для CPU десятки Гб, для видеокарты единицы)
-Обмен данными — в большинстве случаев серверу куда чаще надо получить и передать информацию практически без обработки
-Сложность гейплея — затолкать в небольшой объем кода все правила для оружия, заклинаний, взаимодействия объектов, экономику и т.д. и т.п. (я не про Minecraft конкретно)
-Где взять арендовать стоечный сервер с крутой видеокартой

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

Прирост производительности может быть очень солидный, даже если данные размещать не в памяти видеокарты, а в оперативке.

К примеру у мну на лаптопе. проц core i5 2.5GHz, видюха GT640M

выполняем бпф для набора из 16777216 значений, на java с библиотеками apache commons math и jCuda

БПФ с использованием apache commons math
Время преобразования: 80.71962624 сек

БПФ через JCufft (данные в оперативной памяти)
Время преобразования: 0.070345416 сек

БПФ через JCufft (данные в памяти видеокарты)
Время преобразования: 1.0714499999999999E-4 сек


вот как-то так
GPU хорош, когда ветвлений немного. Плюс передача данных из памяти GPU в основную — относительно дорогое удовольствие.
Привет. Очень рада что проект развивается. Было интересно читать. Хочу еще статей от тебя =)
«Я хочу от тебя статей!»
Да-да, именно этот расхожий штамп я и имела ввиду, однако никто почему-то не оценил. Видимо, нелюбовь к комментариям личного содержания перевесила.
Интересно… онлайн 200 это уже хайлоад?..
Для Minecraft — да. Оцените объем объектов при 200 человеках, которые надо обработать. Добавьте к этому то, что ничего не заскриптовано и все обрабатывается в мире, который всегда может быть изменен.
Не думали об Erlang-е? Ну, понятно, что он СОВСЕМ другой, но ведь как раз одна из его основных фишек — сверхбыстрые треды…
Если в Java реализовывать патерн Consumer/Producer через ExecutorService, то задания тоже выполняются легковестно. А если в очередь заданий складывать короткие события и писать код в стиле обмена сообщениями, то получится тот же Erlang / NodeJS по производительности.
А можно просто взять Akka…
Возможно я где-то ошибаюсь, но затраты на создание треда по-моему в Яве всё же гораздо выше (да что там, даже в Си они выше), чем в Эрланге. А связано это с тем, что треды у Эрланга реализованы совсем по иному — по своему, используются системные треды лишь для распаралеливания на несколько физических ядер, тогда как Шедулер своих собственных тредов у Эрланга свой.
Создание — да, дорогое. Но в Java есть реализация ExecutorService которая позволяет переиспользовать ранее созданные потоки: ThreadPoolExecutor
При правильном подборе параметров и выборе очереди можно подстроиться под многие задачи.
Хм, если только так, конечно… Хотя, по-моему (не уверен), Erlang при этом был бы всё же пооптимальней, в том плане что ему не надо держать треды «наготове» — он их создаст быстрее. А значит, использование RAM получится ниже.
Потоки в Executor не хранят состояния и их там не так много, что бы был заметен оверхед. Вся информация о задаче хранится в объектах с интерфейсами Runnable или Callable. Они создаются при необходимости и отправляются в очередь, откуда их заберут свободные потоки Executor'а и выполнят.
Я не спорю, что Erlang был бы оптимальнее для этой задаче — мне самому так кажется. Я за правильное понимание работы java.util.concurrent.

P.S. У Erlang'a не треды, а процессы. Разница в разделяемой памяти — у процессов её нет. По этой причине нельзя сказать, что в Erlang'е используются зелёные потоки.
Не путайте мягкое и теплое. У меня все основные потоки создаются исключительно при старте сервера. Возможно, потом я добавлю, чтобы создавались новые при высоких нагрузках, но это в любом случае процесс редкий, так что ни о каких затратах на создание потока не может быть и речи…

Так же потоки создаются при подключении клиента, но даже когда 500 человек одновременно ломились на сервер, это не вызвало ни каких проблем, а обычно они спокойно заходят и выходят. Да и эту систему с одним потоком на клиента можно положить на пул или вообще один поток, была бы нужда и желание.
Чанки же отменили пару патчей назад. Теперь секции — по сути то же самое, но по вертикали не 128 блоков, а 32 (или 16, не пинайте за неточность)
16. Но вообще-то чанки все так же есть, изменилось лишь то, что они теперь тоже разбиты на куски. От этого не легче, на самом деле, потому что куски 16х16х16 слишком маленькая структура, в итоге только больше циклов на поиск блока и больше памяти на хранение секций…
Из статьи интересно было узнать некоторые вещи о том, как написан майнкрафт. Хотя мораль, которую можно свести к одной фразе, «не пишите однопоточные игровые сервера», несколько тривиальна. Также не понравилось подчеркнуто агрессивное поведение автора в комментариях. Хороший программист это не тот, кто все знает, а тот, кто умеет учиться и воспринимать опыт других людей.
И да, числа, указанные в статье, это ни разу не «highload». Я, например, вообще не вижу проблемы с сохранением чанков на диск, если диск — это, например, кластер кассандры или другой NoSQL key-value storage.
Я должна, конечно, извинится за негатив в комментах, но это не я промазала по комментарию и начала отвечать не на то, всё запутав.

Вывод получился слегка смазанным, это точно. Но поток мыслей кончился к концу статьи…

Эти числа весьма highload, если обрабатывать это на одном ядре. Наш сервер по рассчетам потянет человек 800-1000. Можете говорить, что это не highload, но как я писала выше, вы не учитываете, что все объекты существуют в мире, который изменяется, и не заскриптованны совсем.

На счёт чанков — у нас сохраняется примерно 1000 чанков в секунду, ограничивает сейчас скорость сжатия чанков для записи на диск, т.к. SSD более чем справляется со сжатым потоком данных.
Эти числа весьма highload, если обрабатывать это на одном ядре.
Слово highload уже стало таким, базарным, что ли, что его применяет ко всему, что только можно. Хайлоад и одно ядро, ну вам самой то не смешно? Хайлоад и использование синхронизации для доступа к общим данным.

Вы писали что у вас все лежит или лежало в дефолтных коллекциях. Я вот уверен, что если немного посидеть и подумать над математикой то можно это все ускорить в, ну не знаю, раз десять. Вот когда вы выжмите из просчета мира все, что только можно, тогда и думайте о том, что у вас хайлоад, и ващи десять тыщ игроков уже не влезаеют на один сервер…
Ок-ок, в статье все равно не было слов highload. До хайлоад я надеюсь когда-нибудь дойти. И боже упаси использовать стандартные коллекции, только trove, только хардкор и парочка самописных узкоспециальных коллекций.
Я (не знаю, к счастью или к сожалению), пока еще не занимался оптимизацией матиматики под яву, но знаю людей которые плоненько так думали над тем, как быстро и красиво обработать пару млн структур с несколькими интовыми значениями… одним словом в таких случах следует быть чуточку ближе к памяти, нежели хочеться: тут и кэш у процессора сыграет свою роль, и возможностей по обработке больше (хотя они все страшные и посложнее будут).
Как написан майнкрафт — узнать не сложно — это java, который великолепно дизасемблируется (не знаю, может Нотч уже исходники выложил, он обещал давно). В дополнение: со знакомыми пару лет назад настроили сервачок и там игрались, потом пришлось что-то допилить, — полез в исходники… в общем, такой говнокод ещё придумать надо. На этом игру и забросил. :)
На счёт говнокода вопрос спорный. Я наизусть практически знаю код клиента версии Minecraft 1.0.0 (мы с этой версией клиента работаем), некоторые решения очень хороши и прослеживается опыт разработки игр, а некоторые решения откровенно ужасны и стоит за такое отрубать руки.

Вообще код обфуцирован, но есть практически официальный деобфускатор, да и Bukkit деобфуцируют почти весь код и пишут свой поверх.
Это как так? Насколько я знаю, одним из методом обфускации есть переименование осмысленных имен идентификаторов в разную чепуху. Как это можно восстановить испохдное имя??? Или вы что-то другое имели в виду?
Есть проект от энтузиастов, называется MCP (Minecraft Coder Pack).
Они создали набор утилит для декомпиляции и деобфускации Minecraft.
Имена для деобфускации предлагает сообщество моддеров через специального бота в IRC-канале.
Обалдеть. До чего только народ не додумается. Я думал, что при обфускации классам и переменным каждый раз назначается новое имя. А получается, что только раз и можно создать мапу соответствий. Правильно?
При каждой новой версии Minecraft, MCP Team обновляет MCP.
Это очень сложный процесс, хотя зависит от количества изменений.
У них есть самописная утилита которая сравнивает куски кода, и если там много совпадений то присваивает имя которое дали в предыдущей версии. Остальное обрабатывается вручную.
В среднем для обновления на новый major релиз уходит 6-10 часов беспрерывной работы.
Мелкие обновления (такие как с 1.4.3 до 1.4.4) делаются от 30 минут до часа.
Они очень крутые, работают уже года полтора и очень тесно взаимодействуют с Mojang. Они даже предупреждают их перед выходом новой версии и сами рекомендуют MCP для создания модов. Не очень понятно, почему они просто не выложат сходники, видимо, какие-то юридические проблемы.
559 человек на сервере? ух ты.
Спасибо, статья интересная. У меня, как не искушенного в написании серверов есть один вопрос к автору и другим опытным серверописателям (Rena4ka LLIbIcpEP). Почему не использовалась модель evented io? Ведь есть такая штука как как akka (http://akka.io/). Насколько мне позволяет осведомленность, в случае использования akka не нужно будет напрямую копаться в java.util.concurrent. Ну и масштабируемость регулировать проще.
> Почему не использовалась модель evented io
Ээээээ… Не потому ли, потому что проблема CPU bound?
Поясните что за CPU Bound? Я не издеваюсь, мне интересен вопрос.
Сам спросил, сам отвечаю. Не вижу в описанном в статье сервере особо сложных вычислений. Обрабатываются коллекции объектов, ведь это же можно распараллелить!
Может кто-нибудь просветит по вопросу? Я же интересуюсь почему нельзя использовать akka, хотя есть масса успешных юзкейсов у акки в плане игровых серверов.
Специфика геймдева. Для игроков действует компенсация лагов и предсказания, а при изменении большого числа блоков надо отсылать весь чанк, так что чистых Actor-ов там мало (печки всякие...). На akka.io есть реализации аркад?
Насчет аркад ничего сказать не могу, просто интересно как существуют крупные онлайн экшн игры. С трудом верится, что там используется вертикальное масштабирование.
Для меня мораль сей басни: Для создания масштабируемой архитектуры использовать Erlang, который может прозрачно утилизировать не только все ядра или которые укажешь, но и расползтись на несколько машин в кластер. И никаких блокировок и коллбеков, радость.
Вот на реддите в комментариях к статье “Twitter survives election after Ruby-to-Java move” так же набижали Node-хипстеры и сказали, что Node! Круче всех масштабируется Node! Node Node Node!!!

На хабре, похоже, Erlang популярнее.
image
Да я уже понял, в чужой монастырь со своим уставом не ходят.
Я согласен, у каждого языка\платформы есть своя ниша и границы применения, но erlang для этой задачи очень хорошо вписывается, по моему скромному мнению, которое по моей ошибке, похоже прозвучало здесь невпопад и не скромно.
Я извиняюсь за свою грубость, тут немного ниже более конструктивно моя мысль изложена: habrahabr.ru/post/157921/#comment_5408217
Но реализовывать игровую логику на Erlang — та еще радость…
Demonware например использует Erlang для сетевой части, а логику пишут на Python — цифры впечатляют — 307+ million gamers
2.4 million+concurrent online gamers
90+ games
300,000 requests per second at peak
Avg. query response time of < .01 second
500,000+ metrics a minute
100 billion+ API calls per month
Эти цифры могут впечатлять только совместно с описанием железа, на котором эти показатели достигнуты.
А так же «особенностей» реализации.

Например у WoT 500к онлайн игроков. Вроде круто, начинаем разбираться и оказывается, 500к это круто по фининсовым меркам, а по техническим все эти 500к размазаны по 4 кластерам и игроки с разных кластеров не могут играть между собой, надо перелогиниваться. Получаем 125к на кластер. Что уже не так круто как 500к.
Идем далее, 125к на кластер это круто. Но физически игроков реально по 2-3к на 1 машину в кластере. А получить на 1 компе 2-3к соединений уже самое обычное дело…
В общем если ваши цифры для датацетра написаны, то это обычное дело. А если это на двухядерном ноуте с 4Гб памяти, то это просто нереально круто)

P.S. Ничего не имею против WoT, привел его только как пример. ))
P.P.S. Так же не пытался ущемить достижения всех программистов когда либо писавших сервера для игр.)
Точное количество серверов на сейчас не знаю, но в докладе на ErlangFactory 2011 написано что «более 1850».
Естественно, это все не на ноутбуке, но говорить «ща как мы поставим 100500 серверов и все будет зашибись!» нельзя даже в вебе, а тут геймдев… Первая версия сервера в 2005 г была однопоточная и без проблем тянула только 80 пользователей и мощностью серверов тут мало что сделаешь. Что же касается WoT — 2-3к соединений на сервер — это немного, но тем более респект инженерам WoT за такую архитектуру.
Своим постом я только хотел сказать что есть примеры успешного использования Эрланга для игровых серверов, не более — не менее. :)
Присоединяюсь к благодарности за статью (хотя заголовок, мне кажется, мог бы быть и поскромнее).

Вопрос по существу — если у вас разные типы объектов обрабатываются в разных потоках, то не возникает ли проблем с неопределённостью *порядка* обработки? Условно, если 2 объекта разных типов как-то связаны (например, через общие данные), то при разном порядке их обработки могут быть различные варианты развития событий, на макро уровне.

Плюс, не может ли это повлиять на рассинхронизацию состояния с клиентами? Ведь у клиентов-то всё в одном потоке, насколько я понимаю.
Порядок обработки значения особого не имеет, у меня же не физическая симуляция, даже если один поток зависнет, то никто не умрёт. Вещи, которые должны быть «вместе» — редстоун и поршни — обрабатываются на одном потоке, который старается работать как можно точнее (чтобы обеспечить как можно более точные задержки механизмов) и даже делают 40 циклов вместо стандартных 20.

Синхронизация с клиентом проблем не вызывает, потому что каждый объект сам заботится о сообщении своего состояния клиенту, то есть пакеты генерирует сам объект, а не что-то отдельное от него.
Рад что ваш проект ещё живёт, движетесь в правильном направлении.
Давайте отвечу сразу всем кто писал выше про event-based. Обработка тика в realtime-игре и event-based подход как-то не очень совместимы.
1) Надо разрешать дурацкие гонки, типа «один объект в своём update поменял другой, а потом у другого вызвался update». Пусть A и B это два типа сообщений обрабатываемых объектом, а 1 и 2 объекты. Так вот внутри тика их надо обрабатывать только в порядке A1 A2 B1 B2.
2) внутри одного тика объект может поменяться несколько раз, и как-то эти события надо объединять. Получается в конце каждого тика объект должен получать сообщение, о том что ему пора отослать все свои изменения.
3) Пока не обработаны сообщения одного тика, начинать следующий тик нельзя.
4) Объект типа «игрок» почти каждый тик порождают ивенты — приходят данные о координатах. Эти события нельзя обрабатывать на клиенте и сервере сразу, они должны записываться в циклический буфер, чтобы на сервере действовала компенсация лагов, а на клиенте предсказания.

Конечно с помощью Actor можно всё это написать, но есть более подходящие шаблоны.
Спасибо, очень интересно было бы почитать про такие шаблоны!
Я реализовываю кое-что необычное для bombermine.ru, возможно скоро раскрою все карты в серии статей.
А вообще этим давно уже занимается Джон Кармак и все используют его наработки :)
Девушка, я хо4у Ваш сервер… ))
Миррион дораров.
согласен
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории