Повседневность Облачной Разработки, Часть Первая

Я продолжу серию официальных постов в блоге компании о том, как работать с облаком, но в то же время хотелось бы рассказать о проблемах, с которыми мы столкнулись при адаптации Xen Cloud Platform к нашей облачной операционной модели.

Эти посты будут немного более сложными и предполагают, что читатель имеет хотя бы базовое представление о том, как работает Xen. Когда понятие «оплата по потреблению» только формализовалось, и я судорожно искал, «как посчитать», мне казалось, что процессор и память — это два простейших ресурса.

Действительно, у нас есть xencontrol (библиотека управления гипервизором Xen), которая может точно сказать о каждом домене (запущенной виртуальной машине), сколько у него памяти, сколько наносекунд времени было потрачено.

Эта библиотека запрашивает информацию напрямую (через xenbus) от гипервизора и подвергается минимальной обработке.

Эта информация выглядит примерно так (вывод привязки xencontrol для Python):

 
 {
     'paused': 0, 
     'cpu_time': 1038829778010L, 
     'ssidref': 0, 
     'hvm': 0, 
     'shutdown_reason': 0, 
     'dying': 0, 
     'mem_kb': 262144L, 
     'domid': 3, 
     'max_vcpu_id': 7, 
     'crashed': 0, 
     'running': 0, 
     'maxmem_kb': 943684L, 
     'shutdown': 0, 
     'online_vcpus': 8, 
     'handle': [148, 37, 12, 110, 141, 24, 149, 226, 8, 104, 198, 5, 239, 16, 20, 25], 
     'blocked': 1
 }
 
Как мы видим, есть поле mem_kb, соответствующее выделенной памяти для виртуальной машины, и есть поле cpu_time, содержащее какое-то умопомрачительное число (хотя на самом деле оно составляет всего 17 минут).

cpu_time считает с точностью до наносекунд (точнее, значение, которое здесь хранится, считается в наносекундах, реальная точность — около микросекунды).

Память, как понятно, в килобайтах (хотя внутренней единицей учета и гипервизора, и ядра Linux является страница — его размер по умолчанию составляет 4 килобайта).

Казалось бы, «бери и посчитай», однако дьявол кроется в деталях… Извините за желтый заголовок ниже, но именно так звучал вопрос в дебатах при обсуждении одной из проблем: Hyper-threading + Xen = воровство денег у клиентов Вопрос: нужно ли включать гиперпоточность на хостах с Xen? Включение его позволяет предложить клиенту больше ядер.

Для двух Зеонов по 4 ядра это даст 16 ядер, а если зарезервировать пару для собственных нужд, то и 14 ядер.

14 круче 8? Кулер.

Значит, должно быть 14. Кроме того, если запустить многопоточное приложение, оно будет рассчитываться в полтора раза быстрее на 14 «фейковых» ядрах, чем на 7 реальных.

Это действительно так, я проверял это в тестах на голом Linux на одном из тестовых серверов.

… Останавливаться.

В полтора? То есть 14 ядер при вдвое большем количестве ядер будут работать в полтора раза меньше? Да, именно так и оказалось.

Ситуация стала особенно драматичной в тот момент, когда я попытался запустить дробилку чисел в одной виртуальной машине с максимальной нагрузкой и задачей, которую заведомо не решить в течение нескольких часов, а в другой я запустил приложение, вычисляющее вычислительную задачу фиксированный объем.

И сравнил, сколько времени занял расчет с выключенным гиперпоточностью и с включенным.

Уровень нагрузки Расчетное время процессора без HT С ХТ
неактивный сосед, 1 ядро 313.758 313.149
соседи простаивают, 4 ядра 79.992 * 4 80.286 * 4
соседи простаивают, 8 ядер 40.330 * 8 40.240 * 8
соседи простаивают, 16 ядер - 29.165 * 16
соседи с полной нагрузкой, 1 ядро 313.958 469.510
соседи с полной нагрузкой, 4 ядра 79.812 *4 119.33 * 4
соседи с полной нагрузкой, 8 ядер 40.119 * 8 59.376 * 8
соседи с полной нагрузкой, 16 ядер - 29.634 * 16
Легко видеть, что 29,6*16 равно 473,6, то же самое, что 59,376*8 (475).

А это в полтора раза больше, чем 40,119*8(320).

Другими словами, гиперпоточность замедляет работу процессоров в полтора раза при увеличении их количества вдвое.

Поможет, если процессор полностью ваш.

Что делать, если процессорное время оплачено и рядом даже не «коллеги», а просто «чужие»? После этого у нас была большая дискуссия (дня три с перерывами длилась) — стоит ли делать HT на облачных хостах для клиентов? Помимо очевидных «справедливо или нечестно» и «никто не узнает», были и куда более серьезные аргументы:

  • Один сервер будет генерировать больше ресурсов процессора (именно для этого Intel и сделала эту технологию)
  • Мы можем объяснить эту «потерю производительности» снижением стоимости машинного времени.

  • Мы можем контролировать загрузку хоста и не допускать перегрузки выше 50%, но можем предоставить клиенту больше ядер.

После обсуждения мы пришли к следующему набору аргументов: Мы не можем контролировать и реалистично (не статистически) прогнозировать потребление компьютерного времени.

Миграция хоть и является решением, но является частичным, поскольку реакция миграции должна составлять минимум 30-40 секунд, а скачки нагрузки могут быть мгновенными (менее секунды).

В связи с этим мы не знаем, какое компьютерное время (полное или нет) мы предоставили клиенту, и в любом случае клиент столкнется с неоправданной потерей производительности без видимых причин из-за того, что его сосед захотел считать что-то тяжелое.

Из-за невозможности обеспечить постоянную производительность виртуальной машины с помощью Hyper-Threading у нас всё же возобладало мнение, что HT в облаке с оплатой машинного времени нужно отключать (отсюда и ограничение в 8 ядер на виртуальную машину).

Миграция: копирование и удаление Вторым забавным моментом стала проблема учета ресурсов при миграции.

По умолчанию предполагается, что дескриптор (он же uuid) является доказательством уникальности объекта, и не может быть двух виртуальных машин с одинаковым uuid. Действительно, это правда.

Однако это относится к виртуальным машинам, а не к доменам.

При миграции содержимое домена (ОЗУ) копируется, запускается на новом узле и только потом удаляется на старом.

Все это сопровождается многочисленными перекопиями фрагментов домена (поскольку виртуальная машина продолжает работать).

В любом случае мы получаем ДВА домена с ОДНОЙ виртуальной машины.

Если мы грубо и прямо посчитаем цифры (суммируем их), то в итоговых счетчиках мы получим совершенно неправильные цифры.

(Кстати, эта проблема была обнаружена довольно поздно и стала одной из причин задержки запуска).

Решение проблемы было элегантным и архитектурно красивым.

Одновременно может работать только одна копия домена — все остальные находятся в режиме паузы.

Это очень важно, потому что если у нас работают два домена, они могут допустить много ошибок.

Таким образом, решение выглядит так: приостановленный домен не засчитывается.

Это имеет несколько незначительных негативных последствий:

  • Нам не удалось предложить клиентам эффектную кнопку «пауза» (в этом режиме домен существует, но не выполняется).

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

    Но мы не можем отличить «паузу при миграции» от просто «паузы» (по крайней мере, без очень больших и нетривиальных танцев с состояниями и базами данных).

  • Когда клиент перезагружает машину, есть небольшой момент, когда домен уже существует, но все еще находится на паузе — мы его не учитываем (таким образом, клиент, который постоянно перезагружает машину, может неучтенно потреблять небольшой объем памяти).

    Возможно, это даже честнее, потому что это наши проблемы — там, где что-то строится, пока машина не заработает, клиенту нет смысла за это платить.

Но в остальном это решение не имеет никаких побочных эффектов.

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

Кто будет платить за dom0? Еще одной огромной проблемой была проблема с загрузкой dom0. Когда пользователь делает запрос по сети или выполняет дисковые операции, запрос передается из domU (домена, в котором работает виртуальная машина) в dom0 на вторую половину драйвера.

Драйвер обдумывает запрос и передает его реальным драйверам реального оборудования.

И надо сказать, при интенсивных дисковых операциях он это умеет. Видеть нас на уровне 50-80% — плохая идея.

И большую часть из этого количества составляют OVS, blktap, xenstore и т. д. (остальные — xapi, compressed, stunnel, которые входят в систему управления облаком).

Кому должен выставляться счет за это машинное время? И самое главное, как отделить одного пользователя от другого? На уровне драйвера это еще возможно, но помимо этого.

Тот же OVS (Open vSwitch, программа, предоставляющая виртуальную сеть) переключает кадры, и ей все равно, к какому домену они принадлежат. Люди из Zeno (разработчики гипервизора и его железа) ломают голову над этим вопросом.

Я тоже начал думать, но вовремя опомнился.

Если дисковые операции платные, то в их стоимость, по сути, входит стоимость обработки запроса.

Это не только дисковые IOPS, нагрузка на рейд-контроллеры, SAN, износ карт 10G и т.д. Это и (весьма незначительное по цене по сравнению с вышеперечисленным) машинное время dom0. Все было логично и разрешилось само собой.

Теги: #Облачные вычисления #Xen #selectel cloud #selectel cloud #selectel cloud #selectel cloud #hyperthreading #машинное время #будни разработчика

Вместе с данным постом часто просматривают: