Comments 16
У вас явно какая-то проблема с алгоритмами. В описанных вами задачах такой сервер как вы выбрали должен был считать бой за 0.01 секунду и меньше, а не за 1.
И зачем вам на таком небольшом трафике городить микросервисы - вопрос к вашему архитектору.
500 запросов в секунду на бой с временем ответа в 1 секунду… У вас там либо 500 ядер на сервер либо просчет боя сделан максимально криво либо вы что-то напутали или наврали в тексте :)
Тут, кажется, просто возникло недопонимание. Сам просчёт боя действительно занимает доли секунды. Около секунды это end-to-end время: чтение состояния из БД, формирование довольно большого JSON-лога боя и отправка его клиенту, по которому рисуется анимация.
500 RPS это не 500 потоков, висящих по секунде, а реальная нагрузка, которую сервер держит при асинхронной обработке. Про «500 ядер» речи, конечно, не идёт.
Микросервисы у нас не из-за текущего онлайна, а чтобы проект дальше можно было масштабировать и развивать без переписывания всего с нуля. Для инди это скорее защита от техдолга, чем усложнение.
Я не думаю, что вы когда либо достигнете тех порядков траффика и сложности архитектуры, при которой микросервисы оправдав. Многие сейчас их используют просто потому что это модно :)
«Чтение состояние из БД» - не должно быть на каждый бой. У вас 128GB RAM, сделайте нормальное кэширование без вытеснения.
Формирование JSON тоже не должно быть долгим, не знаю на чем написан сервер у вас, если на C++, то рекомендую rapidjson, хотя есть и быстрее. Хотя, зачем вы вообще отправляете серверу большой лог в JSON? К вашему архитектору всё больше вопросов. Ладно protobuf, но можно и свой протокол обмена данными создать. Бинарный и эффективный.
Я игровыми серверами занимаюсь уже больше 10 лет, какие только не делал и для шутеров с UDP и для пошаговых игр и для онлайн игр с комнатами и весь мой опыт говорит о том, что у вас что-то не так. Подозреваю, что микросервисная архитектура у вас применяется для галочки, без понимания какие проблемы она решает и как она работает, поэтому и вылезла, например, загрузка чего-то при каждой битве.
Как вы собираетесь это всё масштабировать дальше? 1 бой - 1 секунда что бы там внутри не было сейчас. 32 ядра - 32rps по боям. 10000 онлайна которые вы прогнозируете даст, ну пусть 1/10 боёв в секунду. Это 1000rps, вам нужно 30 серверов чтобы тянуть только бои…
Я бы не стал сейчас заморачиваться с микросервисами, вам монолита боёвка + кэширование данных игроков хватить на онлайн до 10k спокойно на текущем железе (если сделать все правильно).
Масштабирование дальше можно решить шардингом по серверам внутри игры (если смотреть на то, как обычно подобные игры делают сейчас, то игроков всё-равно надо как-то разделять по времени). 2х еще легко выжать с нормальным серверным железом.
В общем, там целый список решений которые делаются легче, быстрее и дешевле, чем любая возня с микросервисами.
Многие сейчас их используют просто потому что это модно :)
Еще моднее кидаться камнями во всех, кто упомянет слово "микросервис"?))
Важно уточнить: у нас нет сотни микросервисов. Сейчас это монолитный backend под балансировщиком, с отдельным auth-сервисом и набором инфраструктурных сервисов (PostgreSQL/Redis/S3/monitoring/WebGL). Мы сознательно не дробим игровую логику на десятки сервисов на ранней стадии, но архитектурно оставляем возможность выносить отдельные домены (бой/экономика/контракты) отдельно, если нагрузка это потребует.
«Чтение состояние из БД» - не должно быть на каждый бой. У вас 128GB RAM, сделайте нормальное кэширование без вытеснения.
Естественно мы используем кэш, иначе бы не было таких показателей. И как раз для этого и была выбрана такая конфигурация сервера. Но чтение из базы нужно, потому что карточки в нашей игре не статичные, им можно прокачивать параметры в нонстопе, открывать новые абилки, иногда даже полностью сменить расу, класс и подкласс.
Хотя, зачем вы вообще отправляете серверу большой лог в JSON?
Я боюсь, вы не до конца понимаете контекст. При нажатии на кнопку "Напасть", отправляется запрос с текущей колодой, на сервере просчитывается весь бой (10 раундов) и формируется JSON со всеми действиями (батл лог), который возвращается в ответе на этот же запрос на клиент, и уже по этому ответу отрисовывается анимация. Все это, включая ожидание ответа от сервера, занимает сейчас менее секунды.
Ладно protobuf, но можно и свой протокол обмена данными создать. Бинарный и эффективный.
Можно и движок свой с 0 написать)) Но кто это все дело поддерживать будет?
У нас используется стандартно HTTP + gzip/br, этого вполне достаточно для такой игры.
1 бой - 1 секунда что бы там внутри не было сейчас. 32 ядра - 32rps по боям. 10000 онлайна которые вы прогнозируете даст, ну пусть 1/10 боёв в секунду. Это 1000rps, вам нужно 30 серверов чтобы тянуть только бои…
Сейчас 500 боев = 1 секунда, на 16 ядрах, и это мы еще в оптимизацию не погружались, там потенциал на много больше.
Масштабирование дальше можно решить шардингом по серверам внутри игры (если смотреть на то, как обычно подобные игры делают сейчас, то игроков всё-равно надо как-то разделять по времени)
Я в статье объяснил почему нам не подходит шардинг, и почему все должны играть на "одном сервере". Это бизнес требование.
Я игровыми серверами занимаюсь уже больше 10 лет, какие только не делал и для шутеров с UDP и для пошаговых игр и для онлайн игр с комнатами и весь мой опыт говорит о том, что у вас что-то не так.
Очень надеюсь, что речь не про сервера по Countre Strike и Minecraft, мы тут все таки свою игру делаем, и работа с сервером и протоколами это лишь верхушка айсберга.
Но спасибо за Ваши советы и рекомендации, обязательно примем к сведению.
Да, вы писали "Время просчёта боя сократилось с двух с половиной секунд до одной", теперь я вижу, что у вас 500 RPS, что уже неплохо, значит не совсем всё ужасно, но всё же - очень мало для 10 раундов на 16 ядрах.
Вы так же пишете, что бой это все действия, в том числе "чтение состояния из БД". Работа с БД при правильной организации кэширования и загрузки игроков не должна появляться в таких событиях, как расчёт боя. Либо вы кэшируете не всё или не так.
И что вы тогда понимаете под микросервисами? То, что вы пописали это не микросервисная архитектура, о которой вы писали в самой статье. Это просто монолит + сервисы. Для того, чтобы сказать что у нас микросервисная архитектура недостаточно сделать 1 микросервис :) Иначе любой монолит + база можно назвать "микросервисной архитектурой".
Я там опечатался, имел ввиду "Хотя, зачем вы вообще отправляете ОТ серверА большой лог в JSON?". Бой довольно частая операция, я бы пожалел игроков и не стал бы их заставлять качать большие логи боёв в JSON, потом ещё распаковывать их (если там gzip/zstd) и парсить.
JSON сам по себе довольно медленный, особенно если у вас фиксированный формат протокола. У нас на одной игре вдруг оказалось что 50% всего CPU сервера с 32 ядрами занимает парсинг JSON-ответов соц. сетей, особенно Mail.ru, там они иногда очень большие. И хотя там и было больше 10k RPS, всё-равно исправили. У вас вряд-ли такая же картина, это чисто для понимания.
Свой протокол это не так страшно и поддержка нулевая, если всё сделать правильно. Но переходить к этому этапу нужно только после анализа где же конкретно проблемы с производительностью. А так никакое сжатие не даст тех же результатов по скорости и трафику.
Сервера у нас свои, на C++, для своих игр :)
По факту узкое место было в БД на HDD. Слишком много самопиара и мало технической инфы для статьи о серверной оптимизации.
При попытках провести нагрузочные испытания сервер начинал работать нестабильно и иногда просто падал. Это делало разработку и проверку новых функций невозможными.
Меня смущает то что это карточная игра.. это не тот жанр который требует больших ресурсов. Что такое вы там испытывали и проверяли? Я java сервера lineage2 запускал в локалке на куда меньшей конфигурации.
Изначально проект работал на обычной виртуальной машине Selectel с четырьмя vCPU, восемью гигабайтами RAM и HDD
А вы могли не отбирать у деда его ноутбук из нулевых, а инвестировать немного в один единственнгый рабочий ПК в роли сервера, и несколько ip адресов? Хуанана на старых ксеонах и с дешевой памямятью вам бы на время разработки хватило на все-все-все.. заодно бы сэкономили на обогреве офиса.
Здесь важно, что под «карточной игрой» у всех разное понимание. У нас бой это довольно сложный серверный просчёт: сотни персонажей и способностей, баффы, дебаффы, триггеры, массовые эффекты, вероятности. Каждый бой почти уникален и формирует большой лог в JSON.
Плюс это не офлайн-матч, а многопользовательская система с общей экономикой, рынком, кланами и мировыми боссами, где всё должно быть синхронно.
Да, алгоритмы ещё будут оптимизироваться, это инди-проект, а не AAA. Сравнивать с Lineage2 не совсем корректно: другая архитектура, другое время и другие ресурсы.
Про «сервер под столом» тоже мимо, т.к. команда полностью удалённая, офиса нет. Нам нужен был стабильный сервер, на котором можно нормально гонять нагрузочные тесты до релиза.
Почему бы не сделать бой более детерминированным? В начале боя выбирается сид и отправляется клиенту (опционально с результатами и наградами)
А то можно дойти до того, что рендерить на сервере видеоролик боя и пересылать клиенту.
Все так и есть. Только сервер решает исход боя, а не клиент. На клиенте только отрисовка анимации. Все случайности контролируются плавающими коэфициентами, отсюда и случайный исход при каждом запуске боя. Если будут сиды, то все бои будут предсказуемы и могут быть скомпрометированы. Нам это не подходит.
А нельзя ли просчитывать бой на самих клиентах и просто сопоставлять что они оба насчитали? Ведь если один из них будет читерить (через подмену траффика или модификацию ассемблерного кода), то результат не совпадет с тем, что посчитал клиент противника. Если читерят оба… но зачем им тогда проще просто сговориться и поддаться друг другу вообще без всяких подмен и ассемблера.
Накинете доступ в ЗБТ или он исключительно платный?)
Привет, а почему вы просто не наймете адекватных разработчиков (может, чуть дороже рынка)?
Время просчёта боя сократилось с двух с половиной секунд до одной
Шо, из Озона ушли?
Паттерн Actor, Orleans.
Кейс: как мы ускорили серверную часть мобильной игры в 2,5 раза и снизили расходы в 5 раз