Слово инженерам: воссоздание войны в Ан'Кираже

Blizzard Entertainment, August 20th в 5:00pm

Началась война. В этом месяце состоялся выход одного из самых ожидаемых событий в World of Warcraft: Classic — войны в Ан'Кираже. Целые игровые миры Classic — объединенная мощь Орды и Альянса — работали сообща, собирая ресурсы для открытия врат Ан'Киража и получения доступа к рейдам. В 2006 г., когда война Зыбучих песков началась в первый (и единственный) раз, тысячи игроков в каждом игровом мире устремились в Силитус — кто по земле, а кто по воздуху — чтобы поучаствовать в бурных событиях или хотя бы понаблюдать за ними. Количество участников события превзошло все ожидания команды разработчиков. Проще говоря, мы были не готовы. Сервера быстро оказались перегружены, и многие из игроков застряли в бесконечном цикле из попыток зайти в игру, разрывов соединения и новых попыток вернуться. Это длилось в течение 12 часов, пока наши инженеры в срочном порядке готовили исправления, чтобы помочь игрокам войти в игру. Хотя мы смогли стабилизировать работу серверов во время события и усвоили несколько важных уроков, мы решили, что в следующий раз справимся лучше. Спустя 15 лет мы начали подготовку к воссозданию одного из самых захватывающих событий в истории WoW для WoW Classic. Мы сосредоточились на оптимизации работы серверов в целях борьбы с задержками и нарушениями в работе, при этом вдвое увеличив возможное число игроков в Силитусе по сравнению с 2006 г.

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

Воссоздание второй войны Зыбучих песков

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

Вторжение анубисатов в Азерот

Преодоление границ

Современная версия World of Warcraft создана на основе выпущенной 15 лет назад кодовой базы. За это время мы разработали более современные способы решения вопросов, связанных с чрезмерной численностью игроков в игровых мирах в Battle for Azeroth, самый важный из которых — технология фрагментации. Благодаря фрагментации серверы WoW способны обеспечивать игру большего числа игроков, чем в 2006 г. В Battle for Azeroth мы применяем эту технологию для управления нагрузкой на серверы путем создания новой копии зоны (например, Зулдазара), когда количество игроков в ней превышает определенный порог. При помощи распределения игроков по нескольким версиям одной зоны мы препятствуем возникновению задержек, поскольку именно взаимодействие игроков приводит к наибольшей нагрузке на вычислительные мощности из-за обмена огромным количеством пакетов, обеспечивающего точную обработку данных о передвижении и применении заклинаний. Кроме того, технология фрагментации устраняет возможные задержки, возникающие при переходе в новую зону, где число игроков достигло максимума. Звучит все просто, но есть подвох — для WoW Classic были достоверно воссозданы все данные версии 1.12, в том числе и особенности игрового процесса. В редких случаях из-за фрагментации ваша цель — будь то вражеский игрок или NPC — может исчезнуть при переходе в новую зону. Если бы мы оставили фрагментацию в игре, то лишили бы игроков памятных моментов, таких как следование за NPC или другими игроками из одной зоны в другую. Поэтому нам было необходимо придумать такое решение, которое не нарушало бы игровой процесс классической версии игры и в то же время позволило бы нам поддерживать большую численность игроков в одном игровом мире, не вынуждая их играть с жуткими задержками.

Чтобы справиться с этой задачей, мы решили использовать слои — копии целых регионов (например, Восточных королевств) — для контроля населенности игровых миров и предотвращения задержек, а также для сохранения хорошо знакомого обаяния оригинальной версии игры, где игроки могли водить боссов в открытом мире через множество зон и преследовать противников по всему региону без опасений, что их перенесет на разные слои. Тем не менее, слои не предназначались как окончательное решение. Поскольку в оригинальной версии игры 1.12 не было ни фрагментации, ни слоев, мы пообещали, что будем использовать их лишь в период выхода WoW Classic и постепенно избавимся после более равномерного распределения игроков по миру. В настоящее время остается еще несколько игровых миров, где мы по-прежнему используем слои из-за высокой численности игроков (например, североамериканский игровой мир Faerilina), но в этих игровых мирах мы уже уменьшили количество действующих слоев. Минуло уже 15 лет, и война в Ан'Кираже стала одним из самых долгожданных событий WoW Classic. Не считая стартовых зон в день выхода версии Classic, во время этого события мы увидим наибольшее скопление игроков в одной зоне без использования слоев. В отсутствие возможности использования слоев или фрагментации нам нужно было срочно придумать что-то новое.

Сбор игроков вокруг гонга

Создание незабываемых приключений вручную

Мы начали процесс поиска решения вопроса перенаселенности, не задействующего ни слои, ни фрагментацию, с создания автоматизированных клиентов игры, которые имитировали действия реальных игроков — применяли заклинания, сражались с NPC и перемещались по зоне. Благодаря этому мы могли изучить показатели производительности при взаимодействии тысяч игроков в одной зоне. После симуляции мы вместе с добровольцами провели тесты производительности, чтобы сравнить действия автоматизированных клиентов с поведением настоящих игроков. Благодаря этому мы смогли определить конкретные пределы возможностей кода наших серверов и те его элементы, что вызывали больше всего неполадок при высокой загруженности. Мы тщательно изучили результаты тестирования, чтобы определить, насколько в различные промежутки времени показатели производительности сервера были близки к тому, чтобы блокировать обработку запросов. Это называется «взаимная блокировка».

Следующим шагом был анализ причин снижения производительности сервера. Так мы смогли разбить огромную задачу на менее крупные достижимые цели. В процесс было вовлечено огромное количество переменных, и недостаточно было простого улучшения оборудования — в этом случае повышение производительности происходит не пропорционально. Вместо этого нам пришлось вручную оптимизировать работу серверов путем ввода конкретных условий: какие данные необходимо передавать игрокам и как часто. Для иллюстрации этой непростой задачи приведем следующий пример. Представьте, что 20 игроков встали в круг и подпрыгивают. Сервер передает действия каждого игрока остальным 19 игрокам при помощи пакетов, в которых содержатся данные. Для этой группы из 20 человек сервер обрабатывает 380 пакетов (20 игроков * 19 получателей = 380 пакетов). Эта проблема только усугубляется по мере роста числа игроков, совершающих одно и то же действие в одной зоне. Если в нашем примере увеличить количество игроков до 500, то сервер отправляет 249 500 пакетов. Если вновь увеличить число игроков до 1500, то сервер получает 2 248 500 пакетов. В зависимости от действий игроков может отправляться сразу несколько пакетов в секунду — обратите внимание, что в приведенных примерах учитывается только одно действие от каждого игрока. Чем больше пакетов получает сервер, тем дольше становится время обработки действий каждого игрока в отдельности. С нарастанием нагрузки сервер начинает приближаться к состоянию взаимной блокировки. В игровых мирах WoW Classic находится значительно больше игроков, чем в 2006 г., поэтому мы рассчитывали, что понадобится обеспечить одновременную обработку данных еще большего числа игроков у ворот Ан'Киража, чем когда-либо ранее.

Оптимизация работы серверов

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

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

Управление численностью игроков

Помимо оптимизации серверов для поддержки большего количества игроков в одной зоне, мы также не забыли и о том, что в Силитусе просто не поместится все население игрового мира (в котором может быть более чем в два раза больше игроков, чем в оригинальной версии WoW 1.12). Для ограничения доступа к зоне нам пришлось принять непростые решения относительно того, кого мы можем пускать в зону и как много игроков мы будем в ней поддерживать. Мы решили, что в Силитус смогут попасть только персонажи 60-го уровня, и когда зона окажется переполнена, другие игроки не смогут в нее войти. Введение таких ограничений было правильным выбором, поскольку Силитус предназначен для персонажей максимального уровня, а те, кто еще его не достиг, могут поучаствовать в войне и в других зонах — например, убивать анубисатов, бродящих по Степям (таки бои предназначены для игроков от 20-го до 30-го уровня). Кроме того, хотя мы и знали предел численности игроков, которую мы можем поддерживать в одной зоне до прекращения работы серверов, требовалось определить, до какого уровня нужно сократить этот предел, чтобы достичь оптимальных показателей производительности для каждого игрока. По результатам тестирования мы выяснили, что это количество равняется приблизительно 1500 игрокам, если они все собрались в одном месте. Но поскольку событие происходит по всей зоне, то при распределении игроков по ней резкого снижения производительности не наблюдалось.

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

Мы начали разработку этой технологии с проведения состязания рыболовов в Тернистой долине, а также применили ее к положительным эффектам, получаемым за победу над Ониксией, Нефарианом, Хаккаром и Рендом. Когда мы убедились, что все работает корректно, мы были готовы начать тестирование этой и других технологий, которые нам понадобятся для войны в Ан'Кираже.

Игроки Орды в Силитусе

Эксперименты с решениями

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

Во время первого теста производительности мы пустили в зону почти всех игроков, чтобы посмотреть, что будет. В какой-то момент мы достигли численности, составляющей 150% от максимальной населенности целого игрового мира версии 1.12. Тогда и произошло прекращение работы тестового игрового мира. Мы знали, что установили очень высокий предел игроков, которые могут попасть в зону, и результаты тестирования серьезно превышали даже это значение. Изучив причины неполадки, мы поняли, что участок кода, отвечавший за то, чтобы игроки заходили в зону и покидали ее, представлял собой очередь, которая могла обрабатывать лишь малое количество игроков одновременно. По этой причине одни игроки не покидали зону, а другие застревали во время перелетов на чрезмерно долгое время. Мы вновь запустили сервер и продолжили тест производительности, внося поправки по ходу дела. Мы понемногу уменьшали количество игроков до тех пор, пока уровень производительности не достиг терпимого, но с задержками, и в зоне по-прежнему было гораздо больше игроков, чем в какой-либо другой зоне в истории игры. Событие, которое должно было длиться всего полтора часа, из-за прекращения работы сервера заняло до четырех часов.

Второй тест производительности мы провели через неделю. Он позволил оценить результаты работы по оптимизации. Едва запустив тест производительности, мы сразу заметили разницу — игроки больше не застревали во время перелетов в Силитус! Мы смогли собрать достаточно данных, чтобы определить, сколько игроков могло без затруднений находиться в Силитусе. После завершения обоих тестов мы продолжили работу с учетом полученных данных, которые, на наш взгляд, соответствовали оптимальному балансу между задержками и стабильной работой серверов. Благодаря этим тестам мы убедились, что наша работа по оптимизации была плодотворной. Мы считаем оба теста успешными, поскольку благодаря им мы смогли определить максимальный предел игроков в зоне и работать дальше с учетом этой информации.

Введение улучшений по всему Азероту

Изначально мы собирались оптимизировать работу серверов только в Силитусе на время войны Зыбучих песков. Когда мы убедились, что можно без рисков ввести эти улучшения во всех регионах, мы сделали это в обновлении 1.13.5. После начала войны игроки занялись массовым сбором ресурсов и тел насекомых. Мы заметили, что значительно возросло количество игроков не только в Силитусе, но и в столицах и близлежащих зонах. С помощью оптимизации мы смогли улучшить производительность в этих зонах, а также позволить игрокам проводить масштабные PvP-сражения по всему Азероту. Некоторые игроки даже вызывали босса в открытом мире Громораана, чтобы с его помощью прогнать игроков вражеской фракции из какого-либо улья.

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

Как только ресурсы были собраны и прошло пять дней, мы начали наблюдение за китайскими игровыми мирами, игроки которых первыми в мире смогли открыть врата. Первым китайским игровым миром, в котором ударили в гонг, был Ouro. Наблюдая за численностью игроков на различных слоях игрового мира, мы заметили, что большинство игроков каждого слоя находилось в Силитусе. Мы никогда раньше не проводили события на нескольких полностью населенных слоях с тысячами игроков. Хотя в игре и наблюдались задержки, во время открытия врат в первых китайских игровых мирах не произошло ни одного прекращения работы серверов.

Бей в гонг!

4 августа мы определили, что в нескольких североамериканских игровых мирах игроки были готовы ударить в гонг после перезапуска серверов. С помощью учетных записей гейм-мастеров и других средств наблюдения мы тщательно следили за каждым из этих игровых миров и готовились исправить все возможные неполадки. После перезапуска игроки смогли войти в игровые миры и без осложнений начать событие. Владельцы скипетров получили престижное средство передвижения «Черный киражский боевой танк», игроки смогли перейти от истребления мелких жуков к борьбе с крупными, а мы радовались стабильной работе серверов. Ожидая завершения пятидневного отсчета времени в первом игровом мире, мы заметили критическую неполадку: после перезапуска игровых миров события не продолжались. Это означало, что в случае прекращения работы или перезапуска сервера весь прогресс события обнулялся. Хотя эта проблема существовала с самого начала разработки WoW Classic, в игре не так уж часто происходят события, которые должны продолжаться после перезапуска серверов. Наша команда смогла быстро исправить ситуацию, но требовалось удостовериться, что перезапусков серверов больше не будет до тех пор, пока мы не введем исправление и не зафиксируем текущий статус войны во всех игровых мирах в базе данных без остановки игрового процесса.


Кто-то скажет, что прекращение работы серверов привнесло толику хаоса в войну в Ан'Кираже, благодаря чему она и стала такой запоминающейся. Но мы решили создать настолько же незабываемое событие в условиях гораздо более стабильного игрового процесса и совместной игры с 1500 другими игроками в Силитусе в каждом игровом мире. Мы хотели бы, чтобы война в Ан'Кираже запомнилась как 10-часовое событие Classic, в котором без каких-либо затруднений могло участвовать множество игроков. Хотя серверы некоторых игровых миров прекращали работу, мы смогли быстро вернуть их в штатный режим. Эти игровые миры удалось полностью восстановить и вновь открыть к ним доступ за считанные минуты, после чего они работали без осложнений.

Во всех регионах уже более 4000 игроков стали королями-скарабеями, и это число продолжает расти по мере того, как война продолжается в каждом игровом мире. Нас потрясли энтузиазм и интерес, которые игроки Classic проявляют к войне в Ан'Кираже. Спасибо всем, кто участвовал во второй войне Зыбучих песков!