Как масштабировать приложение NodeJS с сохранением состояния

В настоящее время я работаю над веб-MMORPG-игрой и хотел бы настроить стратегию масштабирования на основе Docker и DigitalOcean капель.

Однако мне интересно, как я мог это сделать:

Мой игровой сервер должен быть разделен на разные контейнеры Docker НО, каждый экземпляр игрового сервера должен действовать так, как если бы это был только один гигантский игровой сервер. Это означает, что каждая модификация, происходящая в одном (перемещение символов), также должна отражаться на всех других игровых серверах.

Я пытаюсь заставить это работать (по крайней мере концептуально), но не могу найти способ правильно синхронизировать все мои экземпляры. Должен ли я использовать только трансляцию событий только для мастера или есть альтернатива?

Мне было интересно то же самое о моей базе данных MySQL: так как каждый игровой сервер должен будет читать/писать из/в db, как бы я сделал его правильно масштабируемым, так как игра становится все больше и больше? Лучшее решение, о котором я мог думать, это сохранить базу данных на одном сервере, который будет очень.

Я понимаю, что это может быть легко, если всем игровым серверам не нужно "делиться" своим состоянием, но это в первую очередь считается так, что я могу быстро масштабироваться в случае внезапного всплеска активности.

(Там будут разные "глобальные" игровые серверы, такие как A, B, C... но каждый из этих глобальных игровых серверов должен быть за кулисами, состоящий из контейнеров-докеров-1-X, на которых запущен "настоящий" игровой сервер так что "глобальный" игровой сервер - это всего лишь концепция)

Ответ 1

Проблема, о которой вы говорите, слишком обобщена, и трудно дать конкретный ответ. Однако позвольте мне быть безрассудным и дать вам советы общего назначения:

  • Удалить счетчики из баз данных. Вместо первичных ключей, которые являются автоматически увеличивающимися идентификаторами, попробуйте назначить случайные UUID.

  • Измените данные, которые должны быть проверены на соответствие центральной точке данными, которые являются автономными. Например, для аутентификации вместо использования учетных данных пользователя в БД используйте JSON Web Tokens, которые могут быть проверены любым хостом.

  • Используйте такие методы, как Consistent Hashing, чтобы сбалансировать нагрузку без необходимости балансировки нагрузки. Конечно, используйте хеширующие функции, которые хорошо распределяются, чтобы избежать/минимизировать столкновения.

Вышеуказанные рекомендации касаются в основном изменения дизайна для перехода от состояния к безстоящему, насколько это возможно. Если вам в любом случае понадобится предоставить части с состоянием, попробуйте угадать, у каких объектов будет больше шансов поделиться данными с состоянием и распределить их в одном и том же (или почти сервере). Например, если в вашей игре есть города, попробуйте выделить на том же сервере пользователей, которые находятся в одном городе, поскольку они более охотно взаимодействуют между ними (и делятся данными с состоянием), чем пользователи, которые находятся в разных городах.

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

Ответ 2

Ваш вопрос слишком широк и общая проблема масштабирования, о которой говорили другие. Было бы полезно, если бы вы более четко заявили о своих системных требованиях.

Если он должен быть в режиме реального времени, вы можете выбрать Redis в качестве основной базы данных, но тогда вам понадобятся ведомые устройства (для репликации), и вы не сможете автоматически масштабировать их по мере того, как вы идете *, так как Redis doesn ' t поддерживают это. Я предполагаю, что неплохой вариант, когда вы работаете с играми (возможны неожиданные всплески)

*, похоже, некоторые управляемые решения, вы должны проверить их

Если это может быть почти в реальном времени, использование Apache Kafka может оказаться полезным.

Там также очень масштабируемая БД, в которой есть все, что вам нужно: CockroachDB (я являюсь автором, yay!), но вам нужно запускайте тесты, чтобы убедиться, что они соответствуют вашим требованиям к задержке.

В целом, работа с мощным сервером очень - это плохой выбор, поскольку есть потолок, и вам будет стоить больше шкалы по вертикали.

Ответ 3

Там большое преимущество в масштабировании по горизонтали такого приложения. Я попытаюсь записать некоторые идеи.

Вариант 1 (состояние):

При планировании заявленных приложений вам необходимо позаботиться о синхронизации состояния (через PubSub, Network Broadcasting или что-то еще), и имейте в виду, что для каждой синхронизации потребуется время (если не блокировать каждую операцию). Если это вам подходит, давайте продолжим.

Скажем, у вас есть 80k операций в секунду на вашем кластере. Это означает, что каждый процесс должен синхронизировать изменения состояния 80 тыс. В секунду. Это будет вашим узким местом. Обработка 80 тыс. Изменений в секунду - это большая проблема для приложения Node.js(потому что оно однопоточно и, следовательно, блокирует).

В конце вам нужно будет точно указать максимальный объем изменений, которые вы хотите синхронизировать, и выполнить некоторые тесты с разными языками программирования. Накладные расходы на синхронизацию должны быть добавлены к общей рабочей нагрузке приложения. Было бы полезно использовать некоторый многопоточный язык, такой как C, Java/ Scala или Go.

Вариант 2 (состояние с маршрутизацией): *

В некоторых случаях возможно реализовать различный вид масштабирования. Когда, например, ваше приложение может быть разбито на области карты, вы можете начать с одной репликации приложения, которая содержит полную карту, и когда она масштабируется, она распределяет карту пропорционально. Вам нужно будет реализовать некоторую маршрутизацию между серверами приложений, например, чтобы изменить состояние в городе A мира B = > сервер вызовов xyz. Это можно сделать автоматически, но уменьшение масштаба будет проблемой.

Это решение требует большей осторожности и знаний о приложении и не является отказоустойчивым как вариант 1, но оно может масштабироваться бесконечно.

Вариант 3 (без гражданства):

Переместите состояние в другое приложение и решите проблему в другом месте (например, Redis, Etcd,...)