Введение
Веб-лаборатория для изучения алгоритмов планирования должна решать две разные задачи. С одной стороны, она должна быть удобной для студента: достаточно открыть страницу, выбрать нагрузку, отправить код и получить отчёт. С другой стороны, серверная часть должна безопасно обрабатывать пользовательские программы, потому что C/C++ код потенциально может содержать ошибки, бесконечные циклы и вызовы, не относящиеся к учебному планировщику.
Обычный синхронный веб-запрос плохо подходит для такого сценария. Компиляция и симуляция могут занимать заметное время, а сравнение нескольких алгоритмов фактически запускает несколько прогонов подряд. Поэтому архитектура должна отделять приём запроса от выполнения долгой операции, сохранять состояние задачи и позволять пользователю позже получить результат.
В разработанной лаборатории эта задача решается за счёт серверной архитектуры с очередью заданий, воркерами, реляционным хранилищем статусов и объектным хранилищем готовых HTML-отчётов. Отдельный слой отвечает за компиляцию и ограниченный запуск пользовательского бинарника.
Общая структура веб-сервиса
Серверная часть реализована как веб-приложение на Kotlin с использованием Ktor. Компонент маршрутизации принимает HTML-страницы и REST-запросы, проверяет параметры и передаёт данные в сервисы задач. В системе предусмотрены два основных сценария: одиночная симуляция и сравнение нескольких алгоритмов на одной нагрузке.
Для хранения состояния используется PostgreSQL. В базе фиксируются параметры запуска, фаза выполнения, диагностические сообщения, JSON-метрики и ключ объекта отчёта. Готовые HTML-отчёты сохраняются не как большие строки в таблице, а как объекты в MinIO. Такой подход разделяет структурированные данные и готовые документы отчёта.
Архитектура построена модульно: пользователь взаимодействует с HTTP-интерфейсом, сервисы задач создают записи в очереди, воркеры забирают задания, CompilerService выполняет сборку и запуск эмулятора, ReportStorage сохраняет результат в объектном хранилище. Благодаря этому отдельные части системы можно развивать независимо друг от друга, а как вариант дополнить новыми модулями саму архитектуру модулями проверки кода или его предобработки.
Таблица 1.
Основные компоненты веб-сервиса виртуальной лаборатории
|
Компонент |
Назначение |
Результат работы |
|---|---|---|
|
Routing |
Приём HTML-страниц и REST-запросов, проверка входных параметров. |
Создание задач и выдача статуса пользователю. |
|
SimulationJobService |
Обработка одиночных симуляций, запуск воркеров. |
Переход задачи между состояниями очереди. |
|
ComparisonJobService |
Запуск нескольких алгоритмов на одной нагрузке. |
Сравнительный отчёт и набор метрик. |
|
CompilerService |
Компиляция пользовательского кода и запуск эмулятора. |
JSON-метрики либо диагностическая ошибка. |
|
ReportStorage |
Сохранение и чтение HTML-отчётов через S3-совместимый API. |
Ключ отчёта, доступный из базы данных. |
Очередь долгих операций
Для выполнения компиляции и симуляции используется очередь долгих операций. HTTP-запрос не ждёт завершения эксперимента: сервис создаёт запись в базе данных со статусом QUEUED и возвращает пользователю идентификатор задачи. Далее пользователь или интерфейс периодически запрашивает статус.
Воркеры работают независимо от HTTP-запроса. Каждый воркер атомарно забирает свободную задачу из PostgreSQL с помощью конструкции FOR UPDATE SKIP LOCKED. Этот механизм позволяет нескольким воркерам параллельно искать задания, не обрабатывая одну и ту же запись дважды. Если строка уже заблокирована другим воркером, она пропускается, а обработчик берёт следующую доступную задачу [4].
Жизненный цикл задачи включает состояния QUEUED, RUNNING, SUCCESS, COMPILE_ERROR и RUN_ERROR. Такое разделение полезно для пользователя и преподавателя: можно понять, находится ли задача в очереди, выполняется ли она, успешно ли завершилась или остановилась из-за ошибки компиляции либо запуска.
Таблица 2.
Состояния задания в очереди
|
Состояние |
Смысл |
Когда возникает |
|---|---|---|
|
QUEUED |
Задание создано и ожидает обработки. |
После успешного принятия HTTP-запроса. |
|
RUNNING |
Задание забрано воркером. |
После атомарного выбора строки из очереди. |
|
SUCCESS |
Симуляция завершилась успешно. |
После получения JSON-метрик и сохранения отчёта. |
|
COMPILE_ERROR |
Ошибка проверки, компиляции или линковки. |
При некорректном исходном коде или ошибке сборки. |
|
RUN_ERROR |
Ошибка выполнения бинарника или разбора результата. |
При тайм-ауте, ненулевом коде возврата или некорректном JSON. |
Конвейер компиляции и запуска пользовательского кода
Пользовательская реализация алгоритма передаётся как C или C++ файл, содержащий функцию выбора задачи. Перед компиляцией выполняется предварительная проверка SourceSafetyGuard. Этот компонент не является полноценным формальным статическим анализатором, но он отбрасывает заведомо опасные конструкции: запрещённые include, попытки работы с файлами, сетью и процессами, а также inline assembly.
После предварительной проверки создаётся временный каталог. В него помещается пользовательский файл, объектный файл ядра симулятора и будущий исполняемый файл. Ядро rtos_sim.c и пользовательский файл компилируются отдельно, затем линкуются в единый бинарник. Для C используется стандарт C11, для C++ — C++17. Если компилятор возвращает ошибку или превышает тайм-аут, пользователь получает диагностическое сообщение.
Дополнительная проверка выполняется после компиляции пользовательского объектного файла. Сервис анализирует неопределённые внешние символы через nm и отклоняет объект, если он пытается ссылаться на запрещённые функции вроде system, socket, fork или fopen. Это дополняет текстовую проверку и снижает риск обхода через макросы или косвенные конструкции.
Таблица 3.
Уровни ограничения пользовательского кода
|
Уровень |
Что проверяет или ограничивает |
Назначение |
|---|---|---|
|
SourceSafetyGuard |
Размер файла, разрешённые include, запрещённые вызовы, inline assembly. |
Раннее отклонение явно опасного исходника. |
|
Проверка объектного файла |
Неопределённые внешние символы после компиляции. |
Поиск скрытых обращений к запрещённым функциям. |
|
SafeProcess |
Тайм-ауты, ограничение stdout/stderr, очищенное окружение процесса. |
Контроль внешних процессов компиляции и запуска. |
|
sandbox-runner |
chroot, отдельный пользователь, seccomp, no_new_privs, rlimits. |
Ограничение уже скомпилированного бинарника. |
Безопасное исполнение и хранение отчётов
Сам пользовательский бинарник не выполняется внутри процесса веб-сервера. Он запускается как отдельный процесс через sandbox-runner. Runner создаёт ограниченную среду выполнения: переводит процесс в минимальный корень файловой системы, сбрасывает права до отдельного пользователя, включает no_new_privs, задаёт ограничения процессорного времени, памяти, числа процессов, размера файлов и открытых дескрипторов.
Такой механизм не следует описывать как абсолютную промышленную изоляцию произвольного вредоносного кода. Однако для учебной лаборатории многоуровневая защита существенно снижает риск по сравнению с прямым запуском пользовательского кода внутри основного сервера. Если бинарник зависает, превышает лимиты или выводит некорректный JSON, задача завершается состоянием RUN_ERROR.
При успешном завершении stdout рассматривается как JSON-документ метрик. Сервер преобразует его во внутреннюю структуру, сохраняет метрики в PostgreSQL и формирует HTML-отчёт с графиками. Сам отчёт выгружается в MinIO, а в базе остаётся только ключ объекта. Это уменьшает размер строк таблицы и упрощает повторную выдачу отчёта пользователю.
Заключение
Архитектура виртуальной лаборатории ориентирована на учебный веб-сценарий, в котором пользовательский код должен запускаться удобно, воспроизводимо и контролируемо. Для этого синхронный HTTP-запрос отделён от долгого выполнения через очередь задач, а результаты сохраняются в форме метрик и HTML-отчётов.
Предложенное решение сочетает веб-интерфейс, очередь на базе PostgreSQL, объектное хранилище MinIO и многоуровневый запуск пользовательского C/C++ кода. Такая архитектура может быть расширена новыми алгоритмами, наборами нагрузок, ролями преподавателя и автоматической проверкой решений студентов.
Список литературы
- 1. Docker Inc. Docker Documentation. URL: https://docs.docker.com/ (дата обращения: 13.06.2026).
- 2. JetBrains. Ktor Documentation. URL: https://ktor.io/docs/ (дата обращения: 13.06.2026).
- 3. MinIO. S3 Compatible Object Storage. URL: https://min.io/ (дата обращения: 13.06.2026).
- 4. PostgreSQL Global Development Group. PostgreSQL Documentation: SELECT, Locking Clause, SKIP LOCKED. URL: https://www.postgresql.org/docs/current/sql-select.html (дата обращения: 13.06.2026).
- 5. The Linux man-pages project. seccomp(2) — Linux manual page. URL: https://man7.org/linux/man-pages/man2/seccomp.2.html (дата обращения: 13.06.2026).


