null

Неправда и принцип работы VMware Fault Tolerance

То, что русскоязычные материалы о заморских технологиях зачастую порождены надмозгом и скупы на технические детали, дело привычное. Но вольные интерпретации оригиналов и грязные инсинуации из первой десятки по запросу "принцип работы VMware Fault Tolerance" совсем уж удручают. Вот парочка примеров:

  • Пыщ. "Стоит также отметить ограничения на частоту процессора, FT работает только с процессорами с частотой 400 MHz и выше, хотя теперь это уже не особо актуально" что в оригинале выглядело как "The CPU frequency difference should not exceed 400 MHz". Стоит также отметить, что автора не смутила получившаяся чепуха, и он даже произвел анализ её актуальности.
  • Пыщ."Для машин, защищенных при помощи VMWare Fault Tolerance, происходит постоянное (в реальном времени) копирование всего состояния памяти и процессорных инструкций с основной копии на «теневую»"
  • Пыщ."Между активной и пассивной копией происходит односторонняя репликация процессорных инструкций." Способные к мыслительной деятельности индивиды явно бы усомнились в возможности копирования в реальном времени всего состояния памяти (что уж говорить про процессорные инструкции) без существенного падения производительности с учетом пропускной способности самой медленной DDR3 (DDR3-800) даже в одноканальном режиме равной 6.4 ГБайт (51.2 Гбит).

Вообщем, совместными усилиями отечественные блоггеры так намутили воду вокруг FT, что заставили уверовать в чудотворные способности FT даже вполне сознательных личностей. По делу написал лишь Доктор Добрянский: "VMware Fault Tolerance. Фишка ее заключается в том, что при работе виртуальной машины на одном физическом хосте, ее «призрак» (синхронная реплика) работает на другом хосте кластера и при выходе из строя основного хоста (и соответственно виртуальной машины) происходит мгновенное переключение ввода/вывода и активизация призрака. При этом время простоя виртуальной машины равняется нулю, как говорит маркетинг VMware, в реальности все немного не так (на практике замечаются небольшие подтормаживания 1-2 сек и потеря одного «пинга»)"

Итак, как же можно заставить две виртуальные машины работать синхронно на разных хостах, которые даже не обязательно должны иметь одинаковые модели процессоров? Основная проблема состоит в непредсказуемости момента завершения операций ввода-вывода и появления прерываний на физически различных хостах. Но если захватывать все эти события на одной машине (основной) и воспроизводить на второй (теневой), пусть и с задержкой, но в момент выполнения тех же самых инструкций, виртуальные машины будут работать синхронно.

Вся эта непредсказуемая внешняя активность передается по сети на хост с теневой ВМ и обозвана как logging traffic (отдельную запись назовем ft логом). И хотя гипервизор имеет определенный контроль над вводом/выводом, для его воспроизведения (а заодно и воспроизведения прерываний) в необходимый нам момент времени уже требуется специальная поддержка со стороны аппаратуры. Еще раз подчеркну - никакого копирования содержимого памяти и процессорных инструкций не происходит (точнее говоря, за редким исключением копирования памяти не происходит). Правда работает такой подход только в случае однопроцессорных ВМ, ведь в случае SMP любое обращение процессоров в общую память потенциально является недетерминированным событием. Тут задача синхронизации уже совсем не тривиальна, а решение "в лоб" (с блокировкой при каждом обращении) гробит всю производительность. Тем не менее рабочие прототипы FT для многопроцессорных ВМ уже не раз демострировались на конференциях, а "выход в люди" запланирован на 2013 год.

Кроме передачи ft логов системы обмениваются heartbeat'ами. В случае, когда система перестает получать ft логи или heartbeat'ы, начинается процедура failover'а. Однако это может свидетельствовать не только о проблемах с одним из хостов, но и о банальном сбое в работе сети. Поэтому для исключения ситуации split brain используется общее хранилище (ибо текущая реализация ft предполагает использование shared storage). Фунциклирует защита от split brain'а следующим образом. При включении ft, основной хост создает на хранилище файл с именем generation.N. Как только любой из хостов обнаруживает сбой, он пытается переименовать этот файл в generation.N+1. Тот хост, которому это удалось, считается выигравшим и продолжает свою работу. Если операция заканчивается неудачей (т.е. другой хост успел переименовать файл раньше), то ВМ на текущем хосте без лишних слов самоликвидируется. В случае же, когда хранилище недоступно (например из-за проблем с SAN), работа ВМ останавливается, пока хранилище не станет вновь доступно. Сразу после failover'а остается только одна активная ВМ, так как вторая умерла вместе с хостом или от "разрыва мозга" :). Поэтому, дабы восстановить отказоустойчивость, из живых хостов кластера неведомым образом автоматически выбирается один хост и на нём запускается теневая ВМ.

Вроде бы идея довольно простая. Первая очевидная проблема - если две машины в ходе своей нормальной работы будут одновременно гадить в сеть и на общее хранилище, беды не миновать. Решение столь же очевидное - гипервизор принимает запросы на вывод от теневой ВМ, а сам втихую сливает все в /dev/null. В случае выхода из строя основного хоста, теневая ВМ становится основной и весь вывод уже обрабатывается нормальным образом.

Понятно, что теневая ВМ будет работать с некоторым запаздыванием относительно основной. Промежуток времени, который требуется теневой ВМ, чтобы догнать основную, называется vLockstep interval. Скорость работы основной и теневой ВМ может различаться по многим причинам. В хостах банально могут использоваться разные модели процессоров, а даже если и одинаковые, то современные процессоры довольно вальяжно меняют свою тактовую частоту. Кроме того, прочие виртуалки работающие на хостах создают различную нагрузку. Это означает, что vLockstep interval может меняться в обе стороны. Если основная ВМ слишком далеко убегает от теневой, гипервизор притормозит её. Аналогично, если теневая ВМ начнёт наступать на пятки основной, её так же усмирит гипервизор. Таким образом, если защищенная при помощи FT виртуалка тормозит, это вовсе не означает, что на основном хосте недостаточно ресурсов. Вполне вероятно источником проблем может быть хост с теневой ВМ.

Теперь поговорим о чуть менее очевидных вещах. Основной хост может упасть в любой момент, в том числе и во время выполнения ввода-вывода. Тем не менее FT должен обеспечивать прозрачное для внешнего мира переключение на теневую ВМ и в то же время иметь малые накладные расходы на ввод/вывод.

В нормальной ситуации vLockstep interval составляет десятые доли секунды и не превышает 1с. Однако, важно гарантировать, что при failover'е состояние теневой ВМ будет согласовано со всем выводом, который успела породить основная ВМ. Поэтому перед тем, как разрешить теневой ВМ производить реальный вывод, необходимо накатить на неё все ft логи, что потребует примерно vLockstep interval секунд. Это также означает, что на теневом хосте всегда должны присутствовать ft логи обо всех операциях, инициированных основной ВМ, еще перед началом их выполнения. Таким образом любая операция вывода, которую создает основная ВМ, должна быть приостановлена гипервизором до момента, когда теневой хост подтвердит прием соответствующего ft лога. Тем не менее, сама основная ВМ вполне может продолжать свою работу (в случае асинхронного io). При успешном стечение обстоятельств, отправка ft лога может вовсе не сказаться на производительности ВМ. Однако задержка любой операции вывода увеличивается на время, необходимое для передачи по сети ft лога и получения подтверждения. Для большей наглядности приведу рисунок из VMware TechReport'а:

Правда в случае failover'а нельзя гарантировать, что вывод не будет произведен дважды, так как основной хост может упасть сразу после получения подтверждения об отправке ft log'а, но до осуществления самой операции вывода (т.е. нельзя точно сказать была ли эта операция выполнена реально или нет). Кроме этого может потеряться ввод, если хост упадет приняв данные, но не успев отправить ft log. Правда к страшным последствиям это привести не должно: однократную потерю или дубликат сетевого пакета вообще проблемой считать не стоит, а двойная запись одних и тех же данных по одинаковому адресу тоже не очень опасна.

На самом деле ситуация с вводом-выводом чуть сложнее. В реальности логически законченная io операция может состоять из нескольких ft логов, и выполнить только часть из них было бы не совсем правильно для существующих реализаций виртуальных устройств ESX. Поэтому некоторый ft логи маркируются, как "go-live points" (начиная с которых теневой ВМ можно продолжить выполнение как полностью независимой, т.е. стать основной). Гипервизор теневого хоста принимает и буферизирует все ft логи, но накатывает их на теневую ВМ только до последнего go-live. Если среди имеющихся логов нет go-live, то выполнение теневой ВМ останавливается до момента их получения. Кроме этого, в случае failover'а может потребоваться выполнить некоторые специфичные для разных устройств действия. Например, технология ft выполняет автоматическое представление в сети MAC адресов виртуальных адаптеров ВМ, дабы реальные свитчи поняли куда слать сетевые пакеты.

Вкратце как-то так. Более подробно о реализации и тестах производительности ft написано в VMware TechReport'е под названием "The Design and Evaluation of a Practical System for Fault-Tolerant Virtual Machines", а так же в светлой бумаге "VMware vSphere 4 Fault Tolerance: Architecture and Performance".

Являюсь инженером компании Tune-IT. Проявляю интерес к:

  • вопросам производительности ВС
  • VoIP и Asterisk
  • железу SUN
  • Solaris