HighLoad++ 2017
Зал Калининград, 7 ноября, 14:00
Тезисы:
http://www.highload.ru/2017/abstracts/2939.html
CinemaVR - это сеть аттракционов виртуальной реальности, расположенных в торговых центрах и кинотеатрах.
Сеть была запущена 1-го января с 10 локациями, в августе локаций было 25, к концу года будет 80.
На каждой локации 4-8 игровых машин и локальный сервер (итого: флот в сотню машин), которыми нужно управлять: контролировать, что конфигурация операционной системы соответствует целевой; что игровой контент и сопряженные сервисы скопированы и настроены; мониторить загрузку, статус работы, нетиповые события; собирать бизнес-события и синхронизировать данные, которые должны быть общими во всей сети.
...
2. Про VRTech и меня
• VRTech – фонд, вкладывается в VR-проекты
• Андрей Татаринов
• CTO в VRTech
• До этого CTO в Спутник, Zvooq, Enter
3. Про CinemaVR
• Сеть аттракционов
виртуальной реальности
• Размещение рядом с
кинотеатрами в Москве и
Петербурге
• Модульная архитектура
• Уникальные игры по сюжетам
фильмов
• Сеть франшиз
6. Компоненты системы
• VR
• HTC Vive, SteamVR
• Контент
• Собственная разработка – unity/unreal
• Сторонний контент
• Управление локацией
• Агент – C#
• Сервер локации – Ruby on Rails
• Глобальный сервер – Ruby on Rails
• Управление конфигурацией
• Chef
• Мониторинг/Аналитика
• Prometheus, Grafana, Kibana, Jupyter
7. CinemaVR в цифрах
• На момент запуска
• 10 локаций
• 40 Win-машин + 10 Linux-серверов
• Сейчас
• 40 локаций
• 100 Win-машин + 40 Linux-серверов
• Облако
8. Подход к разработке
• Итеративное развитие
• Минимизация необратимых решений
• Постоянное изменение
• Контроль сложности
• (!) Баланс временных и постоянных решений
• Вовремя превращать временное в постоянное
9. Платформа CinemaVR
• Централизованное управление и поддержка
• Автоматизация бизнес-процессов
• Низкие требования к обслуживающему персоналу
• Устойчивость к внешним условиям
13. Управление конфигурацией
• Push
• Нет агента
• Проще, удобнее, интуитивнее
• Ansible, (?)Salt
• Pull
• Агент на каждом хосте
• Сложнее в настройке
• Chef, Puppet
• Подходит только pull
• Хост может быть недоступен – интернет
• Изменение может не примениться с первого раза – интернет
• Chef, т.к. Puppet платный для Windows
34. Мониторинг
• ~700 метрик с локации → всего 26~28K метрик
• Сбор каждые 15 секунд
• CPU/Диск/Память/Сеть
• GPU – нагрузка/память/температура
• Бизнес-процессы – версия и работоспособность компонент,
версия игр, факт запуска игры и тп
40. Управление локацией
• Обслуживание одного клиента
• Принять билет/промокод
• Зарегистрировать в системе
• Запустить игру
• Остановить игру по истечении сессии
• Сохранить результат (игровой счет)
• Должно работать всегда
56. Выводы
Хорошо:
• Начинать с простого, временного решения
• Переделывать по мере необходимости
• Минимизировать необратимые решения
• Контролировать баланс временных и постоянных решений
• Поддерживать общую сложность так, чтобы обойтись без rock-
stars
Всем привет, меня зовут Андрей Татаринов, и я расскажу вам про то, как мы масштабировали сеть CinemaVR.
Я работаю СТО в VRTech, это фонд, который вкладывается в VR-проекты и разрабатывает собственные.
CinemaVR – это самый большой из наших проектов.
Уже есть успех – wargaming вложился и мы развиваем проект совместно.
Теперь про СинемаВиар.
Синемавиар – это сеть физических локаций. Которые располагаются в основном рядом с кинотеатрами в торговых центрах. Туда можно придти, заплатить за билет и поиграть в VR-игру.
У нас есть типовая архитектура, синемавиар строится кубами 5*5 метров и стандартным комплектом оборудования. Это позволяет быстро масштабироваться.
Игры в которые можно играть у нас на площадках разные. Некоторые пишем мы сами и они основываются либо на сюжетах фильмов, которые идут в прокате, либо на сильных брендах. Например недавно запустилась игра по Смешарикам. Мне кажется, это круто.
Большинство локаций в сети – наши, но мы целимся так же и в франшизную сеть, уже есть несколько локаций по франшизе.
Локации синемавиар располагаются не только в москве, есть точки в Санкт-Петербурге, Краснодаре и мы планируем открываться в других городах милионниках.
Куб синемавиар - это единица масштабирования.
Это типовая конструкция, мы готовим его в офисе вместе и железо и оборудование, а на локации требуется только сборка и калибровка.
Куб - это ферма 5*5 метров, такая как используется на концертах. Сверху подвешено четыре игровых машины и VR-маски. Для VR мы используем HTC Vive. Так же по сторонам висят телевизоры в которых видно во что сейчас играют игроки, а когда игры нет - идет реклама. На каждой локации есть сервер, wifi и сопровождающее оборудование.
Также на площадке есть планшет, через который оператор управляет тем, что происходит на площадке. Технические навыки операторов очень низкие, поэтому мы стараемся максимально автоматизировать работу площадки, чтобы они занимались только продажами. Поддержка у нас централизованная и сидит в офисе.
Вот в целом стек на котором мы работаем. Основная система написана на рельсах. Контент свой в основном на анриле, сторонний - на чем попало.
Запускались мы с нуля, с полного отсутствия команды до запуска три месяца.
На момент запуска у нас было 10 локаций, а это сорок игровых машин и десяток серверов. Кстати, даже это уже не мало. Учитывая то, что все должно было быть готово одновременно и запуститься без факапов в новогодние праздники. Как у нас это получилось, я рассказывал на стачке весной.
Сейчас локаций уже сорок штук, в парке сотня машин, на некоторых локациях две игровые машины, на некоторых - четыре. Сорок серверов и облачные компоненты.
Я бы сейчас хотел сделать доклад на две темы. С одной стороны рассказать про технологию, а с другой, про то как нам удается сохранить скорость, как-то контролировать качество и не увязнуть в сложных решениях.
Это конечно может казаться, что все на костылях, но у нас есть какой нюанс, ну как и в любом другом стартапе. Никто не знает, что именно мы будем делать через три месяца. Особенно на старте. Бизнес сам не знает, какие фичи будут важные, а какие отомрут. В этом случае невозможно все делать правильно и фундаментально. Мы будем делать все вечность, а потом окажется, что это не нужно.
Вот делали поддержку одной сложной многопользовательской игры, три раза перенесли ее запуск и потом совсем отменили. Бывает.
Поэтому мы стараемся любую фичу сначала сделать просто, так чтобы заработала. Но здесь интересно.
Решения нужно принимать так, чтобы был путь к отступлению, можно было временное решение переделать на другое более хорошее потом, ну или выкинуть. А где решение необратимое, там надо думать сразу.
Например по интеграции с платежной системой надо сразу думать хорошо, там сказать, ребята мы передумали, давайте быстренько все переделаем нельзя.
Ну и соответственно важно делать так, чтобы необратимых решений было поменьше, а те которые есть делать хорошо. А со всем остальным пасти баланс между хаосом и структурированностью и вовремя переписывать лучше.
Ну а про технологию я, в первую очередь расскажу про разработку того, что мы называем платформой синемавиар.
Разработка игр, это отдельный интересный вопрос, который мы не будем трогать.
Что нас интересует. Чтобы вся система могла централизованно управляться и поддерживаться. Чтобы мы могли нанимать на площадки нетехнический персонал, то есть чтобы все процессы для них были простыми, а проблемы помогала решать удаленная поддержка. И чтобы вне зависимости от внешних условий площадки функционировали.
Например внешним условием может быть интернет.
Несмотря на то, что мы работаем на территории торговых центров, не всегда получается подключиться к проводной сети и часто мы работаем через сотового оператора.
При этом как то я был на площадке в белой даче, смотрел как все работает. И просто не мог никому с площадки дозвониться, потому что у мегафона не было покрытия.
Кстати, вот это сочетание условий делает нашу задачу отдельно интересной. Чаще всего в таких децентрализованных системах бывает как.
Либо сложные внешние условия и простая бизнес логика, тот же интернет вещей. Каждая нода простая, чаще всего атомарная, но связь с ней не гарантирована. И вы решаете интересную задачу синхронизации данных.
Либо система сложная, например магазин, но тогда у него хорошая связь с интернетом и он может себе позволить делать это сильным условием, просто не работать, когда интернета нет.
А у нас надо и адаптироваться под довольно плохое покрытие интернета и поддерживать сложную логику площадок и всей сети.
Какие задачи должна решать платформа?
Платформа должна приводить весь парк в ожидаемое состояние, делать так чтобы нужные файлы лежали в нужных местах и в конфигах был написан правильный текст.
Обеспечивать поддержку своевременной информацией о том что происходит на площадках, чтобы поддержка могла реагировать.
И помогать автоматизировать процессы на площадке, снижая требования к персоналу.
Конфигурация машин синемавиар не статична.
Проект существует уже почти год и только наверное последний квартал можно охарактеризовать как спокойный с точки зрения изменений в требованиях. На старте все было иначе.
И нам важно было не столько подготовить машины какой-то конкретной конфигурации, сколько подготовить их таким образом, чтобы потом, когда они уедут в другой город и встанут на локацию, у нас осталась возможность поменять то, что на ней установлено и переконфигурировать.
Очевидными вариантами являются системы централизованного управления конфигурацией типа Ansible, Chef, Puppet, Salt.
Варианты из мира windows мы не рассматривали, потому что раз - там все хуже и два - нам нужно кроссплатформенное решение для контроля и линукс серверов.
Нам было важно угадать с первого раза, потому что решение про систему управления конфигурацией практически невозможно аккуратно переиграть.
Эти системы условно можно разделить на два типа.
Пуш системы, такие, где применение изменений активируется в явном виде по нажатию на кнопку. Система идет по ssh или winrm на удаленную машину и делает все что нужно.
Это гораздо проще и в понимании и в настройке.
Гораздо легче делаются какие-то разовые операции. Это например ansible и с некоторой натяжкой Salt.
И есть пулл системы, в составе которых есть асинхронный агент.
Конфигурация сначала публикуется на сервер.
Потом агент по какому-то своему расписанию приходит за своим конфигом и применяет изменения.
Это chef и puppet.
Нам подходит только pull схема, потому что мы ну никак не можем гарантировать наличие интернета на всех локациях одновременно.
Всегда есть несколько, которые отключены или недоступны по какой-то другой причине. И нам нужно, чтобы несмотря на все в какой-то момент изменение было применено.
Выбор между chef и puppet был простой - у puppet платная лицензия для использования под windows, при чем так хорошо платная, а у chef - нет.
В лучших традициях итеративной разработки мы внедряли шеф постепенно.
Ключевым моментом была сама возможность последующего удаленного внесения изменений на машины в автоматическом режиме.
Фактически то, что делал шеф на старте - это скачивал новые игры.
А большая часть конфигурации производилась один раз при наливке машины в офисе.
Вот начинали мы с такого документа, в котором по шагам был зафиксирован процесс наливки. Мы были бы рады конечно сразу автоматизировать все, но это требует разработки и отладки, а первая пачка машин у нас должна была быть готова через два с половиной месяца после старта разработки.
Но наличие такого четкого пошагового скрипта дало возможность потом шаг за шагом сокращать его, перенося каждый шаг в конфигурацию шефа.
Вообще это такой иллюстрирующий процесс к нашему подходу: сначала запрототипировать без фундаментальных вложений, а потом формализовать то, что реально оказалось нужным.
Вот кстати анекдот про переусложнить. На самом старте мне почему-то показалось корректным запустить шеф-сервер на каждой локации свой. Логика была такая, что в этом случае стабильность системы будет выше, если у клиента с сервером будет локальное соединение. В рамках общего тренда на децентрализацию локаций. И некоторое время мы пушили новую конфигурацию на каждую локацию независимо. Таким большим циклом из баша.
Потом оказалось что это проблемно, ровно по тем же причинам плохой связности и недоступности локаций в тот момент, когда нужно. Интернета нет - и обновление конфигурации не запушилось. Пришлось табличку вести “обновленные локации”. И отмечать куда применилось изменение а куда нет.
В общем, переделали на центральный шеф.
Это был интересный опыт, без переналивки переключить пятьдесят машин на другой сервер конфигурации, узнал много нового про сертификаты и то, как шеф на самом деле работает. Но, в этой истории был и положительный момент.
За период управления каждой локацией по отдельности, мы плюс-минус выработали подходящий для нас подход по циклу раскатки обновлений.
И при переходе на глобальный шеф нам было довольно просто его повторить, так как правильный ответ мы уже знали.
Получилось два контура: разработческий, там мы могли себе позволить разрабатываться и тестировать разрушительные изменения, и позволить разработке самостоятельно тестировать все решения вплоть до выкладки в предпрод;
и боевой, где отдельно выделен предпрод и прод.
Предпрод оказался нужен для боевой отладки игр и другого функционала, который в полной мере протестировать внутри нельзя.
Мы сделали так, что в предпроде есть все типы локаций: с очень плохим интернетом, с двумя кубами на одной площадке и тп, чтобы на всем разнообразии условий проверять функционал перед тем как катить на весь парк.
Отдельно интересно про дистрибуцию контента. То есть как игры попадают на локацию. Дело в том, что даже под короткую игровую сессию 7-10 минут VR-игра весит как минимум пару гигабайт.
А самая большая игра весила 7Гб.
При этом мы сначала думали, что игра разрабатывается, тестируется, релизится, разливается по локациям и ее жизнь на этом заканчивается. Но нет, обычно после первого релиза игра обновляется еще раз пять-семь в соответствии с обратной связью с площадок.
Как обычно начали с самого простого решения. Игры лежат в отдельном бакете на S3. Каждая машина скачивает игру независимо. Это позволило запуститься, но нестабильный интернет внес правки.
Проблем было две: разные машины одной и той же локации конкурируют за довольно узкий интернет канал; и нестабильный интернет приводил к прерыванию скачивания, после чего все начиналось сначала. Результатом было то, что от момента старта раскатывания игры до полной заливки на все локации проходило несколько дней.
Самое главное в том, что у нас есть способ поменять решение и заменить его на более эффективное небольшими усилиями.
За пару дней написали и отладили новую конфигурацию, в которой контент скачивается на локальный сервер, а с него раздается на игровые машины внутри локации.
Дистрибуция ускорилась и теперь примерно за полдня все локации получают новые игры.
Опять же, это история в меньшей степени про конкретное техническое решение. Ну качать один раз на площадку - это же тривиально. Почему сразу так не сделали?
Потому что такой проблемы могло и не быть, в этом случае бы сэкономили пару рабочих дней.
А так смогли запуститься быстро, отловили проблему - исправили.
Потом ещё за пару дней написали докачку для особо плохих соединений и стабилизировали время разливки до примерно 4 часов.
В общем шеф у нас во многом был и является системой прототипирования будущих бизнес-фич. Сначала в нем появились списки игр.
потом справочники билетов
Потом вшили время работы локаций и точечные ограничения на распространение контента.
В целом, понимание о том, что весь этот функционал нужно будет перенести в какую-то админку из конфигов было примерно сразу.
Но, если сразу писать админку, то мы усложняем себе экспериментирование с бизнес-логикой и способами управления данными.
С другой стороны, функционал, который стабилизировался и про который нет противоречия в понимании между разработкой и бизнесом, можно переносить в менее гибкую но более удобную для работы среду. Вытащить в админку.
Когда весь функционал уже написан, перенос из конфигов в админку - это механическое действие. Сначала зарефакторить конфиги так, чтобы вся информация про локацию была собрана в одном месте. Условно в одном хеше в конфиге.
Все, теперь есть протокол конфигурирования локации.
Потом сделать этот хеш внешним и скачивать его при каждом запуске шеф-клиента из какого-то внешнего сервиса конфигурации просто JSON файлом.
А как он там будет разобран на составляющие сущности - это отдельная задача.
Самое главное, что есть стабильный, соответствующий реальности API. На который можно опираться.
За работоспособностью всего парка нужно следить.
Например для того чтобы с уверенностью сказать, что новая игра доступна на всех площадках или для того чтобы отследить проблемы раньше, чем о них начнут звонить.
Подходящее решение нашлось не сразу.
Начали с простого: с активного логгирования в слак, который читает команда эксплуатации. Это уже было неплохо, так как показывает что что-то происходит в ответ на действия администратора.
Но сразу появился нюанс. Сложно Отличить 36 записей об успешном скачивании игры от 40 на глаз. И нужна была динамика изменений.
Что выбрать? Сисадмины голосовали за Zabbix или Nagios, потому что уже умели с ним работать.
Но они не позволяют делать странных вещей вида, за один запрос просуммировать метрики по маске и вывести на один график.
Мне принципиально важным кажется наличие в инструменте гибкости, поэтому мы пошли дальше.
Графит подходил по гибкости, но масштабировать его - это отдельное удовольствие. Три раза апгрейдили сервер, пока не отчаялись и не остановились на Prometheus.
К вопросу про метрики сейчас с локации нам прилетает примерно 700 метрик, всего это 26-28 тысяч.
Собираем метрики каждые 15 секунд, потому что времена одного измерения в минуту уже прошли.
Собираем как стандартные метрики - процессор, диск, память и сеть.
Так и специфичные для нас: например важно следить за тем, что видеокарта не перегревается. У нас на это есть отдельный алерт, на который мы реагируем.
И отдельно мониторим работоспособность наших систем. Актуальные версии, компонент, хартбиты, состояние в котором находится площадка: запущена игра или нет.
У прометеуса есть нюанс, который повлиял на архитектуру.
Прометеус собирает метрики с хостов сам с центрального сервера.
В условиях хорошей связности сети - это не важно, а вот в условиях с плохим покрытием становится существенно.
То есть в тот момент, когда прометеус не может достучаться до хоста, в графике появляется дырка.
Чтобы иметь графики по тому, что происходило на площадке без дырок, мы сделали схему с федерализацией прометеусов. На каждой площадке - свой, который собирает данные только этой площадки и в котором они полны.
А в облаке стоит федерерирующий прометеус, который собирает данные со всех площадок.
Для понимания того, что площадка недоступна мы используем как раз сигнал прометеуса о том, что он не смог снять метрики по федерации. Это конечно не совсем корректно, так как локальный прометеус может упасть, но пока было все нормально.
В центральном прометеусе мы используем алерт менеджер. В нем настроены уведомления в слак/емейл и смс.
Следить за парком машин - это интересная задача.
В итоге пришли к вот такому способу контроля состояния всего парка.
Выбираем какую-то метрику, например, версия кукбуки конфигурации локации и рисуем график где по вертикали весь парк, разбитый по значениям этой метрики.
Вот например на графике можно увидеть что основная часть парка обновляется быстро, а несколько машин застревают. Так как это агрегированный график у нас есть возможность, при необходимости разбить его и увидеть где именно проблема.
У нас настроены алерты на все основные системные метрики и на работоспособность систем.
В зависимости от типа проблемы время срабатывания алертов от 10 минут до нескольких часов.
Например о том, что кончается жесткий диск можно алертить раньше, а про ошибку в работе шеф-клиента, точнее в то, что последний успешный запуск был давно надо ждать дольше. Пару часов.
При этом не все алерты имеют смысл круглые сутки, например перезагрузка сервера локации без инициации со стороны админов - это проблема. Этим иногда злоупотребляют операторы площадок и нам нужно за этим следить.
С другой стороны нам известно, что некоторые площадки отключают на ночь и выключение сервера ночью и включение его с утра проблемой не является. В качестве бонуса у разных локаций - разное время работы соответственно нельзя просто поставить на мьют алерты с полуночи до 8 утра.
Нам везет и прометеус очень гибкая система, мы пишем в него отдельную метрику, которая показывает когда какая локация должна работать.
Собственно на слайде вы видите запланированное время работы каждой из локаций.
И на ее основании не активируем алерты, которые не имеют смысла во вне рабочие часы. Этот алерт прилетает через 10 минут недоступности площадки в рабочее время.
Теперь про автоматизацию процессов на площадке.
Самый главный процесс - это обслужить одного клиента.
Человек приходит с купленным билетом или промокодом.
Мы должны принять билет, зарегистрировать его в системе.
Запустить игру на одной или нескольких машинах в соответствии с логикой работы этой конкретной игры.
Остановить игру, когда истечет игровое время и сохранить результат.
Еще есть другие процессы, дневной цикл обслуживания площадки, подведение итогов дня для отчетности и т.д.
Но важно, чтобы процесс обслуживания одного клиента работал всегда, вне зависимости от внешних факторов, потому что это ну основной процесс в компании.
В идеальном мире все было бы просто, у нас есть центральный сервер, который знает про все игровые машины в парке и отдает им соответствующие команды.
Все классно, информация в одном месте, все локальные и глобальные процессы работают. Например так делает наш конкурент VivePort.
Но как мы помним, с интернетом все плохо и так не работает.
Поэтому система управления у нас разделена на локальную систему, которая обслуживает процессы площадки и глобальную.
Там живут процессы, которые требуют полной информации для работы. Это расчет лояльности, поддержка работы промокодов и скоринга.
А так как системы разделились, то требуется синхронизация для тех процессов, которым нужна полная информация о системе, например промокоды.
Задача усложняется тем, что у нас сеть франшиз и нам бы не хотелось, чтобы администратор франшизной площадки смог получить информацию о продажах всей сети.
Поэтому синхронизация должна быть только по тем данным, которые действительно нужны на площадке.
Рассмотрим это все на примере промокодов.
С промокодами нужно уметь делать следующее: выдавать их пачками или по одному, проверять актуальность и погашать на площадке, собирать интегральную отчетность по всей сети.
В лучших традициях нашего проекта, на самом старте мы сделали необходимый минимум, который позволил запуститься.
Есть большой предгенерированный список промокодов, мы выдаем коды из него через сайт.
Этот список скопирован на каждую площадку и каждая площадка независимо ведет учет погашенности.
Псевдорегулярно информация о погашении синхронизируется между площадками на ручном приводе.
В целом схема работоспособна и целый квартал мы на ней неплохо жили, пока не начали расти бизнес-требования.
Эта схема работает устойчиво только, когда все промокоды одинаковые и есть большой единообразный список, который можно скопировать.
Но, появились требования хранить и использовать на локациях привязку промокод-телефон и появились разные типы (на разную длительность и разные игры), соответственно коды из одного пула перестали подходить.
Как решать задачу синхронизации в наших условиях?
Начали размышлять про решения. Можно взять какую нибудь интересную NoSQL и организовать мультимастер синхронизацию.
Это ломает требование про ограничение по синхронизации на франшизы, но самое главное, это существенным образом усложняет архитектуру.
Кроме экспертизы по постгресу и рельсам команде надо будет вырастить экспертизу по новой маргинальной технологии. Но отговорить команду от этой мысли потребовало некоторое время :)
Можно делать как делает энтерпрайз и запустить две очереди сообщений: одна в сторону от локации к облаку, и другая - обратно.
Это ближе нам как решение, так мы можем контролировать какие данные попадают куда.
Но, из моего предыдущего опыта - такие системы никто не пишет правильно с первого раза.
Особенно в случае, когда точек мутации много, обязательно начинаются расхождения, которые довольно сложно находить и исправлять.
Нужно что-то похожее, но гораздо проще, такое, чтобы можно было не задумываясь написать правильно и прожить на нем пару кварталов пока не выйдет за ограничения.
Вдохновение пришло с неожиданной стороны: фронтендные практики сейчас становятся очень продвинутыми в плане работы с данными. Нам помог редукс.
Редукс это такая архитектура, которая часто используется совместно с реактом для управления данными.
Упрощенно цикл там выглядит так: нода производит изменение и отправляет сообщение об этом в базу, база получает сообщение, разбирает его и применяет изменение к внутреннему состоянию.
Обратно нода получает новое полное состояние.
Нам эта система очень хорошо подходит, потому что мутации происходят только в одной точке.
Одну систему легче контролировать и делать так, чтобы она работала корректно.
А на локации мы будем отправлять иммутабельный объект - JSON файл, в котором будет написано все знание, которое нужно иметь этой локации.
Вот так выглядела реализованная схема. Раз в минуту локация скачивает JSON в котором находится список активных промокодов, а так же другая существенная для работы информация. Обратно локальный сервер отправляет сообщения о новых событиях через очередь.
Однако даже в такой простой схеме не обошлось без нюансов.
Я не уследил и ребята воспользовались силой метапрограммирования и реализовали синхронизации на уровне отдельных записей актив рекорд из рельсов.
Это действительно просто - повесить хук на метод “сохранить” и по каждому изменению сущности отправлять новое сообщение в очередь.
В идеальном мире даже работает корректно.
Однако в реальном мире порядок доставки сообщений нам никто не гарантирует.
Проблемный сценарий легко проиллюстрировать на таком примере: у нас есть три сущности, игровая сессия с привязанным к ней игроком, результат игры и связка запуска с результатом.
Пересчет глобального скоринга и лояльности мы делаем на основании результата игры. Если в процессе синхронизации сущности перепутаются и результат игры придет раньше чем связанные с ней данные, то триггер на глобальном сервере не сможет обработать пакет.
Тут есть пара вариантов решения. Пятисотить и надеяться, что пакеты выстроятся в нужном порядке после последовательности ретраев, или игнорировать обработку бизнес-логики на этом пакете. Мы пятисотим, но и тот и другой вариант - так себе.
Лучше когда данные, которые участвуют в бизнес-процессах летят через синхронизацию одним пакетом.
То есть в пакет, который сообщает о запуске игры дополнительно подвязаны все сопровождающие данные о сессии игрока и его номере телефона. Это приводит к небольшому дублированию данных в потоке синхронизации, но идемпотентная запись поможет нам не ошибаться.
Но и это еще не все.
С точки зрения синхронизации не все локации одинаковые.
Одна, та на которой стоит человек прямо сейчас - гораздо важнее.
Нас интересует чтобы промокод который только что показал и погасил клиент, не мог быть использован снова прямо здесь через 10 секунд.
При этом сценарий когда один и тот же промокод используется одновременно на двух разных локациях, нас не интересует как очень маловероятный.
То есть нам нужен ещё один механизм, который позволит работать с локальными изменениями быстрее, чем позволяет механизм синхронизации.
Кстати, описанная проблема будет присутствовать в большинстве других архитектур синхронизации, кроме мультимастера.
Для решения этого кейса нам нужно ввести локальную таблицу корректировок, в которой будут храниться события которые произошли именно здесь, на этой площадке. Она поможет закешировать информацию о том, что промокод погашен до того, как мастер данные обновятся, пройдя по большому циклу
Вот вообщем все.
Кроме собственно рассказа про то как мы делали CinemaVR, мне было важно рассказать про то, как мы разрабатываем системы.
О том, что очень здорово начинать с простых и временных решений. Их можно развивать до пределов применимости и переписывать, на следующее менее временное решение.
Но при этом важно очень аккуратно принимать необратимые решения и минимизировать их количество.
Отдельно круто будет, если сложность вашей системы никогда не требует звездных программистов для развития и поддержки.