В настоящий момент группа разработчиков Luxoft работает над новым проектом – разработкой online квеста, который позволит программистам не только протестировать свои скиллы, но и окунуться в атмосферу триллера. Подробно о самой игре мы вам расскажем немного позже, 07.10.2012, когда состоится официальный запуск, а сейчас мы хотели бы поделиться с вами чисто техническими подробностями и проблемами, которые мы встретили во время процесса разработки и их решениями.
Самой главной проблемой проекта стало обеспечение безопасности серверов во время игры, т.к. суть квеста заключается в том, чтобы игроки, выполняя задания, выкладывали на сервер свои программы, где они будут впоследствии проверяться. Т.е., запуская программы, мы должны понимать, что они были написаны для решения поставленной задачи и не являются вредоносными файлами.
Итак, мы выявили и сформулировали следующие проблемы:
У нас есть сервер, на котором будет крутиться некоторое программное обеспечение, полученное из внешнего источника, и которое, по факту, неизвестно что будет делать, пока работает;
Есть, в перспективе, большое количество пользоваталей, которые будут заливать на сервак большое количество приложений. Часть из них, вполне возможно, могут оказаться даже вирусами: мы позволим заливать все, начиная от php, заканчивая exe файлами. Проблема похожа, но немного шире: программа может резидентно остаться работать на сервере;
Запускаясь, программы будут выедать огромное количество ресурсов.
Затем, мы приступили к поиску решений:
Как вы понимаете, это не вариант при таких условиях, т.к. сервак однозначно упадет, это вопрос времени. Когда кто-то напишет программу с каким-то жутким багом, или когда кто-то зальет вирус. Тут, кстати, возникает еще одна проблема: можно портить результаты соперников, используя их как свои.
Если бы нашей платформой выступал Linux, это было бы решением. Это было бы хорошим и устойчивым решением, которое бы всех устроило как по стоимости, так и по времени создания. Однако, так исторически сложилось, что наша группа — разработчики .NET и нам чужда эта система. А потому, чтобы не подрывать безопасность сервера своим незнанием тонкостей, было решено остановиться на Windows платформе.
Песочницу в системе Windows создать можно. По этому вопросу было проведено целое исследование. Например, можно процесс ограничить по количеству выделяемой им оперативной памяти. Или по количество дисковой памяти, которое может быть занято на файловой системе. Можно ограничить процесс почти во всем, однако, да простит меня Билл Гейтс, в ОС Windows слишком много вирусов, а это значит что все эти преграды могут быть устранены, например, вирусом. Потому, на середине разработки этой версии, было решено от нее все-таки отказаться. Несмотря на то, что по сути это было бы классным решением: нет проблем сбора результатов работы программы, и нет проблем очистки от деятельности программы. С помощью объектов ядра Windows, которые называются Jobs, ставятся ограничения на использование ресурсов ОС, а с помощью правил в NTFS – ограничения на работу в файловой системе. Практически то, что надо, но чувство самосохранения подсказывало, что есть еще варианты, которые могут быть сделаны достаточно быстро.
На самом деле, этот вариант лежит на поверхности как первое, что приходит в голову. Есть виртуальная машина, на которую надо задеплоить необходимые приложение и файлы. Далее, приложение запускается, его output собирается в файл, а после завершения работы – файл забирается с виртуальной машины, которая в свою очередь сбрасывается в исходное состояние. Это решение обладает целым рядом плюсов, делающих его выигрышным по всем статьям:
Состояние машины сбрасывается, а это значит, что там, внутри, хоть апокалипсис, хоть снос операционной системы с жестких дисков. Абсолютно все равно, что происходит. В конце работы (или по таймауту) просто берем и откатываем до снапшота.
Окружение не ломается после того, как отработает предыдущая машина.
Можно контролировать каждую мелочь.
Однако, есть один минус: сложное управление.
Сначала мы думали, что внутри машины придется запускать агента, который будет управлять деплоем, запуском, и забором output программы для последующей пересылки на хост-машину. Однако потом, как выяснилось, есть замечательный продукт: VirtualBox, у которого есть богатый API и агент, который мне так необходим. Почему меня так обрадовало наличие готового агента? Чем больше компонент мы запустим с нуля, тем больше багов мы словим. Не потому, что мы такие неопытные, нет. Просто баги есть всегда, а в только что написанном ПО тем более. Отлаженный сотнями тысяч запусков код гораздо лучше самописного.
По той же самой причине мы отказались от одного рискованного шага: чтобы сэкономить на ресурсах можно было бы использовать в качестве гостевой операционной системы ReactOS. Реально можно было бы. Если бы не одно НО. Часть интерпретаторов там просто не запустилась. Ни в какую. Может быть в этой ОС есть всего одна ошибка, и она находится глубоко в ядре. Но ее наличие аффектит половину приложений и создает ощущение нестабильности происходящего. Если бы не это, мы бы выбрали именно ее, хотя бы по следующим причинам:
Она сравнительно ничего не занимает на жестком диске (~40Мб)
Она почти не занимает оперативную память (~40 Мб)
Она практически не забирает на себя ресурсы процессора
Это делает ее идеальной для случая, когда на одной физической машине надо запустить до 20 виртуальных машин. Эта шикарная операционная система и будет идеальной, когда ее аккуратно допилят до безбажного состояния. Легковесный Windows, время запуска которого исчисляется секундами (~5).
Итак, итоговое решение:
Хостинг – облачный. Имеет API, можно динамически, программно, наращивать ноды, если на сервер придут тысячи человек и начнут играть. Также динамически можно их отключать.
Нода поднимается с шаблона. В шаблоне – Windows, Git, VirtualBox и скрипт. Скрипт выкачивает последнюю версию исполняемых файлов с репозитория и запускает сервис.
Сервис стартует, поднимает VirtualBox, ищет на нем шаблонную виртуальную машину и в зависимости от конфигурации, клонирует ее в нескольких экземплярах. Машина – предварительно настроенная, с интерпретаторами PHP, Perl, Python, Ruby, Lua, а также — Java, .Net Framework 3.5 версии. Windows XP 64bit.
Начинает слушать очередь команд.
Когда приходит команда, она парсится, на свободную вирт машину, закачивается скрипт или EXE файл игрока, запускается. На решение задачи отводится 30 секунд. По истечении времени либо когда процесс завершится, файл output.log, в который пишется OUTPUT поток программы копируется на хост машину и виртуальная машина сбрасывается в исходное состояние, откатываясь на последний снапшот.
Результаты уходят в браузер.
На данный момент можно говорить о следующих результатах нашей работы:
Единственное, что нам не нравится – это размер образа виртуальной машины. На рабочей станции клонирование 4 Гб образа на пять нод занимает порядка 20-30 минут. При исправлении бага – это было бы кошмарное время. Поэтому наличие готового агента на стороне гостевой виртуальной машины и наличие стабильных версий интерпретаторов – это отдельный жирный плюс. Это в какой-то степени гарантирует бесперебойность работы гостевой машины. Как будет вести себя в облаке – скоро нагрузим и узнаем;
Полное время, которое занимает весь путь от браузера в виртуальную машину, запуск, ожидание окончания и обратно – в виде логов (с учетом отката гостевой машины до исходного состояния), занимает 4 секунды при загрузке в 20% CPU максимум. Это отличный результат. Т.е. при запуске сервера, на котором будет крутиться 5 вирт машин, мы сможем обрабатывать до 75 проверок заданий в минуту. Т.е., можно предположить, что отделаться можно и одним сервером. Второй будет работать, на всякий случай. И третий, если отключится (а вдруг!) один из двух.
В следующий раз мы расскажем вам поподробнее про техническую часть, заглянем еще поглубже. А пока что милости просим на сайт игры (и не забудьте написать в комментариях, на каком языке хотели бы решать задачи вы?):