Компания
1 683,14
рейтинг
5 февраля 2015 в 12:32

Разработка → За кулисами закрытого бета-тестирования Skyforge



Сегодня я хочу рассказать о первой части закрытого бета-тестирования (ЗБТ) Skyforge. Это уже не первое ЗБТ, но зато оно стало самым массовым. Большинство игроков составляют не сотрудники компании и их друзья, а поклонники игры, выбранные случайно из числа зарегистрировавшихся для участия в тесте, а так же купившие или выигравшие наборы раннего доступа. С вечера пятницы, 6 февраля, и до конца выходных будет организован специальный бета-уикенд, во время которого доступ на ЗБТ будет открыт всем пользователям, имеющим аккаунт в почте Mail.Ru. Этот пост носит повествовательный характер и передаёт мою личную точку зрения на происходившие до и во время ЗБТ события.

Подготовка к ЗБТ


Самые первые тесты Skyforge проводились исключительно внутри команды разработчиков, всё делали своими силами. С течением времени игра становилась стабильнее, соответственно, и расширялся круг лиц, допущенных к тестированию. Сперва мы показали игру коллегам по Allods Team. Затем — игровому департаменту Mail.Ru Group. Потом — всему коллективу компании. Начиная с этого этапа, все тесты уже проводились отдельной командой — командой оперирования. Внешние тесты шли на стенде, который готовился к проведению ЗБТ и, впоследствии, ОБТ.

Для того чтобы закрытое бета-тестирование было продуктивным, мы тщательно готовили нашу инфраструктуру. Проводили нагрузочные тесты на серверах ЗБТ, настраивали сбор различных метрик, приём крашей, анализ логов и многое другое. И вот, когда всё было готово, мы открыли заслонку и впустили первых реальных пользователей.

Первые мгновения


Как только начали заходить игроки, мы сразу стали искать трансляцию на Twitch, чтобы увидеть реакцию пользователей, понять, насколько хорошо справляется сервер, да и просто из любопытства. Большая часть студии смотрела трансляцию ничего не подозревающего геймера, а какие-то советы на правах обычного пользователя ему давал даже директор по качеству. Мы начали получать первые отчёты с боевых серверов — проблемы с авторизацией на веб-портале, краши клиента, ошибки подключения отдельных игроков. Но, в целом, старт прошел успешно: аккаунт-сервер справился, а сервера игровой механики не тормозили. Что, впрочем, неудивительно, потому что мощности железа, по нашим данным, должно было хватить и на куда большее число пользователей.

Патчим на живую


Нам повезло, что сервер Skyforge написан на Java. Этот язык нативно поддерживает механизм HotSwap, горячую замену кода без остановки приложения. Мы даже написали специальную утилиту, которая пробегает по ним и патчит. Этот инструмент пригодился нам уже во время старта ЗБТ. Когда мы поняли, что у нас есть баг при загрузке пользовательских аватарок для чатика, то просто закомментировали данную функциональность.



Для пользователей потеря аватарки осталась почти незамеченной, зато некоторым серверам жить стало значительно легче. В следующем же патче эту функциональность выключили сразу.

В принципе, техника точечного патчевания настолько же крута, насколько и страшна, и без полной уверенности в успехе ею лучше не пользоваться.

Трудности клиента


С точки зрения тестирования серверу, к счастью, повезло гораздо больше, чем клиенту. Мы знаем спецификацию железа, на котором сервер будет работать, знаем точное окружение, сами задаём настройки. Клиенту в этом плане гораздо сложнее. В ходе разработки у нас есть 10-20-30 различных конфигураций ПК, на котором запускается клиент. Это компьютеры самих разработчиков. После выхода в свет количество конфигураций идет на тысячи. И у каждой из них могут быть свои особенности: экзотические драйверы, видеокарты и прочие компоненты. Поэтому первая волна новых игроков стала жертвой массовых крашей и проблем с производительностью. Но благодаря нашей системе сбора статистики по железу и производительности удалось оперативно внести необходимые улучшения. Сейчас вся работа команды также направлена на улучшение стабильности и увеличение FPS.



Именно по таким тепловым картам мы оцениваем FPS игроков на открытых зонах.

Трудности сервера


Выход тестирования за пределы круга друзей и членов семьи познакомил команду сервера с некоторыми странностями реального мира. Так, например, несколько пользователей страдали из-за особенностей своей сетевой инфраструктуры — новому соединению доставался новый внешний IP. Таким образом, когда игрок телепортировался с одной карты на другую, у него менялся IP. И мы его честно отключали от сервера, т.к. считали эту ситуацию невалидной. Но уже после нескольких поставленных тикетов пришлось отключить проверку IP в рамках одной игровой сессии как излишне параноидальную. Другие проверки валидности пользователя мы оставили.

Если вы читали статью про архитектуру нашего сервера, то знаете, что он состоит из множества распределенных серверов, каждый из которых живет на своём хосте и выполняет определённую роль: сервер авторизации, сервер игровой механики, сервер баз данных и так далее. При разработке мы старались делать так, чтобы падение отдельно взятого сервера не было фатальным и большинство пользователей могли продолжать играть. Но реальность оказалась жестче, чем мы думали.



Иногда сервера падают целыми стойками. Первый раз нам «повезло», когда полностью обесточилась стойка с порталом и несколькими серверами игровой механики. Мы считали, что игроки поведут себя так: те, кому не повезло оказаться на обесточенных серверах, спокойно перезаходят в игру и продолжают играть дальше, правда, потеряв прогресс прохождения персональных карт, которые остались на умершей механике. К сожалению, так как выключение было нештатным и хосты механик пропали полностью, сервер-координатор не получил сообщение о разрыве соединения. Лично для меня это было не самое ожидаемое поведение TCP keep-alive. Оказалось, что keep-alive начинает отправлять пакеты по неактивным TCP-соединениям по истечении некоторого (по умолчанию — очень длительного) таймаута. Это сделано для того, чтобы не захламлять канал, когда всё хорошо. В принципе, можно было выставить значение таймаута для каждого подключения индивидуально, но для этого бы потребовались грязные хаки. Поэтому мы договорились сделать своё решение: простой механизм пинг-понг опроса серверов. Его плюс в том, что админы на удаленных территориях не смогут его случайно отключить, в отличие от TCP keep-alive, а мы можем отключать серверы, которые ушли, например, в серию Full GC.

После того как мы обсудили эту идею, договорились реализовать её до ОБТ. Всё-таки не каждый день хосты обесточиваются.



Когда мы в режиме реального времени увидели указанный выше график, то подумали, что резкое падение количества активных пользователей — это признак окончания рабочего дня. Но оказалось, что упал хост с механикой номер 13. Два падения за неделю — это все ещё совпадение. Но уже значительная часть команды сервера изучает логи, где и что можно улучшить в консерватории. И вот тут, в последнюю пятницу года, за несколько часов до корпоратива, хост с механикой номер 13 падает опять. А впереди Новый Год и 12 дней праздников, которые хочется провести вдали от работы. Решили-таки отключить несчастливую механику. И с тех пор подобных инцидентов больше не было. Но чтобы Новый Год прошёл спокойнее и падение отдельных механик не приводило к срочным профилактическим работам, мы в тот же корпоративный вечер приготовили первую версию фикса. Тестировали мы её по-честному: запускали на локальных ПК распределённую версию сервера и выдёргивали провод питания из механической части. Фикс был признан рабочим и ушёл на боевые во время последних профилактических работ 2014 года. Новогодние праздники в итоге прошли спокойно.

Ошибка 107


107 — именно такой код у ошибки превышения тайм-аута при подключении к серверу. Эта ошибка, к сожалению, получила широкую известность среди игроков, участвующих в ЗБТ. И с ней связано сразу несколько довольно интересных фактов.

Баг, или даже баги, приводящие к ошибке 107, были внесены в сетевой движок довольно давно — за несколько месяцев до старта ЗБТ. И первыми об таймаут споткнулись боты. Но тогда был то ли дефицит времени, то ли я не смог разобраться с причинами, но в ботах в итоге просто отключили всяческие таймауты. В результате баг, к несчастью, доехал до боевых.

Дальше мы стали свидетелями того, как несколько активных пользователей могут создать иллюзию важности той или иной проблемы. Ошибка 107, как показало исследование, могла возникнуть только у пользователей, имеющих пинг в районе ~3 мс, причём вместе с обработкой в коде, как на сервере, так и на клиенте. К сожалению, фикс только ухудшил ситуацию: исчезновение ошибки было отмечено у очень небольшого процента пользователей, зато она появилась у гораздо большего числа игроков.

Это были пользователи, которые играют в Skyforge через 3G/4G-модемы и/или слабые ПК. Мы никак не могли повторить этот новый баг локально. К счастью, у нас есть боты. Мы включили в них таймауты и починили код их обработки, сразу же получив просто вал ошибок 107. Дальше починить баг было уже делом техники. После выдачи фикса на боевую популярность ошибки 107 сошла почти на нет. Сейчас есть всего 1 незакрытая жалоба.

На самом деле было сразу несколько причин ошибок 107:
  • слишком хорошее сетевое подключение и быстрый клиент (пинг < 3 мс);
  • нестабильный и/или плохой пинг (3G- и 4G-модемы);
  • медленные клиенты или слишком большая общая загруженность системы (копирование файлов);
  • счастливые обладатели CD/DVD-ROM (при старте клиент собирает статистику о железе).

Урок ошибки 107 в очередной раз показал, как важно исследовать не до конца понятное поведение в системе. А также — как важно иметь на руках объективную статистику по распространению тех или иных ошибок у игроков. Такая статистика, кстати, должна появиться уже к старту ОБТ.

Сухая статистика о прогрессе игроков, принявших участие в тестировании:

X — Регистраций всего
0.96*X — Z1. Остров Данкит
0.84*X — Z2. Раскопки Исолы
0.58*X — Z3. Ланберский лес
0.37*X — Z4. Остров Наори
0.11*X — Z5. Миленские пещеры

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

На правах заключения


Закрытое бета-тестирование — это один из важнейших этапов перед запуском игры для широкой аудитории. На мой взгляд, наша команда справилась с прошедшим этапом ЗБТ вполне достойно. Хочу поблагодарить всех пользователей, принявших и принимающих участие в ЗБТ, ваши репорты помогают делать игру лучше. А также приглашаю всех на стресс-уикэнд. Надеюсь, что вместе у нас получится заставить сервер трещать по швам :)
Автор: @Jimilian

Комментарии (21)

  • +5
    Играл с самого начала ЗБТ.
    Очень интересно побывать на «кухне» игры, спасибо :)
  • +4
    Интересная статья!

    P.S.
    А будут ли еще статьи про графику?
    • +1
      Спасибо!

      У нас нет каких-то планов по написанию статей. Захотел — написал. Попросили — написал. Поэтому я не обладаю никакой инсайдерской информацией на эту тему. Поэтому только SergeyMakeev знает, будет он еще писать или нет.
  • +1
    > На самом деле было сразу несколько причин ошибок 107:
    > — слишком хорошее сетевое подключение и быстрый клиент (пинг < 3 мс);
    Посмеялся. Как это вообще так? Я в упор не представляю, как от слишком хорошего подключения мог оказаться превышен таймаут.
    • +1
      Это баг, вызванный гонкой состояний в масштабах клиента и сервера. Представьте, что клиент посылает две команды, при этом клиент ожидает, что после первой команды сетевой поток, его обслуживающий, успел переключиться в нужный для второй команды режим. Но при хорошем подключении две команды идут так быстро, что сервер не поспевает. И получает второе сообщение в невалидном состоянии. Лечится, как правило, путём добавления сообщения-ответа в духе «состояние переключил — давай следующее сообщение».
      • +2
        Ошибка на уровне протокола, нехорошо как-то.
        • +2
          Да, протокол входа в игру был не очень надежен. Именно для того, чтобы находить такие баги, и были заведены таймауты. Если мы в стейт-машине входа в игру не переходим из одного состояния в другое слишком долго, то оповещаем об этом игрока и «выходим».
          Старый «движок» входа в игру понравился бы вам еще меньше, поэтому мы его и переписали, добавив диагностики и таймаутов. Раньше можно было застрять в каком-то состоянии навсегда.
          • +1
            Может вы ещё и производительность клиента намерянно снижаете и пинги удлинняете?) В skyforge вообще интересно обстоят дела с пингом. Все сервера (которые попросила пропинговать тех. поддержка) пингуются в 26мс, в игре наблюдаю от 35 до 100. Может счётчик врёт, потому, что лаги можно наблюдать при любом значении пинга. Ну и странно видеть увеличение пинга при проседании ФПСа.
            • +1
              Пинг, который вы видите в игре — это не то же самое, что результат выполнения команды ping. Это сериализация + отправка + пересылка + прием + десереализация сообщения. Я сейчас посмотрел график латенси с идущего прямо сейчас стресс-теста:
              95 перцентиль — ~110 мс.
              90 перцентиль — ~86 мс.
              80 перцентиль — ~60 мс.
              70 перцентиль — ~ 43 мс.
              50 перцентиль — ~ 23 мс.

              И так далее. Т.е. в принципе, ваши ощущения верны. У значительного числа пользователей разброс от 35 до 100.
              Так же верны ваши наблюдения, что при падении ФПС падает пинг — мы работаем медленнее, медленнее отправляет и принимаем сообщения.

              Наши механики отлично должны себя чувствовать до 300мс. У нас есть различные механизмы компенсации пинга, чтобы бой смотрел и игрался хорошо.
              • +1
                Тогда в вашей архитектуре фатальный недостаток. То, что ФПС и пинг держится на приемлемом уровне 99% времени — это ничто по сравнеию с оставшимся процентом, который случается всегда ВНЕЗАПНО и в критических моментах приводит к фатальным последствиям. Телепортируешься(скилом) уже мёртвым, ульта срабатывает после смерти, мобы убивают последним хитом, после того как они были сами убиты. Не вижу никакой предсказуемой связи между отображением и работой механики, либо она не работает как задумывалось.

                На примере паладина — это приводит к тому самому эффекту метронома, о котором писалось в одной из ваших предыдущих публикациях. Я не могу ориентироваться на картинку на экране, т.к. вижу рваный ритм СКАЧУЩЕГО «пинга» и мне приходится самому быть механизмом его компенсации.

                Если честно, не очень понимаю, как связана графика и механика. Почему «пинг» не сокращается и скачет, когда ФПС высокий, т.е. всё успевает отрабатываться с высокой скоростью и в игре в данный момент ничего не происходит, т.е. я стою один в пустом инстансе и просто кручу камеру?

                Пока что я вижу приоритет графики над здравым смыслом и пингом. А пока игра для топовых конфигураций и толстых каналов. Но так как она мне понравилась, я мирюсь с этими косяками и надеюсь вы успешно победите все эти косяки и отполируете шероховатости.
                • +1
                  Мы могли бы показывать игроку пинг до нашего датацентра, на который мы никак повлиять не можем. Тогда бы он был стабильный и не вызывал вопросов. Но это было бы ложное ощущение, т.к. качество обслуживания могло не соответствовать указанному значения. Мы же показываем «честный пинг»: реальную задержку между применением команды и получением результата. Это тот параметр, над улучшением которого мы можем работать.

                  Почему «пинг» не сокращается

                  Как я писал выше, значение «пинга» — это сумма нескольких слагаемых. FPS, а точнее производительность клиента, может влиять только на сериализацию. Поэтому можно легко загнать один из слагаемых в гору, значительно увеличив сумму, но, уменьшив его до минимума, не получить явной выгоды, т.к. остальные слагаемые никуда не делись.
                  Кстати, на днях мы заметили, что включенный в фоновом режиме uTorrent может задирать «пинг» до 4к. Правда, пока мы не знаем точных причин.

                  Телепортируешься(скилом) уже мёртвым, ульта срабатывает после смерти, мобы убивают последним хитом, после того как они были сами убиты.

                  А вот эти все проблемы могут быть как связаны с пингом, так и быть отдельными. Например, сервер честно прислал сообщение клиенту и уже отработал его, но рендер не успел показать, что аватар умер. Или интерфейс послал команду с запозданием. Я понимаю, что вам, как конечному пользователю не очень интересна причина бага. Просто хочу объяснить, что не «пингом» единым.

                  я мирюсь с этими косяками и надеюсь вы успешно победите все эти косяки и отполируете шероховатости

                  Спасибо за добрый отзыв.
                  • +2
                    Кстати, на днях мы заметили, что включенный в фоновом режиме uTorrent может задирать «пинг» до 4к. Правда, пока мы не знаем точных причин.

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

                    • +1
                      Очень хороший вопрос. Передам его коллегам на изучение — сам я в отпуске почти :)
      • +1
        Симптомы похожи на гонку состояний, да, но ваш ответ как будто бы о чем-то другом. Пусть пакет доходит от клиента к серверу аж за 500 мс — все равно обе команды дойдут до сервера за одно и то же время, разве нет? Единственная ситуация, в которой это будет не так — нестабильный пинг, тогда первая команда дойдет за 50 мс, а вторая уже за 55 мс, скажем. При этом в статье сказано, что нестабильный пинг тоже к таймауту приводит, хотя как раз при нестабильном пинге эта гонка и не должна возникать…
        • +2
          Как это было:
          • Клиент отправляет сообщение_1
          • Сообщение_1 доходит за время t0
          • Сервер получает сообщение_1 и переключает состояние сетевого подключения за t1
          • Спустя dt после отправки сообщения_1 клиент отправляет сообщение_2
          • Сообщение_2 доходит за время t2

          Если (t2 + dt) > t1, то всё было хорошо. Иначе сообщение_2 приходило в момент, когда его никто не мог корректно обработать.

          Это был самый первый баг ошибки 107, которому были подвержены пользователи с маленьким пингом и быстрым клиентом.
          • +1
            А пофиксить пытались на скорую руку добавив задержку? И это привело к проблемам у пользователей с медленным соединением?
            • +2
              Нет, конечно. Мы не чиним race condition добавлением sleep. Мы так только дебажимся :) Хотя в данном случае, sleep отработал бы лучше.

              Мы добавили сообщение-уведомление для сервера, что клиент посылает следующее сообщение в новом состоянии. Чтобы сервер явно переключил сетевое соединение в нужное нам состояние. Проблема была в том, что на медленных соединениях TCP любезно склеивал пакеты «переключи состояние» и следующее сообщение, и они приходили в рамках одного тика сервера. Сервер же не мог отработать в рамках одного состояния два сообщения, предназначенные для двух разных состояний. Но я согласен, что фиксили на скорую руку. Потому что не предусмотрели все варианты развития событий. Простым добавлением в клиент ожидания подтверждения от сервера о переходе в нужное состояние удалось пофиксить таймаут в этом месте еще раз.
          • +1
            Что мешает серверу не обрабатывать команду 2, пока команда 1 не отработала и не переключила стейт-машину в нужное состояние? Команда 2 может спокойно подождать в очереди.
            • +1
              Серверу, чтобы понять, какая команда что значит, нужно сперва превратить поток байтов во что-то вразумительное. Проблема в том, что для команды 1 и для команды 2 нужны разные способы десериализации. Т.е. команду 2 мы пытаемся десериализовать неправильным способом и получает какую-то фигню вместо команды. Поэтому мы не можем понять, что это была команда 2.
              • 0
                Даже если так, можно складывать в очередь команду в виде массива байтов и парсить опять же после переключения стейта в результате выполнения 1-й команды. Но вообще звучит как ужасный дизайн протокола, сложно представить разумную причину для такого решения — можете пояснить для чего так сделано?
                • +1
                  Зачем делать очередь? Можно просто добавить пару-тройку сообщение для того, чтобы строго определить, кто и когда переключил стейт. Да, это понизит скорость подключения на пару пингов до сервера и обратно, но это копейки по сравнению с загрузкой сцены. То, что такой синхронизации не было изначально — просто баг. А не злое намерение или преждевременная оптимизация. Код отлично работал несколько месяцев, в том числе в нагрузочных теста, пока не оказался на боевых.

                  К сожалению, я не понял, что именно вы считаете «ужасным дизайном протокола»?
                  Разделение всех сообщений от клиента на две группы? Условно их можно назвать «до того, как игрок вошел в мир» и «после того, как игрок оказался в мире». И, скажем так, для них действуют разные контракты.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Самое читаемое Разработка