У меня довольно необычная задача...
Есть проект(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 подходящим языком, способным пройти такой стресс-тест.
Но давайте все же попытаемся найти ответы на вопросы:
- О возможности эффективно выполнить функцию написанную на одном языке программирования(абсолютно любой язык высокого уровня, не обязательно JS, может быть даже Lua), разными языками программирования.
- О легальности выполнения подобных вычислений на клиенте, с ведомом и без ведома пользователя. Ведь эти вычисления выполняются пользователем не для него самого, а для третьего лица.