Замедление времени
Часто говорится, что война против лагов не может быть выиграна, поскольку наши игроки всегда могут привести еще один корабль. Это, по существу, верно, и принятие этой истины важно для работы, которую мы выполняем в команде Gridlock (”затор”). В дополнение к работам по оптимизации, выполняемых нами, мы также боремся с проблемами деградации, чтобы, в случае перегруженности сервера, она обрабатывалась разумным способом. Именно об этом сегодняшний блог. Но, чтобы понять, куда мы движемся, нужно знать, где мы сейчас. В настоящее время, при перегруженности сервера нет никакого явного механизма для обработки такой ситуации. Те же самые механизмы, которые обеспечивают нормальное функционирование, продолжают двигаться собственным ходом. В результате возникает интересное поведение, но мне нужно определить некоторые термины, прежде чем я углублюсь в обсуждение.
Об tasklet’ах, планировщиках, и уступке
Серверы EVE Online, в целом, существуют, чтобы выполнять набор задач – будь это ответ на поступающий от клиента пакет, задача, поддерживающая состояние модулей или, в общем, почти всё. Их называют tasklet’ами, по причинам, о которых вам сегодня знать не потребуется. Так как мы имеем дело с компьютером, только один tasklet может выполнятся в любой момент времени, и должна существовать такая часть программного обеспечения, которая бы решала, какой именно tasklet это должен быть. Эта часть называется планировщиком.
Планировщики бывают совершенно разнообразные. Тот, который управляет tasklet’ами EVE Online довольно прост – это циклический, совместно-многозадачный планировщик. Цикличность означает, что каждому tasklet’у дадут возможность выполнится прежде, чем любому tasklet’y дадут две возможности. Нет никакого установления приоритетов, или специальной обработки - это очень справедливо в том смысле, что каждый получает в свою очередь. Совместная многозадачность означает, что никакой tasklet не будет прерван извне во время его исполнения. Tasklet будет выполняться вплоть до того, как завершиться, либо до вызова специальной функции, которая сигнализирует планировщику, что tasklet желает передать возможность выполниться всем остальным. Это называется уступкой.
Таким образом, то, что мы имеем, является примерно такой системой:
Вы могли задаться вопросом - "Почему tasklet будет когда-либо уступать?" Ну, если бы они были эгоистичны, они бы так не делали, они держались бы изо всех сил, и выполняли бы всё, что хотят завершить, прежде чем позволить любому из тех, других, очевидно, менее важных растяп сделать попытку. Но такой подход работает не очень хорошо ... лишение всех остальных ресурсов центрального процессора - плохая идея для всех вовлеченных. Поэтому, когда мы кодируем систему, и ожидаем, что операция может занять много времени на выполнение, мы вставляем уступки в удобных точках, чтобы она вела себя хорошо с другими.
Другой распространённой причиной, по которой tasklet уступает, является ожидание некоторого ввода от другой машины, например базы данных. Нет никакого смысла сидеть и постоянно спрашивать "оно уже вернулось?" снова и снова и снова - мы можем позволить другим tasklet’ам делать свою работу, пока мы ждём. (Да, технари, это – состояние приостановки, до сигнала о завершении операции ввода/вывода, но остальным это знать не интересно).
Да, чувак, к чему это ты клонишь ?
Извините, мне нравиться писать о компьютерных вещицах. Клоню к объяснению поведения tasklet’ов при большой нагрузке. Если сервер перегружен, то может пройти пять или более секунд, до получения возможности что-либо сделать, после того как ты уступил. Результатом всего этого является то, что задачи, которые либо очень благовоспитанны, или имеют многочисленные требования по взаимодействию, могут, в конечном итоге, завершаться адски длительно, поскольку они проводят большую часть своего времени в ожидании очереди на выполнение. Уничтожение корабля является великолепным примером - требуется множество запросов к базе данных, поэтому tasklet уступает очень часто, в результате чего событие растягивается на несколько минут, прежде чем, наконец, завершится. Схожим образом, модули также могут очень замедлиться в обработке, так как tasklet, который управляет ими, уступает после 100 миллисекунд выполнения.
Я рассказываю вам всё это для того, чтобы мотивировать следующее заявления:
Сервер EVE Online [под нагрузкой] должен деградировать таким образом, чтобы очередь tasklet’ов, ожидающих исполнения, была минимальной – в идеале нулевой.
Именно на это и нацеливается Замедление Времени.
Для того, чтобы привести все вещи к уровню, при котором сервер будет справляться, существует болезненно мало вариантов. Они сводятся к двум: снижение нагрузки, или увеличение обрабатывающих мощностей.
Команда Gridlock, на сегодняшний день, использовала много времени для снижения нагрузки с помощью оптимизации. Мы можем продвинуться по этому пути и дальше – и, вероятно, сделаем именно так, - но мы находимся в точке, где большинство легких побед уже позади. Переход к многопоточности относится к категории увеличения мощностей – он увеличивает нагрузку, которая может быть обработана за секунду, но не настолько много, как многие считают. Мы доберёмся и до многопоточности, потому что, ну, мы должны. Но на сегодня это слишком большой объём работы, по сравнению с ожидаемым выигрышем от неё, чтобы атаковать именно здесь.
Регулировка нагрузки выглядит гораздо более привлекательным предложением на данный момент, теперь, когда мы разобрались с кучей легких оптимизации. Были выдвинуты несколько различных предложений о том, что можно было бы сделать. Одно, которое предлагалось большинством в первую очередь – это переход к более низкому разрешению, нежели один раз в секунду, в Destiny, нашей системе моделирования физики, при возникновении перегрузки. Это помогло бы снизить нагрузку выполнения моделирования, но, как оказалось, она составляет только 5-10% от нагрузки, поэтому много мы бы не выиграли.
Еще одна распространенная идея заключается в увеличении времени цикла модуля, при пропорциональном повышении их эффективности и расходе. Это дало бы нам больший запас, но меняло бы игру очень глубоко в зависимости от того, какова нагрузка. А вот это действительно не круто. Нынешняя схема деградации также меняет поведение игровой механики, и мы хотели бы уйти от этого, вместо того, чтобы усугублять.
К счастью, у нас есть средство, чтобы регулировать нагрузку, которая даёт нам преимущества, оставляя нетронутым дизайн: сделать время бегущим медленнее. Подавляющее большинство нагрузки в больших схватках привязаны ко времени - модули, физика, перелёты, отварпы, все эти вещи случаются в течение некоторого периода времени, так что замедление времени пропорционально снизит вызываемые ими нагрузки. Таким образом, идея состоит в замедлении внутриигрового времени настолько, чтобы поддерживать очень небольшую очередь ожидания tasklet’ов, а затем, при снижении нагрузки, ускорении времени вплоть до нормального, по мере того, как мы справляемся с нагрузкой. Это будет выполняться на лету, и очень маленькими шажками; нет никаких причин, по которым мы не можем работать на 98% времени, если мы просто немного перегружены.
Хорошо конечно, но как вы себе это представляет во время большого боя?
Вот как я себе это представляю в время большого сражения (к примеру, 1600 или около того). Когда атакующий флот приварпывает, сервер становится сильно перегружен – варп и другие подготовительное задачи, к примеру, выпуск дронов, довольно дороги – и игровое время чрезвычайно замедляется, до 5% реального времени. Как только эти задачи выполняются, у сервера возникает достаточный резерв для безопасного сокращения коэффициента замедления до 30% нормального времени, и к схватке присоединяются должным образом. К этому моменту, у нас 1600 активно противоборствующих пилотов, с быстрым и справедливым подтверждением запросов, но просто используется в 3 раза больше времени, чем обычно. Игроки во флотах могут заметить это, потому что замедлилась анимация элементов управления кораблём, и взрывы в космосе происходят как будто в замедленной съёмке. По мере того, как всё больше кораблей уничтожаются/улепётывают, нагрузка, вызываемая сражением, снижается, и, по достижении около 1200 участников, оценивая-предугадывая, мы вернёмся к 60% нормального времени. Может быть в этот момент один из командиров понимает, что проигрывает, и приказывает отступать. Отварп также дорог, поэтому часы замедляются, скажем, до 10%, пока флот сматывается. С завершением битвы, и уходом проигравших, нагрузка на сервер становится малой, и он возвращается к 100% времени.
Во всём этом есть сложные моменты, конечно, например, что делать с длинными таймерами и им подобным. Я думаю, с большинством этих случаев довольно легко разобраться. Если мы замедлим таймеры реинфорса, это открывает возможность для игроков войти в момент истечения реинфорса, что идёт вразрез с их целью. Так что таймеры реинфорса не замедляются. С другой стороны, восстановление щита может занять некоторое время, но крайне важно для протекания боя, так что должно быть замедленно. Эмпирическим правилом для меня является то, что если вы смотрите на ваши часы, чтобы узнать, когда произойдёт завершение, то это не должно замедляться. Если вы можете придумать случай, для которого этот подход будет неприменимым, пожалуйста отметьте его в теме с комментариями к этому блогу.
Время управлять ожиданиями !
Замедление времени не решает всех вопросов. Некоторые нагрузки не привязаны к продолжительному времени, поэтому у нас не будет возможности обрабатывать бои бесконечного размера. Сегодня мы находимся в точке, в которой это будет охватывать все, что мы видим на регулярной основе. Я думаю, однако, мы должны будем поставить жесткое ограничение на то, как сильно мы готовы замедляться. Нет смысла в замедлении системы до 0,1% времени, поскольку никто не сможет ничего сделать, и это ни к чему не приведёт. Я не знаю, где будет этот порог - это то, с чем мы должны будем поиграться после развертывания. Если бои будут постоянно превосходить этот порог, каким бы он не был выставлен, мы окажемся ровно там же, где и сегодня – с сервером, становящимся невосприимчивым, противным, и прочим. Посмотрим.
Это был довольно длинный блог, всё, что здесь сказано – это супер-предварительно. Это была идея, всплывшая на моём радаре уже давно, но пока по ней выполнено не так много фактической работы, на настоящее время. Мы сделали прототип еще в августе, чтобы доказать, что игра может работать с замедленным временем, и он остался ровно на этом этапе. Положительные отзывы после упоминания идеи на фанфесте, в сочетании с освещением этой идеи CSM’ами как стоящей на вершине текущего списка их пожеланий убедили меня, что это идея, время которой пришло. Это довольно большой проект, так что я практически уверен, что она не будет реализована этим летом. Осень – весьма вероятно, если дела пойдут хорошо.
Короткая версия блога:
Замедление времени замедляет время так, чтобы сервер мог справляться со всем, что вы все там делаете. Мы собираемся поработать над этим, и если всё сработает, вы увидите всё это, но не совсем скоро.
--------
Выборочные посты CCP Veritas в теме с обсуждением:
#1
McThife: Мне не понравилось, как вы отбросили вариант с многопоточностю. Работа в многопоточных средах на различных платформах с различными серверами приложений показывает, что многопоточность в системах с высокой нагрузкой является решением №1. Я знаю, что это, вероятно, не самая простая вещь для воплощения, и движок EvE, вероятно, архитектурно построен вокруг однопоточной модели, но, пожалуйста, не говорите, что этот подход не дал бы выигрыша.
CCP Veritas: Я лишь сказал, что он не дал бы такого большого выигрыша, как многие думают. Переход к, скажем, 4-ём потокам не учетверяет производительность, за исключением ошеломляюще лёгких случаев. С накладными расходами, и требующимися блокировками, нам сильно повезёт, если мы получим 2х-3х кратный прирост производительности при 4-ёх потоках.
Учитывая количество усилий, которые необходимо предпринять, чтобы это реализовать, и последующих усилиях на поддержку многопоточного кода, это не будет лучшим планом прямо сейчас. Мы это неизбежно сделаем, через какое-то время. По этому пути сейчас идут очень многие.
#2
fossura: Какого размера будет зона, испытывающая эффект замедления, будет ли это грид, в котором происходит бой в системе, и т.д. Интересует вопрос, если битва длится в 5 раз дольше обычного, даст ли это одной из сторон преимущество в возможности привести подкрепления, и можно ли вызвать такой эффект по желанию, к примеру, группируя оружие и выпуская/отзывая дронов всем флотом ?
CCP Veritas: В первой реализации все локации на узле будут замедлены. Для выделенненных узлов, это будет лишь система, вызывающая нагрузку. Для разделяемых узлов - все системы на узле будут замедленны. Несколько вещей должны занять своё место, прежде чем я смогу безопасно реализовать отдельное течение времени для каждой системы, но это, безусловно, необходимо
Сообщение отредактировал prototype: 24 April 2011 - 11:05