Системный программист
0,0
рейтинг
24 июля 2012 в 22:59

Разработка → CRIU — новый амбициозный проект для сохранения и восстановления состояния процессов

CRIU (application Checkpoint/Restore In Userspace) — это амбициозный, быстро развивающийся проект, который позволяет сохранить состояние программы в виде контрольной точки, и впоследствии возобновить работу приложения с этой точки.
Возможности применения программного обеспечения для создания контрольных точек достаточно разнообразны. К примеру, OpenVZ использует похожий механизм для “живой” миграции. Parallels Virtuozzo использует подобный механизм для быстрого возобновления работы контейнеров после обновления ядра. CRIU уже используется в высокопроизводительных кластерах для для сохранения промежуточных результатов вычислительных процессов, используемых для возобновления работы приложения в случае сбоя.
В этой статье рассказывается, как CRIU сохраняет и восстанавливает состояние программы, и почему этот проект может быть успешнее своих предшественников.


Немного истории


CRIU — это далеко не первая попытка реализовать некий механизм сохранения и восстановления программ в Linux. Существует как минимум две рабочие реализации C/R: OpenVZ и проект linux-cr, лидером которого является Oren Laadan.
Проблема обоих проектов в том, что они реализуют весь C/R практически полностью в пространстве ядра. Однако эти проекты не стали частью основного ядро Linux из-за большого объёма и сложного кода.
Лидер команды разработчиков OpenVZ Павел Емельянов предложил изменить сам подход к C/R и перенести основную работу в пространство пользователя. Сообщество хорошо приняло эту идею и появился проект CRIU.

Сохранение состояния приложения


Приложение может состоять как из одного, так и из множества запущенных процессов. CRIU поддерживает оба типа.
Для получения информации о состоянии процесса первое, что приходит на ум, это использование механизма, которым пользуется отладчик (ptrace). Но он не предоставляет всей информации. Часть состояния процесса можно почерпнуть из файловой системы procfs и системного вызова prctl, однако и этого недостаточно.
Для получения недостающей информации в проекте CRIU был использован механизм внедрения исполняемого кода в процесс (т.н. паразитный код), который был разработан и любезно предоставлен Tejun Heo, одним из основных на сегодняшний день разработчиков ядра Linux.

Восстановление состояния приложения


Для восстановления приложения с контрольной точки необходимо сначала создать дерево его процессов. Для этого в ядре Linux был разработан отдельный механизм для создания процессов с заданными идентификаторами. После старта каждый процесс восстанавливает свою память, открытые файлы, сокеты, пайпы, IPC и т д.
Однако на самом деле всё не так просто, ведь ресурсы могут быть общими для нескольких процессов.
Регионы адресного пространства процесса могут быть уникальны (MAP_PRIVATE) либо доступны одновременно несколькими процессами (MAP_SHARED). Первый тип восстанавливается достаточно просто (если не задумываться о технологии “copy on write” — она остаётся за скобками этой статьи).
В чем же проблема во втором варианте? Если у нас регион адресного пространства отображается в файл, то все в порядке — для восстановления такого куска адресного пространства можно использовать стандартные механизмы Linux.
Но что делать, если регион анонимный (MAP_ANONYMOUS), т.е. отображается в оперативную память? Для поддержки восстановления такого региона пришлось опять подровнять ядро напильником, а именно реализовать отображение каждого в файловой системе procfs — для каждого распределенного региона памяти ядром создаётся файл в /proc/self/map_files/<start_addr>-<end_addr>. Благодаря этим файлам анонимные регионы распределённой памяти можно восстанавливать как файловые.
Следующей проблемой на очереди были открытые файлы. Они тоже могут использоваться совместно несколькими процессами. Здесь пригодилась возможность передачи файловых дескрипторов через Unix сокеты. Один из процессов-пользователей открывает файл, и пересылает его дескриптор остальным.
Итак, память восстановлена, файлы открыты. Как же передаётся управление процессу? Передача управления основана системном вызове sigreturn(): когда процессу приходит сигнал, ядро сохраняет состояние процесса и передает управление обработчику сигнала, который по окончанию вызывает sigreturn(). Таким образом для того, чтобы запустить процесс с желаемой точки достаточно восстановить состояние процесса в нужном формате и позвать sigreturn().
И вот процесс восстановлен и продолжает работать.

Интересное


CRIU умеет сохранять и восстанавливать TCP соединения. Это может использоваться для живой миграции. Пользователь заметит лишь небольшую задержку в сетевой активности при переезде приложения со всеми своими соединениями на другой сервер.
CRIU сохраняет данные процесса на диске с помощью формата Google’s Protocol Buffers. Программные библиотеки для работы с этим протоколом существуют для большинства популярных языков.
При разработке вся возможности CRIU постоянно проверяются встроенной тестовой системой. Для этого используется переработанный и улучшенный фреймворк, заимствованный из проектов по разработке OpenVZ и Virtuozzo.
CRIU разрабатывается компанией Parallels, в рамках проекта по переносу кода OpenVZ в основное ядро Linux.

Цели


Основная цель проекта на ближайшее будущее — это научиться сохранять и восстанавливать состояние Linux Containers (LXC). Для этого необходимо реализовать сохранение и восстановление терминалов, полученных, но ещё не обработанных сигналов, пространств имен сетевого окружения (network namespace) и иерархии файлов (mount namespace; находится в разработке).

Ссылки


ru.wikipedia.org/wiki/CRIU
ckpt.wiki.kernel.org/index.php/Main_Page
wiki.openvz.org/Checkpointing_and_live_migration
www.parallels.com
code.google.com/p/protobuf
Вагин Андрей @avagin
карма
54,0
рейтинг 0,0
Системный программист
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

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

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

  • +1
    Немного не в тему, но я тут недавно задавался вопросом о восстановлении TCP соединения, чтобы при переключении с одной тачки на другую keep-alive соединение не разрывалось. Интересно было бы использовать только механизм восстановления TCP сессий.
    • +1
      Ядерная часть вошла в 3.5 kernelnewbies.org/Linux_3.5#head-9ef0326b4fa2e159cdc12f5ab329a06d8658e1e4
      Пример userspace кода вы можете найти тут: git.criu.org/?p=crtools.git;a=blob_plain;f=sk-tcp.c;hb=HEAD
    • 0
      conntrackd?
      • 0
        conntrackd для гейтвеев/файрволлов. Мне же требуется на двух разных бэкендах с разными IP поддерживать на уровне приложения и ядра уже установленные коннекты. Т.е. на web1 создается ESTABLISHED соединение, а на web2 создается клон, на тот случай, если к нему буду приходить коннекты.

        Я уже задавался этим вопросом на lor, но низкоуровневого решения не нашлось, пришлось использовать nginx в качестве прослойки и по сигналу RST перенаправлять трафик на нужный backend.
  • +1
    Я немножко не понял, что оно делает со средой обитания программы при восстановлении. Понял, что переоткроет все дескрипторы (файлы, сокеты, мьютексы...), но не понятно, что будет делать если файл был удалён, сокет закрыт, а мьютекс переключен. Насколько я понимаю, segmentation fault либо что-то похожее можно гарантировать… Разъясните пожалуйста этот момент.
    • +3
      Программа будет работать как раньше, никаких лишних segfault-ов быть не должно. Если файл будет удален, то его содержимое будет сохранено и на ресторе файл будет восстановлен, открыт и снова удален. С закрытым сокетом проблем еще меньше, достаточно на восстановлении создать сокет и закрыть его. С мьютексом проблемы совсем нет, его состояние хранится в памяти, а она восстанавливается.
      Предупрежу дальнейшие вопросы. Мы не просто приоткрываемым сокеты, пайпы и т д, но и восстанавливаем их состояния. Для каждого объекта свой подход. Сначала мы стараемся использовать существующие механизмы, если не получается добавляем новые интерфейсы в ядро.
      • +2
        Железно)
  • 0
    Программа будет работать как раньше, никаких лишних segfault-ов быть не должно. Если файл будет удален, то его содержимое будет сохранено и на ресторе файл будет восстановлен, открыт и снова удален. С закрытым сокетом проблем еще меньше, достаточно на восстановлении создать сокет и закрыть его. С мьютексом проблемы совсем нет, его состояние хранится в памяти, а она восстанавливается.
    Предупрежу дальнейшие вопросы. Мы не просто приоткрываемым сокеты, пайпы и т д, но и восстанавливаем их состояния. Для каждого объекта свой подход. Сначала мы стараемся использовать существующие механизмы, если не получается добавляем новые интерфейсы в ядро.
  • +2
    Интересно, а какие-то наработки такого рода для Windows существуют?
    • 0
      Persistence в Windows Workflow Foundation?
  • +1
    Для восстановления приложения с контрольной точки необходимо сначала создать дерево его процессов. Для этого в ядре Linux был разработан отдельный механизм для создания процессов с заданными идентификаторами.

    Что будет, если такой PID в системе уже присутствует? :)
    • 0
      Тоже интересовал этот вопрос. И как решается если на дургой системе немного другое дерево. Или тут должна быть ос 1 в 1. ЧТо конечно логично но хотелось бы коментарий.
      • 0
        Что значит немного другое дерево? В каждой системе дерево свое.
        Есть проблема с изоляцией приложений. Мы сохраняем и восстанавливаем только те процессы, которые попросил пользователь. Проблема в том, что процессы могут быть связаны между собой и иметь некий двусторонний внутренний стейт, который зависит от логики приложения. В этом случае, если мы сохраним только одну сторону и потом ее восстановим, то формальная связь (unix сокет, fifo) будет восстановлена, но мы ничего не знаем о внутреннем состоянии.
        Сохранение и восстановление контейнера целиком, гарантирует что мы собрали все зависимости и с большой вероятностью сможем его восстановить на другой системе.
    • 0
      В этом случае восстановление не возможно. Это не проблема, если мы дампим контейнер (lxc или OpenVZ), потому что они используют pid namespace.
  • 0
    Ну наконец-то, давно думал почему этим еще никто не занялся, это же будет очень удобно.
  • 0
    Напомнило долгостроящуюся ru.wikipedia.org/wiki/Фантом_%28ОС%29 — в ней что-то такое обещают с самого начала, а это лет шесть назад.
    Q: Каково же уникальное свойство ОС Фантом?
    A: Говоря попросту — бессмертие. В отличие от всех существующих систем Фантом умеет обеспечить работающим в нём программам вечную жизнь. Для программ не существует необходимости завершаться. Это довольно сильно меняет ситуацию. Во-первых, это удобно — пользователь не должен перед выключением машины закрывать все программы и снова открывать их перед началом работы. Во-вторых, это позволяет программам быть сильно проще — например, программа больше не вынуждена вообще уметь записывать своё состояние в файл! Одно лишь это упрощение снижает затраты денег и времен на те самые 30%. А есть и другие.
    • 0
      Да, чем-то напоминает, но в нашем случае нет возможности обновить приложение и потом его восстановить.
      К слову 6 лет назад у нас уже была эта функциональность в OpenVZ. CRIU позволит избавиться от своего кода в OpenVZ ядре, который нам сейчас приходится поддерживать. В свою очередь это даст нам возможность сделать что-то новое.
      • 0
        Я упомянул «Фантом» не для установления исторического первенства, а скорее, чтоб вы могли черпать идеи из ещё более амбициозного проекта, и учиться на опыте и на ошибках его разработчиков.
        Например, у них снимки памяти делаются инкрементально, что позволяет существенно сократить задержку. Может, сумеете и из юзермода так же?
        • 0
          Я понял о чем вы хотели сказать. Не думаю, что в «Фантоме» успели реализовать какие-то новые идеи. Ваш пример существует и используется в Virtuozzo во время живой миграции.

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