Разработка в Wargaming – встреча с Максимом Барышниковым, Head of Platform (ч.I)
Все побежали, и я побежал. Недавно я запустил серию онлайн-митапов, куда приглашаю на дискуссию экспертов в области разработки крупных IT-проектов. Нашим первым гостем был Максим Барышников, Head of Platform из Wargaming. Ниже — расшифровка нашего разговора, вернее, её первая часть, посвященная архитектуре.
Из этой части вы узнаете, например:
- сколько людей работает в Wargaming и сколько строк кода в «Танках»
- как, какие и куда едут байты во время боя в «Танках»
- какие подходы используют в Wargaming для обеспечения масштабируемости и отказоустойчивости
- какие архитектурные боли испытывают и на какие компромиссы между геймплеем и инженерными практиками идут
- почему в Python приходится отключать garbage collector, и где используется Erlang
- какие у Wargaming open source policies, и что они открывают в паблик
Разговор получился достаточно длинным, но подробным, если вам интересна тема разработки больших игровых проектов — прошу под кат.
Алексей Рыбак: Всем привет!
Максим Барышников: Привет.
Алексей Рыбак: Сегодня у нас в гостях Максим Барышников из Wargaming. Поговорим о разном, совместим интервью, ваши вопросы, и сделаем еще такую сессию, которую я назвал Lean Bar, но о ней позже. Максим, привет! Расскажи буквально пару слов о себе, пока я зашлю URL трансляции нам в канал и в группу на Facebook.
Максим Барышников: Привет. В Wargaming я с 2013 года, по-моему. До этого у меня была своя небольшая компания. До этого я занимался другими достаточно крупными проектами. А начинал свою айтишную карьеру с работы в собственном университете — это белорусский Политех, 1999 год. Где-то на втором или третьем курсе, когда я сдал свой первый, можно сказать, коммерческий проект, я примерно и отсчитываю свою профессиональную деятельность.
Алексей Рыбак: Сейчас у нас будет несколько сессий. Одна вводная: знакомство, блиц, короткие вопросы, короткие ответы, в первую очередь про компанию, про ваш технический setup. Приблизительно полчаса будем говорить про компанию, про технологии, которые используются, про особенности игровой разработки, про архитектуру. И после этого будет сессия комментариев, вопросов, когда мы на основную панель будем подключать всех желающих, кто находится в комнате Zoom. Поговорим таким образом 15 минут. Может быть, больше, может быть, меньше. Никто в рамки нас особо не ставит. Потом опять полчаса поговорим про управление большим коллективом. У тебя сейчас большой коллектив, несколько сотен человек, да?
Максим Барышников: 200, да. Достаточно большой.
Алексей Рыбак: Да. Поговорим про управление большими коллективами, про какие-то практики, которые используются, про какие-то личные боли — про разное. И после этого опять 15 минут вопросов. И в самом конце мы сделаем так называемый Lean Bar Session, когда все желающие с помощью канбан-доски могут предложить темы для обсуждения. Дальше мы за них проголосуем, что-то выберем. Вы достанете, может быть, какие-то напитки, которые припасли (я припас бутылочку пива). И в свободной форме, у кого будет время, пообщаемся в значительной более неформальной обстановке.
Максим, вопросы сейчас будут достаточно быстрые. Погнали.
Максим Барышников: Давай.
Блиц-опрос
Алексей Рыбак: Сколько у вас в среднем во всех проектах вашей компании пользователей онлайн в пиках?
Максим Барышников: В пиках, если суммарно говорить, то немногим больше миллиона сейчас будет.
Алексей Рыбак: А какие у вас самые пиковые часы, дни?
Максим Барышников: Как правило, это локальный вечер, 8–9 часов локального времени. Если смотреть по российским кластерам — они у нас более-менее регионально адресованы, охватывают Россию и СНГ, — это 8–9 вечера сейчас по Москве.
Алексей Рыбак: Сколько человек обычно в месяц пользуются сервисами?
Максим Барышников: Если брать целиком все игры, то несколько десятков миллионов. Наверное, 50 с небольшим.
Алексей Рыбак: Давай поговорим про стек технологий. Какие языки программирования вы используете?
Максим Барышников: У нас очень много Python, это не секрет. Дальше у нас есть C++ (безусловно, без него никуда). Весь более-менее традиционный веб-стек тоже основан на Python преимущественно. Сейчас появляется потихоньку Rust, он в некоторых областях сейчас очень хорошо себя показывает. Есть Erlang, Elixir, есть немножко Go, есть Java (умеренное количество). И для всяких энтерпрайсных внутренних наших систем есть .NET, и ничего такого больше нет. Достаточно много.
Алексей Рыбак: Какие вы используете системы контроля версий?
Максим Барышников: «Танки» в SVN, но сейчас основная — это Git (Bitbucket конкретно).
Алексей Рыбак: Какое примерно у вас число строк кода?
Максим Барышников: Строк кода без пробелов и всего прочего в танках около 10 с небольшим миллионов. Суммарно сказать затрудняюсь.
Алексей Рыбак: Какие сервера приложения вы используете? По-видимому, там стек достаточно большой. Может быть, назовешь 1–2 основных.
Максим Барышников: Да, стек там действительно достаточно большой, разлапистый. Все Python веб-сервисы, которые есть, они у нас работают достаточно традиционно — через uWSGI. Про игровые сервера я не говорю, там всё достаточно специфично.
Что еще из интересного? Например, есть Apache Ignite немножко. Всякое интересное в обработке данных, которые непосредственно идут для внутренней аналитики, для кучи разных других вещей. Там много всего интересного, и не очень стандартизовано.
Алексей Рыбак: Понятно. Какую базу данных вы используете в первую очередь?
Максим Барышников: На текущий момент я бы сказал, что PostgreSQL. Но у «Танков», «Кораблей», «Самолетов» в качестве игровой базы используется MySQL. Но он используется довольно специфическим образом. Ничего нетрадиционного там нет, но он зачастую просто используется как key value storage.
Алексей Рыбак: Если можно, попробуем быстрее. Можно просто называть какие-то аббревиатуры, потом поговорим подробнее.
В качестве брокера очередей используете какие-то решения?
Максим Барышников: Kafka, RabbitMQ.
Алексей Рыбак: Какой-то distributed job processing?
Максим Барышников: Если питонячий, то довольно часто используется Celery, но я упоминал Apache Ignite Data Grid (Прим. МБ: На Apache Ignite у нас построена инфраструктура для запускания лямбд, эдакий function-as-a-service, которые зачастую довольно удобно использовать для построения data processing pipelines. Некоторые проекты используют Alooma).
Алексей Рыбак: Для аналитической платформы есть какие-то стандартные компоненты: DWH, стриминг логов, хранение сырых данных, агрегированных данных для анализа?
Максим Барышников: Аналитика у нас — это достаточно большая дисциплина, совмещенная с Business Intelligence. Коротко в рамках блица я о ней не расскажу. Если захочешь, потом расскажу подробнее в рамках другой сессии. Там очень много всего серьезного, интересного про DWH и прочую аналитику.
Алексей Рыбак: Колоночные базы используете какие-то?
Максим Барышников: ClickHouse есть.
Алексей Рыбак: Хранилища логов типа Hadoop?
Максим Барышников: Hadoop есть.
Алексей Рыбак: Что ни спроси, всё есть!
Максим Барышников: Я бы предпочел, чтобы было не так, но оно, к сожалению, так.
Алексей Рыбак: Я так понимаю, у вас очень большая компания. Сколько человек работает?
Максим Барышников: Чуть меньше 5 тыс.
Алексей Рыбак: Это всё инженеры?
Максим Барышников: Нет. Давай поугадываешь. Как думаешь, какая часть инженеров из этих 5 тыс. человек?
Алексей Рыбак: Я не очень понимаю, кто остальные, но предположу, что саппортеры. Тогда скажу, что половина.
Максим Барышников: Чуть меньше половины, потому что в Wargaming, в отличие большинства компаний, разрабатывающих игры, еще включены функции паблишинга, маркетинга, вся эта красота. И помимо инженеров же еще большое количество художников, разных других артистов.
Алексей Рыбак: Да, под инженерами я имел в виду весь продакшен. То есть пару тысяч, да?
Максим Барышников: Да. Если художников и прочих людей в работающих над продуктом включить, то, думаю, и 3 тыс. точно будет.
Алексей Рыбак: В каких городах в-основном вы сосредоточены?
Максим Барышников: Самые крупные центры — это Минск, Питер, Киев, Чикаго, Балтимор. Остальные поменьше.
Алексей Рыбак: Минск самый большой, наверное?
Максим Барышников: Да. В нем суммарно работает 2400 человек.
Алексей Рыбак: Круто! Свое железо, своя инфраструктура или используете какие-то публичные облака?
Максим Барышников: Свое железо. У нас есть технологический партнер, компания, которая занимается всей этой красотой и инфраструктурой — это G-Core Labs. У нас очень много своего железа. Опять же, я бы предпочёл, чтобы у нас было меньше своего железа, но об этом можем, наверное, потом чуть подробнее.
Алексей Рыбак: Интересно. Обычно те, у кого много железа, думают несколько иначе с точки зрения контроля и прочего. Но это долгий разговор.
Есть у вас какая-то основная операционная система?
Максим Барышников: Да, CentOS 7.
Алексей Рыбак: Понятно. Площадки, точки присутствия, дата-центры?
Максим Барышников: Европейские, Москва, несколько в Америке, в Китае (штуки четыре, наверное). Еще разбросаны. На самом деле, их несложно все увидеть. Если у нас просто пойти на нашу Wiki-страничку, там написаны локации серверов.
Алексей Рыбак: Когда ты делал доклад, ты рассказывал, что в различных городах ещё есть: в Новосибирске, Красноярске… Они остались до сих пор?
Максим Барышников: Остались. Добавились еще в Павлодаре. В Узбекистане добавилась одна периферийка. Еще несколько точек присутствия есть. Из некоторых мы переезжали по тем или иным причинам.
Алексей Рыбак: Последний кусочек про тестирование delivery, про всю вторую часть, пайплайны разработки. Что вы используете для раскатки кода, какие компоненты?
Максим Барышников: В разных командах оно может быть по-разному.
Алексей Рыбак: В вашей команде что используется?
Максим Барышников: В нашей команде самописно допиленная Fabric, для раскатывания приложений. А управление OS, раздеплоивание всего остального — Terraform и вся остальная красота. Но у нас отличие от «Танков» состоит в том, что нам надо деплоить не одно приложение, а целую длинную цепочку. В целом мое подразделение — это где-то 150 разных приложений. И мы вынуждены использовать release trains для того, чтобы у нас всё согласовано работало там, где это нужно. «Танкам» этого не требуется, и там они просто спокойно раскатывают билды по серверам, делают это во время downtime. Игровая индустрия может себе позволить сказать: «А теперь у нас мир останавливается на три часа. Мы раскатываем релиз». Это что касается конкретно игры.
Алексей Рыбак: Скажи, пожалуйста, насколько вы заморачиваетесь автоматизированным тестированием, насколько у вас это является основополагающей парадигмой? Пишете ли вы тесты? Если да, то какой code coverage считаете нормальным?
Максим Барышников: Это преимущественная парадигма. У нас практически не осталось исключительно ручных тестировщиков. Те, которые есть, потихонечку становятся автоматизаторами, потому что такой объем всего без автоматизированного тестирования просто невозможно вывезти. Это заняло бы бесконечное количество времени.
Алексей Рыбак: Но coverage, наверное, всё-таки не автоматизаторы делают, это же сценарии больше.
Максим Барышников: Конечно. Я просто говорю про функцию QA. То есть QA у нас преимущественно делают автоматические тесты. Тестов пишем много. Coverage не является у нас какой-то особенной метрикой, мы не гонимся за coverage. Нам не надо говорить: «Чтобы было покрыто 80%». Команды решают отдельно.
Если говорить про мое подразделение — я говорил про 150 сервисов, — в некоторых подразделениях команды решают, что хотят отслеживать coverage и делать его максимальным. Это отдано на откуп команде.
Алексей Рыбак: Соотношение в командах между инженерами, которые пишут код, и инженерами, которые занимаются QA, является ли метрикой, которая универсальна и за которой вы следите?
Максим Барышников: Нет, за соотношение мы не следим, хотя оно примерно 1 к 3. Просто я заметил из практики, что ты там ни делай и как ни организовывай эту работу, она всё равно остается 1 к 3.
Алексей Рыбак: Или 1 к 4?
Максим Барышников: Да.
Алексей Рыбак: Или, если у тебя микрокоманды, то 1 к 2 или 1 к 1, если совсем микро-микрокоманды?
Максим Барышников: На самом деле, есть микрокоманды, у которых вообще нет QA инженеров, где они полностью полагаются на свой coverage, на автоматические тесты, написанные раньше, или на интеграционные тесты, которые они всё равно вынуждены проходить, и релизы у них проходят QA-less в режиме. Такие тоже есть.
Алексей Рыбак: Хорошо. С таким блицем давай закончим. Теперь хочется углубиться непосредственно в архитектуру. У тебя есть совершенно замечательный доклад, который ты делал на конференции HighLoad. Но если мы попытаемся подробно осветить все эти темы, то у нас уйдет время всего нашего митапа. Мы это делать не будем. Попробую сам дать какое-то архитектурное summary, чтобы плясать от него. Но прежде чем я расскажу свою интерпретацию этого доклада, расскажи, пожалуйста, следующее.
Мне как человеку, который больше работал с более традиционными, не real-time архитектурами, кажется, что ключевое отличие игровых проектов в том, что вам нельзя «лагать», вы должны упарываться по сетевому стеку и прочим делам — по всему тому, что влияет на user experience в плане real-time. Потому что все остальные проекты, там есть какой-то элемент интерактивности — вебсокеты, какой-нибудь polling, но всё это чатики или карандашик, когда кто-то пишет друг другу, там «лаг» даже в секунду будет незаметной ерудой. У вас должны быть совершенно другие SLA и совершенно другие особенности. Помимо этой реалтаймности это что?
Максим Барышников: Реалтаймовость — это, безусловно, основное. Но я уже упоминал, что, например, ни один из веб-проектов не может позволить себе выключиться на время релизов, а игры могут. Это такое послабление.
Второе, за чем нам приходится пристально следить — это скорее специфика конкретно наших проектов, в смысле эти цепочки специфичны конкретно для наших проектов: из игры, от сервера, от клиентов начинается очень много разных цепочек обработки данных, событий и всего прочего. Приходится следить за тем, чтобы эти цепочки тоже функционировали правильно и надежно, чтобы у них не скапливались очередь. Там реалтаймовость постепенно начинает немножко терять в своей значимости, но она просто меняется в цифрах. Учитывая количество всех событий, которые приходят, даже минимальная задержка в работе одного сервиса моментально где-нибудь строит здоровенную пробку из данных. Это уже будет, так или иначе, заметно пользователю. За этим тоже пристально следим.
Алексей Рыбак: Вернемся к твоему докладу. Тезисно озвучу, как я понимаю вашу архитектуру на самом базовом уровне каких-то компонент.
Юзеры пришпилены к дата-центру жестко, играют в рамках одного дата-центра. У вас есть два режима взаимодействия юзера с системой. Один режим — это всякие настройки. Наверное, сюда же можно отнести оплату, всё, что не связано с игрой, и второй режим — игра. Всё, что связано с настройками, включая настройки внутри игры… Я так понимаю, что у вас есть режим ангара в игре. Я там выбираю оружие, танк… Я сейчас говорю про танк, хотя, как понимаю, ваша платформа работает не только для «Танков», но и для остальных проектов. Но пока оставим «Танки», и пример, который я хочу осветить, тоже будет про «Танки». За это всё отвечают демоны base-app. Дальше у вас есть понятие игры, есть арена. Я зашел в игру, я в этой арене. Эта арена также присобачена к дата-центру, на этой арене достаточно много танков. Арена — это какая-то карта, которая побита на какие-то кусочки. За каждый кусочек отвечает свой демон cell-app, который обсчитывает логику, какие-то сцены. Там есть довольно интересные проблемы пограничных кусочков карты, но мы этого не коснемся.
В этой модели всё ли правильно? Надо ли к этому что-то добавить?
Максим Барышников: На момент, когда я делал этот доклад, всё было так. Сейчас немного изменилась некоторая вводная в сторону упрощения, но в целом всё так.
Алексей Рыбак: Мне и как пользователю, и с точки зрения архитектуры, всегда хочется понять, как те или иные сценарии задействуют те или иные компоненты, и какие байты в каком случае куда едут.
Давай представим себе ситуацию. Мы с тобой играем в одной игре. Мы на одной сцене на одной ячейке. Ты стреляешь в меня и, например, попадаешь в меня. Две точки во времени. Первая — ты стрельнул, второе — ты попал. Какие байты куда у кого поехали, и какие компоненты были задействованы?
Максим Барышников: Во-первых, сервер «авторитарный». То есть фактически и ты, и я находимся в одном времени, в одном пространстве, и всё это происходит более-менее так же, как это происходило в физическом времени. Сейчас я выстрелил. В рамках этого же процесса — оставим кусочки пока за кадром — сервер уже сам посчитал, куда это полетело, когда это попало, куда попало, и так далее.
Интересное начинается, если рассматривать всю ситуацию с точки зрения меня, сидящего за компом, и тебя, сидящего за компом в соседнем городе. Получается, от тебя идет input, от меня идет input. Я нажал кнопку выстрела, и от меня полетели байтики, вектор input в сервер. Он туда прилетел. Там сработал выстрел.
В это время и к тебе, и ко мне одновременно из одного и того же пространства сейчас идут байтики обратно, которые транслируют состояние дел.
Алексей Рыбак: Что это за байты? Пока не понимаю, что передается. Когда ты стреляешь, передается что?
Максим Барышников: На самом деле, с выстрелом всё менее интересно с инженерной точки зрения, чем с положениями, чем с координатами танков. Про выстрелы тебе рассказать или про координаты, про байтики?
Алексей Рыбак: Про всё. Я не понимаю, что едет. Я так понимаю, что должно быть какое-то представление сцены и действий.
Максим Барышников: Да. Представление сцены передавать по сети не нужно. В смысле ее геометрию и прочее. Она у тебя есть на клиенте, точно такое же, как и на сервере.
Алексей Рыбак: То есть мне нужно обеспечить очень быстрый протокол и обмен сообщениями об изменениях, которые переобсчитываются на моем локальном компьютере.
Максим Барышников: Да.
Алексей Рыбак: Ты говорил, что какие-то сцены обсчитываются непосредственно на сервере. Что там обсчитывается?
Максим Барышников: Геометрия сцены… геометрию карты тебе передавать не надо, она у тебя есть на компьютере, не меняется. Что тебе надо передавать с сервера? Всё считается на сервере. На клиенте ничего не считается. Клиент — это своеобразный плеер.
Алексей Рыбак: То есть вся картинка, вся 3D-отрисовка?…
Максим Барышников: Нет. Вся картина и вся 3D-отрисовка считается на клиенте, безусловно. Но весь геймплей, все положения объектов, геймплейное взаимодействие между ними и так далее, всё на сервере. То есть, грубо говоря, ты не можешь никак подхачивать свой клиент, чтобы у тебя увеличилось здоровье или еще что-нибудь. Но картинка, безусловно, рисуется на твоем клиенте. Есть, на самом деле, танки через GeForce Now (Прим. АР: NVidia cloud gaming service), где ты получаешь видеострим, но это другая история.
Алексей Рыбак: Правильно ли я понимаю, что пока мы играем на сервере, в основном нагружается проц, ну, может быть, еще память? То есть это такая CPU-bound архитектура?
Максим Барышников: Верно.
Алексей Рыбак: И дальше ты говорил в своих докладах, что вы каким-то образом бэкапируетесь. В целом для геймплея какой подход к high availability используете? Есть ли у вас балансеры, как балансируют? И так далее.
Максим Барышников: Вот что я говорил про бэкапирование в рамках того доклада. Поскольку у нас несколько процессов считают один и тот же бой, то теория high availability нам говорит, что любой из этих процессов может помереть, и нам надо решать, что делать в этой ситуации. Первоначальная стратегия, под которую делался движок, было то, что любой из процессов выпадает, и кластер должен суметь восстановиться с данных, какими они были до выпадения этого процесса, включая те данные, которые хранились на этом процессе. Поэтому этот процесс, который потенциально в нашей модельке выпал, он бэкап своих данных делает на соседей.
Алексей Рыбак: Давай представим себе совершенно упрощенный случай. Вся карта — это один cell, фактор репликации — условно говоря, два. У вас будет два процесса на серверной стороне?
Максим Барышников: У нас всегда будет одинаковое количество процессов на серверной стороне, сколько мы сконфигурируем, но просто на каждом процессе будет разное количество объектов, условно.Допустим, для простоты у нас есть два процесса, на всем кластере играет один бой. Один из процессов обсчитывает текущий бой. И по механизмам бэкапирования он все свои данные будет бэкапить на соседние.
Алексей Рыбак: Второй при этом ничего не считает, клиентов не обслуживает?
Максим Барышников: Да. Но если боя становится два, то на втором тоже запустится бой, он будет считать бой, обслуживать клиентов, а бэкапить свои данные на первый процесс.
Алексей Рыбак: Общение между этими двумя процессами… У вас фактор репликации какой?
Максим Барышников: (Прим МБ: Я так и не ответил на вопрос про фактор репликации, в описанном случае он равен единице.) Следующая картина сейчас. Мы пришли к тому, что мы сейчас любой бой можем считать на одном процессе жестко, не заморачиваясь с этими кусочками. Это первое изменение относительно времени того доклада. Процессоры стали существенно быстрее, а карты у нас так и не стали бесконечными. Это геймплейно не получалось, и в этом не было большого смысла. Поэтому мы сейчас на каждом ядре современного серверного можем обслуживать 3–4 боя легко, без проблем.
Второе. В рамках того доклада я говорил, что когда мы считаем, что мы бой безнадежно потеряли, то мы просто его убиваем, и люди начинают следующий бой, как будто ничего и не бывало. В рамках таких допущений то, что происходит конкретно в рамках одного боя, мы по-прежнему можем не бэкапить. Мы это пока еще делаем, но думаем о том, чтобы, если мы уже всё равно жертвуем боем в определенных условиях, то зачем нам его целиком бэкапить?
Алексей Рыбак: Я тогда не понимаю. Я так понял, что это ваше требование, чтобы в случае, если процесс умер, вы возобновили этот бой достаточно быстро. Как улучшение процессоров снизило риск того, что процесс может умереть, и у вас будет страдать пользовательский опыт?
Максим Барышников: Сам бой — особенно сейчас, он стал короче, 5–6 минут, может быть, 7, — пользователь в одну сессию играет 20–30 боев, а некоторые больше. Наши товарищи гейм-дизайнеры и прочие дизайнеры игры решили, что если один бой по каким-то причинам безвозвратно утерян, то лучше его похоронить совсем, чем пытаться восстановить.
Алексей Рыбак: И в этой ситуации вы говорите, что «Нам не нужно бэкапить. Если пользователь не расстроился и не ушел, то он еще раз запустит бой, бой будет на нормальном процессе».
Максим Барышников: Да.
Алексей Рыбак: Я теперь примерно понимаю, как это работает. Между различными компонентами есть ли у вас какая-то балансировка? Если есть, то что используете?
Максим Барышников: Да. Можно, еще к предыдущему пункту? Это как раз та ситуация, когда инженеры говорят: «Но как же? Мы же можем сделать, чтобы всё не потерялось», но гейм-дизайнеры говорят: «Всё и так хорошо. Не надо».
Балансировка нагрузки, безусловно, есть. Когда ты разбирался с этим докладом, там есть два специальных процесса — один BaseApp Manager, второй CellApp Manager — которые менеджерят свои типы процессов. Заодно они выступают load balancers в некотором смысле. То есть base manager знает всегда всю информацию о всех процессах base, их загрузку, количество cущностей, которые там запущены и работают (Прим. АР: танки, игроки и прочее), и они могут выступать в роли балансеров. То есть когда мне нужно подключить нового пользователя, именно BaseAppMgr решит, в каком конкретно процессе поднять эту сущность. Когда мне нужно создать еще какой-нибудь геймплейный объект и так далее, код фреймворка написан там таким образом, что ты просто говоришь: «Создай мне объект и скажи, где он создался», и всё. И балансировщик уже решает, где его создать.
На одной карте, если мы говорим про бой, там сотни объектов, если не больше. И каждый из них — это отдельный instance питонячьего в нашем случае класса с C++ бэкграундом, который создается на каком-либо процессе. И ты прозрачно работаешь с ним по сети — опять же, код так написан, — что тебе не надо знать, где он, а всё за тебя этот фреймворк обработает.
Алексей Рыбак: Всё самописное, правильно понимаю? Я так понимаю, что поскольку у вас сетевой стек свой, то всё остальное, что касается балансировки, там тоже свое?
Максим Барышников: Да. Безусловно, там много достаточно традиционных алгоритмов и очень традиционной и хорошо описанной математики, но реализация своя.
Алексей Рыбак: В жизни любого проекта есть определенные архитектурные боли, которые нельзя исправить очень быстро, они живут и потихонечку уменьшаются или, наоборот, увеличиваются. Можешь рассказать 1–2 кейса, что у вас было такого, и как вы порешали?
Максим Барышников: В случае конкретно «Танков», наверное, самая большая архитектурная боль — что кластер целостный. Он вот такой, и всё. От этого он достаточно хрупкий. Может случаться… Сейчас поясню почему.
В прошлом вопросе я рассказывал, что фреймворк сам тебе даст объект, и тебе неважно, где он находится и как обсчитывается. Безусловно, это провоцирует программистов начинать об этом забывать. В итоге, когда ты точно знаешь, что тебе надо объект не где-нибудь на кластере, а здесь рядом, потому что это условно сервисная штука и так далее, ты всё равно пишешь код: «Создай мне объект где-нибудь». Он для тебя выглядит как локальный, ты работаешь с ним как с локальным, но на самом деле он работает в кластере. В итоге потенциально порождается большое количество неэффективностей. Тебе надо маленький сервисный объектик, а он у тебя обсчитывается на соседней машине, это требуется дополнительная сеть и прочее, и делает заодно немасштабируемой и неделимой твою логику.
Алексей Рыбак: Проблема похожа на ORM.
Максим Барышников: Да, она имеет что-то общее в своей философской части с ORM. Я большой противник ORM вообще. Вернее не ORM, а тем, чтобы им пользовались, не зная, как работает база данных.
Алексей Рыбак: ОК, про архитектурную боль рассказал. Как это решать?
Максим Барышников: В конкретном случае «Танков» концептуально архитектуру принято решение не переделывать. Она такая есть. Я уже упоминал, более 10 млн строк кода, всё это переделать невозможно. Поэтому существуют определенные практики, правила, чем надо пользоваться и так далее, которые обязаны знать все серверные программисты — у клиентских всё проще, — и за которые жестко бьют на code review.
Алексей Рыбак: Понятно. Следующий вопрос. Я понимаю, что команда большая, но как тебе кажется, ядреные компоненты, если бы делали всё с нуля, что бы сделали иначе? Может быть, отказались от каких-то базовых компонент?
Максим Барышников: Уточняющий вопрос. С теми знаниями, которые есть сейчас, в то время, когда начинались «Танки», или сейчас с теми занниями, что есть сейчас?…
Алексей Рыбак: (смеется) Это очень программистский вопрос, невероятно программистский. Прямо сейчас и с теми знаниями, которые есть сейчас. Я спрашиваю для того, чтобы люди получили какой-то опыт, а не для умственного упражнения.
Максим Барышников: С теми знаниями, которые есть сейчас, с тем опытом разработки и оперирования тем продуктом, который есть сейчас, а главное, с теми технологиями, которые есть сейчас… То есть тут не всё 100% зависит от конкретно тебя. С теми технологиями, которые есть сейчас, не стали бы делать монолитный кластер. Сделали бы жесткое разделение между этой ангарной условно частью и боевой, чтобы можно было боевую условно запускать отдельно от кластера.
Алексей Рыбак: Есть определенные зависимости, и даже в момент боя какой-то обмен информациями между и cell-app, и base-app приходится тягать, да?
Максим Барышников: Два соседних боя никак не взаимодействуют. Они по идее могут быть разделены. Игроки во время боя тоже эксклюзивно заняты. В теории можно запустить бой так, чтобы минимизировать латенси тем игрокам, которые в нем сейчас собраны; или можно просто их собрать по географическому признаку, и запустить бой рядом с ними на другом конце мира. В 2008–2009 году это было сделать невозможно с точки зрения мировой инфраструктуры, облачных провайдеров и всего прочего. У тех в принципе так не получалось. Это раз. Во-вторых, сам BigWorld дизайнился с идеей бесконечного continuous мира. По-моему, он был воодушевлен играми а-ля Ultima Online, хотя Ultima, по-моему, не была первой такой игрой. Но Ultima-подобные игры на BigWorld делать вообще волшебно.
Алексей Рыбак: Ты упомянул про алгоритмы. Я правильно понимаю, что алгоритмы в основном в обмене данных, в сетевых сообщениях. Можешь рассказать, что здесь самое алгоритмически «челленджовое»?
Максим Барышников: Много алгоритмического «челленджа» как раз в сетевой части, в части трафика от сервера к клиенту. Напомню, в каком году это вышло, и с сетями всё было довольно плохо. И там надо было извращаться максимально, чтобы передавать максимум информации в минимальный трафик. При этом еще желательно без всяких задержек, быть толерантными к потере пакетов.
Например, кодирование координат. Это алгоритм, где в фиксированном векторе ты передаешь набор координат относительно какой-то опорной точки, координаты кодируются в порядок и мантиссу относительно опорной точки. И чем больше у тебя значение координаты, тем меньше у тебя получается точность. Мы всегда передаем координаты относительно самого игрока, что логично, потому что чем ближе к нему… Чем ближе к ишроку, тем чаще мы передаем координаты, и поведение объекта получается плавнее и точнее. Чем дальше, тем реже у него происходят эти обновления, и уменьшается точность позиционирования.
Алексей Рыбак: Я правильно понимаю, что вы должны передать какой-то пакет информации, в котором будет написан объект и его новая координата? На уровне протокола, сетевого стека. Там, наверное, не TСP, а UDP?
Максим Барышников: Да.
Алексей Рыбак: В одном UDP что едет?
Максим Барышников: В одном фрейме UDP что едет? Те объекты, которые находятся в area of interest этого игрока. Там тоже есть концепция, чтобы отсекать что-то ненужное (Прим. МБ: Level of Details (LoD) примененный к сети.).
Алексей Рыбак: Скажи, пожалуйста, это число объектов, которые прилетают в одном пакете, чем ограничено?
Максим Барышников: Ограничено MTU, во-первых. Мы стараемся не вылезать за MTU. Учитывая, что это UDP, то фрагментированный UDP по сети ходит довольно плохо, поэтому мы не вылезаем за MTU. А дальше апдейты внутри приоритезированы в соответствии с логикой. То есть даже если кто-то пропускает свой черед отправить координаты из-за того, что мы в MTU уперлись, то он всё равно отправится в следующем пакете. Это позволяет достаточно надежно передавать всю эту информацию. И мы несколько раз даже расширяли точность координат, потому что видели, что мы перестарались слегка, и у нас полпакета уходит пустым.
Алексей Рыбак: Сейчас давайте тогда объявим небольшую сессию вопросов и комментариев.
Алексей Рыбак: Фрол Крючков, пожалуйста, подключайтесь.
Фрол Крючков: Спасибо большое за рассказ.
Алексей Рыбак: Друзья, еще кто-то хочет присоединиться? Прошу вас, Фрол.
Фрол Крючков: У меня достаточно примитивные вопросы. С учетом болей архитектуры как долго происходит онбоардинг новых ребят? С учетом того, что нужно понять, какие есть текущие ограничения использования тех или иных сущностей в коде, чтобы что-то не положить случайно.
Второй момент, исключительно любительский. А где используется Erlang, и в какой части всего этого стека?
Максим Барышников: Хорошо. Расскажу сейчас по очереди. Полный онбоардинг, во-первых, отличается в разных командах. В серверной команде, онбоардинг наиболее сложный, занимает до трех месяцев. Но где-то через 2–3 недели человек способен писать вполне себе приличные вещи.
Поскольку кода