Це правильна архітектура для нашої мобільної гри MMORPG?


14

Сьогодні я намагаюся створити архітектуру нової мобільної гри MMORPG для моєї компанії. Ця гра схожа на війни Mafia, iMobsters або RISK. Основна ідея - підготувати армію для боротьби зі своїми противниками (онлайн-користувачами).

Хоча я раніше працював над кількома мобільними додатками, але це для мене щось нове. Після великої боротьби я придумав архітектуру, яка проілюстрована за допомогою діаграми потоків високого рівня:

Діаграма високого рівня

Ми вирішили перейти з моделлю клієнт-сервер. На сервері буде централізована база даних. У кожного клієнта буде своя локальна база даних, яка залишатиметься синхронізованою із сервером. Ця база даних виконує функції кешу для зберігання речей, які часто не змінюються, наприклад, карти, продукти, інвентар тощо.

Коли ця модель створена, я не впевнений, як вирішити такі проблеми:

  • Який був би найкращий спосіб синхронізації баз даних сервера та клієнта?
  • Чи повинна подія зберегтись у локальній БД, перш ніж оновити її на сервер? Що робити, якщо програма чомусь припиняється перед збереженням змін у централізованому БД?
  • Чи слугуватимуть прості HTTP-запити для синхронізації?
  • Як дізнатися, які користувачі зараз увійшли? (Один із способів може полягати в тому, щоб клієнт продовжував надсилати запит на сервер через кожні х хвилин, щоб повідомити, що він активний. В іншому випадку вважайте клієнта неактивним).
  • Чи достатньо перевірок на стороні клієнта? Якщо ні, то як відновити дію, якщо сервер щось не перевірив?

Я не впевнений, чи це ефективне рішення, і як воно буде масштабуватися. Я дуже вдячний, якщо люди, які вже працювали над такими додатками, можуть поділитися своїм досвідом, який може допомогти мені придумати щось краще. Заздалегідь спасибі.

Додаткова інформація:

Сторона клієнта реалізована в ігровому двигуні C ++ під назвою мармелад. Це кросова платформа, яка означає, що ви можете запускати додаток на всіх основних мобільних ОС. Ми, звичайно, можемо досягти різьблення, що також проілюстровано на моїй схемі потоку Я планую використовувати MySQL для сервера та SQLite для клієнта.

Це не покрокова гра, тому немає великої взаємодії з іншими гравцями. Сервер надасть список онлайн-гравців, і ви можете боротися з ними, натиснувши кнопку бою, і після деякої анімації результат буде оголошено.

Для синхронізації бази даних я маю на увазі два рішення:

  1. Зберігати часові позначки для кожного запису. Також слідкуйте за тим, коли місцевий БД востаннє оновлювався. Під час синхронізації вибирайте лише ті рядки, які мають більшу позначку часу, та надсилайте до локальної БД. Зберігайте прапор isDeleted для видалених рядків, щоб кожне видалення просто поводилось як оновлення. Але у мене є серйозні сумніви щодо продуктивності, оскільки для кожного запиту на синхронізацію нам доведеться сканувати повний БД і шукати оновлені рядки.
  2. Іншою технікою може бути ведення журналу кожної вставки або оновлення, яке відбувається проти користувача. Коли клієнтська програма запитує синхронізацію, перейдіть до цієї таблиці та дізнайтеся, які рядки таблиці було оновлено чи вставлено. Після успішного перенесення цих рядків до клієнта видаліть цей журнал. Але тоді я думаю про те, що станеться, якщо користувач використовує інший пристрій. Відповідно до таблиці журналів усі оновлення передані для цього користувача, але насправді це було зроблено на іншому пристрої. Тож нам, можливо, доведеться також слідкувати за пристроєм. Впровадження цієї методики забирає більше часу, але не впевнений, чи виконує її перший.

2
Я б захопив оцінку MsSQL і поспілкувався з нею - я не впевнений, що надає MySQL з точки зору реплікації, але MsSQL 2008 R2 дає вам НАБУТИ реплікації (5-6) методів на вибір. Просто думка, а не ненависть до MySQL чи чогось іншого, але Microsoft справді хороший у кластеризації.
Джонатан Дікінсон,

1
@Jonathan Dickinson: Є кластер MySQL: P
Coyote

1
Також подивіться на PostgreSQL - версія 9 має технологію реплікації, PostgreSQL має чудову давню репутацію для обробки важких вантажів дуже добре, багато розробників здаються оптимізаційними гайками, а найкраще, що це відкритий код і абсолютно безкоштовний для будь-якого використання (включаючи комерційну).
Рандольф Річардсон

річ у тому, що ми не можемо використовувати ту саму базу даних на стороні клієнта та сервера. Я думаю, що найбільш підходящим БД для клієнта буде SQLite, щоб він не витрачав багато ресурсів, оскільки додаток буде працювати на мобільних пристроях. Хоча людина, яка працює на серверній частині, знає лише MySQL, тому ми вибрали саме це. Також я чув, що більшість ігор MMO використовують базу даних MySQL.
umair

1
@umair: Клієнт може бути SQLite (наприклад, на iPhone це вже є). Але ви можете просто зберігати потрібні дані, які вам потрібні, у файлі (що все-таки робить SQLite) і не турбуватися з клієнтською базою даних взагалі так, як ви це зробите з додатком Javascript.
Койот

Відповіді:


15

Якщо це не гра «в реальному часі» в тому сенсі, що гравцям не потрібно бачити безпосередній результат дій іншого гравця на ігровій сцені, то вам слід добре відповідати з HTTP-запитами. Але майте на увазі накладні витрати HTTP.

Зауваження, що використання HTTP не вбереже вас від обережного проектування вашого протоколу зв'язку. Але якщо ви керуєте і сервером, і клієнтом, вам пощастило, оскільки ви можете скорегувати протокол, коли вам це потрібно.

Для синхронізації між основною БД та Клієнтською БД ви можете використовувати будь-який транспортний протокол, до якого ви маєте доступ, HTTP або інші. Важливою частиною є логіка синхронізації. Для прямого підходу просто об'єднайте з сервера всі останні зміни, необхідні клієнтові з моменту останньої часової позначки в клієнтській БД. Застосуйте його до клієнтської БД і перейдіть з цим. Якщо у вас є більше змін на стороні клієнта, завантажте його, якщо воно все ще актуально, інакше відмовтеся.

Деякі ігри навіть не використовують локальну БД, вони просто відслідковують стан, об'єднуючи відповідну інформацію з сервера, коли це необхідно.

Якщо втрата локальних подій неприйнятна, тоді так, ви повинні мати локальне сховище та зберігати в цьому сховищі якомога частіше. Ви можете спробувати це зробити перед надсиланням кожної мережі.

Для перевірки активних користувачів ми звикли пінг з HTTP кожні 20 секунд в успішній грі ... Це значення зросло негайно, оскільки сервери були перевантажені :( Команда сервера не думала про успіх. Тому я б сказав вам додати повідомлення або якийсь спеціальний заголовок у вашому протоколі зв'язку, який дозволить вам перенастроїти своїх клієнтів (для врівноваження частоти навантаження та інших значень, пов'язаних із зв’язком).

Клієнтські перевірки достатньо, якщо ви не заперечуєте, щоб обдурювачі, хакери та інші автоматизовані сценарії атакували вашу гру. Сервер може просто відмовитись від вашої дії та надіслати повідомлення про помилку з деякими деталями. Ви обробляєте це повідомлення про помилку, відкочуючи локальні зміни або не застосовуючи їх до свого локального сховища, якщо ви можете зачекати, поки сервер відповість, щоб фактично зберегти зміни.

Ми використовували шаблон команди в нашій грі, щоб дозволити простий та ефективний відкат помилкових або недійсних дій користувача. Команди відтворюються локально, надсилаються до однолітків або переводяться на серверне повідомлення, а потім застосовуються до колег або перевіряються на сервері, у разі проблеми команди не відображаються, а сцена гри повертається у початковий стан із повідомленням.

Використання HTTP не є поганою ідеєю, оскільки пізніше це дозволить вам легко інтегруватися з клієнтами Flash або HTML5, це гнучкість, ви можете використовувати будь-який тип скриптових мов сервера та за допомогою основних методів балансування навантаження додавати більше серверів пізніше без особливих зусиль щоб масштабувати ваш бекенд.

Вам належить багато зробити, але це весела робота ... Тож насолоджуйтесь!


3
+1 для "HTML, ймовірно, досить хороший", тому що він, мабуть, є :).
Джонатан Дікінсон

1
@Coyote: спасибі за те, що ви зайняли час та надали таку детальну відповідь. Дуже подобається вашій ідеї HTTP щодо підтримки підтримки інших клієнтів.
umair

1
Нехай сила буде з вами :)
Coyote

5

Який був би найкращий спосіб синхронізації баз даних сервера та клієнта?

Найпростіший спосіб - реалізувати базу даних як єдиний файл, який ви можете передати. Якщо ви намагаєтеся порівнювати відмінності між базами даних, то це світ болю, і я кажу з досвіду.

Зауважте, що ваш сервер не повинен довіряти рішенням, які приймає клієнт на основі цієї локальної бази даних, оскільки клієнт може це змінити. Він повинен існувати виключно для презентаційних деталей.

Чи повинна подія зберегтись у локальній БД, перш ніж оновити її на сервер?

Ні. Що робити, якщо сервер вирішить, що подія ніколи не відбулася? Клієнт не повинен приймати рішення щодо подій, оскільки клієнту не можна довіряти.

Зауважую, ви також говорите про локальну БД двома способами: один, для "речей, які часто не змінюються", і два, для подій. Вони дійсно не повинні знаходитися в одній базі даних з причин, зазначених вище - ви не хочете починати намагатися об'єднати або розмежувати окремі рядки даних у базах даних. Наприклад, референтна цілісність стає проблемою, коли клієнт має посилання на предмет, який ви вирішили видалити з сервера. Або якщо клієнт змінює рядок і сервер змінює рядок, яка зміна має перевагу, і чому?

Чи слугуватимуть прості HTTP-запити для синхронізації?

Так, якщо вони досить рідкісні або невеликі. HTTP не є пропускною здатністю, тому майте на увазі.

Як дізнатися, які користувачі зараз увійшли? (Один із способів може полягати в тому, щоб клієнт продовжував надсилати запит на сервер через кожні х хвилин, щоб повідомити, що він активний. В іншому випадку вважайте клієнта неактивним).

Якщо ви використовуєте перехідний протокол типу HTTP, то це розумна ідея. Коли сервер отримує повідомлення від клієнта, ви можете оновити час останнього побачення для цього клієнта.

Чи достатньо перевірок на стороні клієнта? Якщо ні, то як відновити дію, якщо сервер щось не перевірив?

Ні, зовсім ні. Клієнт перебуває в руках ворога. Як відновити дію, повністю залежить від того, яким ви вважаєте дію та які наслідки вона може мати. Найпростіший маршрут - це взагалі не виконувати дії, поки сервер не відповість, щоб дозволити це. Трохи складніший маршрут полягає в тому, щоб забезпечити можливість кожної дії відкидати дію та кешувати всі невпізнані дії на клієнті. Коли сервер їх розпізнає, видаліть їх з кешу. Якщо відхилено дію, відкажіть кожну дію у зворотному порядку, аж до відхиленої.


1
Ти впорався. Ви маєте рацію щодо синхронізації БД +1 Клієнт ніколи не повинен змінювати БД самостійно ... Просто зателефонуйте до функцій, які працюють на сервері та оновлюють БД за допомогою логіки гри, а потім отримуйте результати.
Койот

@Kylotan: спасибі за вказівку потоків у моїй моделі
umair

@Kylotan: "Найпростіший спосіб - це реалізувати базу даних як єдиний файл, який ви можете перенести. Якщо ви намагаєтеся порівняти відмінності між базами даних, то це світ болю, і я кажу з досвіду". це означає, що всі дані завантажуються при кожному запуску програми. Є речі, які звичаї змінюються дуже часто, тому завантажувати їх може неприйнятно кожен раз. Це також значно збільшить час запуску програми. Будь-які думки?
umair

Якщо даних мало, то проблема відходить. Я був би здивований, якби ваша централізована база даних статичних даних була дуже великою. Але в будь-якому випадку, якщо ви розділите статичні дані на більш дрібні частини, тоді вам потрібно надіслати лише ті, що змінилися з минулого разу. Звичайно, ви можете це зробити на кожному рядку, якщо ви бажаєте зберігати час модифікації в кожному рядку. Як правило, я вважаю за краще статичні дані поза реляційною БД, щоб я міг легко їх перезаписати.
Килотан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.