@NicoBurno
Разработчик-прокрастинатор

Как правильно реализовать систему распределенных вычислений?

У меня довольно необычная задача...

Есть проект(node.js) который довольно высоко нагружен.
Задача проекта:
  • В базе данных(Redis) есть более 20 миллионов крупных записей(у каждой свыше 100 различных параметров в JSON-строке)
  • Есть очень сложная функция, которая модифицирует запись.
  • Каждая запись обязательно должна обрабатывается функцией раз в 10-15 секунд, и выдавать в качестве результата большой объект(конкретно - большущий лог своей работы)
  • Допустимая задержка не более 10 секунд(не должно быть запланировано выполение новой итерации, если не была выполнена старой, иначе система даст сбой)


Имеющиеся ресурсы:
  • 5000$ на железо
  • около 100.000 одновременно работающих клиентов(Android(Unity 3D), iOS(Unity 3D), браузеры(JS, поддержка с IE10)) на WebSocket


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

Схема сейчас следующая:
1. Все записи во время каждой итерации кладутся в стек FIFO, назовем его "стек задач"
2. На каждый клиент во время начала сессии отправляется функция-обработчик(она часто меняется, мы не можем позволить внедрять ее в код клиента)
3. Каждый клиент, когда ему нечего делать, берет из стека задачу. Выполняет ее и отправляет результат на сервер.
4. Сервер кладет полученный результат в FIFO-стек который назовем "стек валидации"
5. Каждый клиент так же периодически берет задачи по валидации не своих результатов(мы не можем сильно доверять одному клиенту). Проводит валидацию и отправляет результат на сервер.
5.1. Если валидация успешна - модифицируем запись и закрываем задачу.
5.2. Если валидация провалена - сервер сам, лично займется задачей

Но проблемы в следующем:
  • С браузерами проблем нет - там клиенты на JS и вполне справятся с функцией, но браузерных клиентов у нас слишком мало(не больше 10.000), в основном сидят с телефонов и планшетов. Можно ли организовать кроссбраузерную функцию, работающую и на сервере и на всех типах клиентов одинаково? Если да, то каким примерно образом?
  • Можно ли вообще так делать? Если да, то обязательно ли предупреждать пользователей? Сильно нагружать клиентов не планируем, будем делать небольшие перерывы между вычислениями, иначе потеряем доверие к приложению из-за отзывов типа "жрет батарейку за несколько часов". Нагружать клиентов, у которых приложение свернуто(только в случае мобильных платформ), так же не планируем.
UPD:
Время выполнения функции сервером около 30мс

UPD 2:
Наверное мне все же стоит кратко описать функционал:
Записи в БД - это персонажи игроков.
Функция-обработчик это генерация боя между двумя персонажами. Результатом является полноценный лог боя, который позже воспроизводит клиент.
На вход функции передаются только те данные, которые нужны и ничего лишнего.
Функция довольно хорошо оптимизирована, но в силу сложной механики игры эта функция все равно сложна(представьте себе быстрый генератор матчей между ботами в какой нибудь игре вроде Heroes of Might and Magic в режиме боя, запускаемый два миллиона раз в секунду).

На всякий случай уточню так же, что остальная часть приложения тоже оптимизирована. Например мы в реальном времени считаем только персонажей игроков в онлайне... А бои для остальных считаются разом раз в час/день/неделю(зависит от даты последней активности), причем считаем таким игрокам не все бои, а только часть из них, увеличивая множитель наград.

UPD 3:
Способ решения проблемы сменой языка и покупкой специфического железа - это конечно хорошо, нам следовало бы вообще написать проект на Erlang... ведь мы не знали что будет такая проблема, и считали node.js подходящим языком, способным пройти такой стресс-тест.
Но давайте все же попытаемся найти ответы на вопросы:
  1. О возможности эффективно выполнить функцию написанную на одном языке программирования(абсолютно любой язык высокого уровня, не обязательно JS, может быть даже Lua), разными языками программирования.
  2. О легальности выполнения подобных вычислений на клиенте, с ведомом и без ведома пользователя. Ведь эти вычисления выполняются пользователем не для него самого, а для третьего лица.
  • Вопрос задан
  • 1849 просмотров
Решения вопроса 1
riky
@riky
Laravel
Самый лучший выход на мой взгляд сделать эту возможность как задание в игре. То есть клиент сам выбирает активировать ее или нет и насколько сильно можно загружать проц и взамен за рассчет кадой игры получает какие то внутриигровые бублики, по сути они работают на вас, ведь с таким же успехом вы могли бы майнить битки на их видюхах, вместо рассчета игр, поэтому им за это надо платить, пропорционально работе которую они выполняют, и тогда игроки будут рады это делать. естественно не обязательно говорить им именно про рассчет игр, а обыграть уже геймплеем (например ускоренное изучение магии со сокростью x2 требует дополнительной вычислительной мощности для игрока + обьяснить игроку что чем мощнее комп тем быстрее будет идти изучение). + можно сделать опцию чтобы активировать эту штуку только при питании от сети, таким образом многие игроки будут специально оставлять телефон включенным на зарядке лишь бы получить бонусы.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
DrunkMaster
@DrunkMaster
Вам сложно помочь даже при желании. Первым делом надо посмотреть что там за строка с параметрами, все ли в ней необходимы. Допустим все. Все ли необходимы именно сейчас? Видели наверное что статистика (процент побед) у WOT обновляется раз в сутки ночью - не случайно же.
Про GO Pavel верно сказал, посмотрите в сети исходники Ogame - там вся игра на php но система боя написана на каком-то из С-языков.
Зачем вам распределённая система? Купите на 5000$ 1 сервер почти без оперативы и HDD, закажите туда процессоров побольше и напишите обработчик на GO, C++ и т.п. Отправляйте все задачи по расчётам на него. PROFIT! )))
Ответ написан
Комментировать
vpuhoff
@vpuhoff
Программист в свободное от работы время
не уверен на счет того возможно ли это в вашей системе, но можно попробовать ввести систему "временных меток", при этом "неактивные" объекты не просчитывать вашей функцией без особой необходимости, "замораживать" их до момента обращений к ним, когда к ним обратились просчитывать функцию столько раз, сколько это необходимо, для того чтобы "время" в объекте "догнало" объективное, при этом свободные вычислительные мощности (когда мало клиентов) тратить уже на расчет "отстающих" объектов.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы