
Здравейте! Искам да разкажа на прост език за механиката на възникването на steal в рамките на виртуалните машини и за някои неочевидни артефакти, които успяхме да установим при изследването му, в което трябваше да се потопя като технически директор на облачната платформа. . Платформата работи на KVM.
CPU steal time е времето, през което виртуалната машина не получава ресурси от процесора за своето изпълнение. Това време се счита само в гостуващите операционни системи в средите на виртуализация. Причините, поради които тези ресурси не достигат, както в живота, са доста неясни. Но ние решихме да разгледаме въпроса, дори проведохме цял ред експерименти. Не можем да кажем, че вече знаем всичко за steal, но ще споделим някои интересни факти.
1. Какво е steal
И така, steal е метрика, която показва недостига на процесорно време за процесите в рамките на виртуалната машина. Как е описано , steal е времето, през което хипервизорът извършва други процеси на хостващата ОС, докато е поставил процеса на виртуалната машина в опашка за изпълнение. Тоест, steal се счита за разликата между времето, когато процесът е готов за изпълнение, и времето, когато му е предоставено процесорно време.
Метриката steal се получава от ядрото на виртуалната машина от хипервизора. При това, хипервизорът не уточнява какви точно други процеси изпълнява, просто казва „докато съм зает, не мога да ти дам време“. В KVM, поддръжката на изчисляването на steal е добавена в Ключовите моменти тук са два:
- Виртуалната машина научава за steal от хипервизора. Тоест, от гледна точка на загуби, за процесите на самата виртуалка, това е непряко измерване, което може да бъде подложено на различни изкривявания.
- Хипервизорът не споделя с виртуалката информация за това с какво друго е зает — важното е, че не отделя време за нея. Поради това самата виртуалка не може да установи изкривявания в показателя steal, които биха могли да се оценят по характера на конкуриращите процеси.
2. Какво влияе на steal
2.1. Изчисляване на steal
По същество, steal се изчислява по подобен начин на обикновеното време на използване на процесора. Информацията за това как се изчислява използването не е много. Вероятно защото повечето смятат този въпрос за очевиден. Но и тук може да има подводни камъни. За запознаване с този процес можете да прочетете : ще се запознаете с куп нюанси при изчисляването на натовареността и с ситуации, когато това изчисление може да е погрешно по следните причини:
- Прегряване на процесора, при което се пропускат тактове.
- Включване/изключване на turbo boost, в резултат на което се променя тактовата честота на процесора.
- Промяна на продължителността на времевия квант, която настъпва при използване на технологии за пестене на енергия от процесора, например SpeedStep.
- Проблемът с изчисляването на средната стойност: оценка на натовареността в рамките на една минута на ниво 80% може да скрие краткотрайно избухване на 100%.
- Цикличното блокиране (spin lock) води до това, че процесорът е натоварен, но потребителският процес не вижда напредък в изпълнението си. В резултат на това изчислената натовареност на процесора от процеса ще бъде сто процента, въпреки че физически времето на процесора няма да се консумира.
Статии, описващи подобно изчисление за steal, не намерих (ако знаете - споделете в коментарите). Но, съдейки по източниците, механизмът на изчисление е същият като за натовареността. Просто в ядрото се добавя още един брояч, директно за процеса KVM (процес на виртуалната машина), който брои продължителността на престоя на процеса KVM в състояние на изчакване на времето на процесора. Броячът взема информация за процесора от неговата спецификация и проверява дали всички негови тактове са били използвани от виртуалната машина. Ако всички, считаме, че процесорът е работил само по процеса на виртуалната машина. В противен случай информираме, че процесорът е работил и по нещо друго, е появил се steal.
Процесът на изчисление на steal е подложен на същите проблеми, каквито е обикновеното изчисление на натовареността. Не казвам, че такива проблеми се появяват често, но изглеждат обезкуражаващо.
2.2. Типове виртуализация на KVM
Като цяло има три типа виртуализация, и всички те се поддържат от KVM. От типа виртуализация може да зависи механизмът на появяване на steal.
Транслация. В този случай работата на операционната система на виртуалната машина с физическите устройства на хипервизора протича приблизително така:
- Гостоприемната операционна система изпраща команда на своето гостувано устройство.
- Драйверът на гостуващото устройство приема команда, формира заявка за BIOS на устройството и я изпраща в хипервизора.
- Хипервизорният процес извършва транслация на команди в команди за физическото устройство, правейки я, между другото, и по-безопасна.
- Драйверът на физическото устройство приема модифицираната команда и я изпраща директно на самото физическо устройство.
- Резултатите от изпълнението на командите се връщат по същия маршрут.
Предимството на транслацията е, че тя позволява емулация на всяко устройство и не изисква специална настройка на ядрото на операционната система. Но за това се плаща, най-вече, с производителността.
Аппаратна виртуализация. В този случай устройството на хардуерно ниво разбира командите от операционната система. Това е най-бързият и ефективен начин. Но, за съжаление, не всички физически устройства, хипервизори и операционни системи за гости го поддържат. В момента основните устройства, които поддържат аппаратна виртуализация, са процесорите.
Паравиртуализация (paravirtualization). Най-разпространеният вариант за виртуализация на устройства на KVM и изобщо най-разпространеният режим на виртуализация за операционни системи за гости. Характеристиката му е, че работата с някои подсистеми на хипервизора (например, мрежовия или дисковия стек) или разпределение на страници памет се осъществява чрез API на хипервизора, без транслация на низкостепенни команди. Недостатък на този метод на виртуализация е необходимостта от модификация на ядрото на гостоприемната операционна система, за да взаимодействува с хипервизора чрез това API. Обикновено това се решава чрез инсталиране на специални драйвери в гостоприемната операционна система. В KVM това API се нарича .
При паравиртуализация, в сравнение с транслацията, пътят до физическото устройство значително се съкращава благодарение на директното изпращане на команди от виртуалната машина към процеса на хипервизора на хоста. Това позволява ускоряване на изпълнението на всички инструкции в рамките на виртуалната машина. В KVM за това отговаря virtio API, който работи само за определени устройства, като мрежовия или дисковия адаптер. Именно затова в виртуалните машини се използват virtio-драйвери.
Недостатъкът на такова ускорение е, че не всички процеси, които се изпълняват вътре в виртуалната машина, остават вътре в нея. Това създава някои специални ефекти, които могат да доведат до появата на steal. Препоръчвам да започнете подробно проучване на този въпрос с .
2.3. „Справедливо“ разпределение на ресурси
Виртуалната машина на хипервизора е по същество обикновен процес, който подлежи на законите на разпределението на ресурсите (шедулинга) в ядрото на Linux, затова нека да го разгледаме по-подробно.
В Linux се използва т. нар. CFS, Completely Fair Scheduler, който от версия 2.6.23 стана диспетчер по подразбиране. За да разберете този алгоритъм, можете да прочетете Linux Kernel Architecture или изходния код. Същността на CFS е в разпределението на процесорно време между процесите в зависимост от времето, необходимо за тяхното изпълнение. Колкото повече процесорно време изисква един процес, толкова по-малко получава. Това гарантира „честно“ изпълнение на всички процеси — за да не може един процес постоянно да заема всички процесори, а и другите процеси да имат шанс за изпълнение.
Понякога тази парадигма води до интересни артефакти. Дългогодишните потребители на Linux със сигурност помнят как стандартният текстов редактор на десктопа замръзва по време на стартиране на ресурсоемки приложения като компилатори. Това се получавало, защото нересурсоемките задачи на десктоп приложенията конкурирали с активно ресурсопотребяващите задачи, такива като компилаторите. CFS счита, че това е нечестно, затова периодично спира текстовия редактор и позволява на процесора да обработи задачите на компилатора. Това бе коригирано с помощта на механизма , но останаха много други особености в разпределението на процесорното време между задачите. Всъщност, това не е разказ за лошото функциониране на CFS, а опит да се обърне внимание на факта, че „честното“ разпределение на процесорното време не е тривиална задача.
Още един важен момент в шедулера — preemption. Това е необходимо, за да се изгони заемащия процесор процес и да се даде възможност на другите да заработят. Процесът на изгонване се нарича context switching, превключване на контекста на процесора. При това се запазва целият контекст на задачата: състоянието на стека, регистрите и други, след което процесът е изпратен да чака, а на негово място застава друг. Това е скъпа операция за ОС и се използва рядко, но по същността си няма нищо лошо в нея. Честото превключване на контекста може да говори за проблем в ОС, но обикновено те протичат непрекъснато и не указват нищо особено.
Тази дълга история е необходима, за да обясни един факт: колкото повече ресурси на процесора се опитва да консумира процес в честен шедулер на Linux, толкова по-бързо ще бъде спиран, за да могат и другите процеси да работят. Правилно ли е това или не — сложен въпрос, който се решава по различен начин при различни натоварвания. В Windows до неотдавна шедулерът беше насочен към приоритетна обработка на десктоп приложения, поради което фоновите процеси можеха да се блокират. В Sun Solaris имаше пет различни класа шедулери. Когато беше пусната виртуализацията, добавиха шести, , защото предишните пет не работиха адекватно с виртуализацията на Solaris Zones. Подробното изучаване на този въпрос препоръчвам да започнете с книги като или .
2.4. Как да следим steal?
Следенето на steal вътре във виртуалната машина, както и на всяка друга метрика на процесора, е просто: можете да използвате всяко средство за извличане на метрики на процесора. Важно е виртуалката да е на Linux. Windows по някаква причина не предоставя такава информация на своите потребители. 🙁

Изход на команда top: детайли за натоварването на процесора, в крайната десна колона — steal
Трудности възникват при опити за извличане на тази информация от хипервизора. Можете да опитате да предскажете steal на хост машината, например, по параметъра Load Average (LA) — средното количество на процесите, които чакат в опашката за изпълнение. Методиката на изчисление на този параметър не е проста, но като цяло, ако нормализираният спрямо броя на нишките на процесора LA е над 1, това говори, че сървърът с Linux е претоварен по някакъв начин.
Какво всъщност очакват всички тези процеси? Очевидният отговор е - процесора. Но отговорът не е съвсем точен, тъй като понякога процесорът е свободен, а LA е в горна стойност. Спомнете си, По подобен начин може да се случи и с диска, и с другите устройства за вход/изход. Всъщност, процесите могат да чакат завършването на всяка блокировка, както физическа, свързана с устройството за вход/изход, така и логическа, например мютекс. Тук попадат и блокировките на ниво хардздраве (същия отговор от диска) или логика (т.нар. блокиращи примитиви, които включват много същности, адаптивни мютекси и въртящи, семафори, променливи на условията, rw заключвания, ipc заключвания…).
Още една особеност на LA е, че тя се счита като средна стойност за операционната система. Например, 100 процеса се конкурират за един файл, и тогава LA=50. Тази голяма стойност, изглежда, говори за това, че операционната система е в лошо състояние. Но за друг некачествено написан код, това може да е нормално състояние, при което само той страда, а другите процеси в операционната система не са засегнати.
Поради това усредняване (като минимум за една минута), определянето на нещо по показателя LA - не е най-благодарната задача с много неопределени резултати в конкретни случаи. Ако се опитате да проучите, ще откриете, че в статии на Уикипедия и други достъпни ресурси са описани само най-простите случаи, без дълбоко обяснение на процеса. Всички заинтересовани насочвам отново, — по-нататък чрез линковете. На когото му е мързел да чете на английски — .
3. Специални ефекти
Сега ще се спрем на основните случаи на появата на steal, с които сме се сблъсквали. Ще разкажа как произтичат от всичко казано дотук и как се отнасят към показателите на хипервизора.
Преупотребление. Най-простото и често: хипервизорът е преупотребен. В действителност, много стартирани виртуални машини, голямо потребление на процесор вътре в тях, голяма конкуренция, утилизация по LA над 1 (в нормализация по процесорни нишки). Вътре в цялата виртуализация всичко забавя. Steal, предаван от хипервизора, също нараства, необходима е переразпределение на натоварването или изключване на някой. В общи линии, всичко е логично и ясно.
Паравиртуализация срещу самостоятелни инстанции. На хипервизора има само една виртуалка, която консумира малка част от него, но предизвиква голямо натоварване при вход/изход, например по диска. И отнякъде в нея се появява малък steal, до 10 % (както показват няколко проведени експеримента).
Интересен случай. Steal тук се появява именно поради блокировките на ниво паравиртуализирани драйвери. Вътре във виртуалката се създава прекъсване, обработва се от драйвера и попада в хипервизора. Поради обработката на прекъсването, за виртуалката това изглежда като изпратена заявка, тя е готова за изпълнение и чака процесор, но не получава време на процесора. Виртуалката мисли, че това време е откраднато.
Това се случва в момента на изпращане на буфера, който попада в kernel space на хипервизора, и започваме да го чакаме. Въпреки това, от гледна точка на виртуалката, той трябва да се върне веднага. Следователно, според алгоритъма за изчисляване на steal, това време се счита за откраднато. Вероятно в тази ситуация могат да съществуват и други механизми (напр. обработка на различни sys calls), но те не трябва да се различават значително.
Шедулера срещу високо натоварените виртуалки. Когато една виртуалка страда от steal повече от другите, това е свързано именно със шедулера. Колкото повече процесът натоварва процесора, толкова по-бързо шедулерът го изгонва, за да могат и останалите да работят. Ако виртуалката консумира малко, тя почти не ще забележи steal: нейният процес честно е седял и чакал, трябва да му се дава повече време. Ако виртуалката генерира максимално натоварване на всичките си ядра, тя по-често бива изгонвана от процесора и се стараят да не ѝ дават много време.
Още по-лошо е, когато процесите вътре във виртуалката се опитват да получат повече процесор, защото не се справят с обработката на данни. Тогава операционната система на хипервизора, чрез честна оптимизация, ще дава все по-малко процесорно време. Този процес протича лавинообразно и steal скача до небесата, въпреки че другите виртуалки почти не го забелязват. И колкото повече ядра, толкова по-зле за машината, попаднала под раздаването. Накратко, най-много страдат високо натоварените виртуалки с множество ядра.
Нисък LA, но има steal. Ако LA е около 0,7 (т.е. хипервизорът изглежда недозапълнен), но вътре в отделни виртуалки се наблюдава steal:
- Вече описаният по-горе вариант с паравиртуализация. Виртуалната машина може да получава метрики, указващи на steal, въпреки че хипервизорът не показва проблеми. Според резултатите от нашите експерименти, такъв steal не надвишава 10% и не би трябвало да оказва съществено влияние на производителността на приложенията вътре в виртуалната машина.
- Параметърът LA се счита неправилно. По-точно, в всеки конкретен момент той се счита вярно, но при усредняване за една минута резултатът е занижен. Например, ако една виртуална машина на третата хипервизор консумира всички свои процесори точно в продължение на половин минута, то LA за минутата на хипервизора ще бъде 0,15; четири такива виртуални машини, работещи одновременно, ще дадат 0,6. А фактът, че половин минута всяка от тях е имала steal около 25% по показателя LA, вече не може да се възстанови.
- Отново, поради шедулера, решил, че някой яде твърде много и той трябва да изчака. А аз междувременно ще превключа контекста, ще обработя прекъсванията и ще се заема с други важни системни задачи. В крайна сметка едни виртуални машини не виждат никакви проблеми, а други изпитват сериозно понижение на производителността.
4. Други изкривявания
Има още милион причини за изкривявания на честното възстановяване на процесорно време на виртуалната машина. Например, сложности в изчисленията внасят хипертрединг и NUMA. Те окончателно объркват избора на ядро за изпълнение на процеса, тъй като шедулерът използва коефициенти - тегла, които при превключване на контекста правят изчисленията още по-сложни.
Има изкривявания и поради технологии тип турбобуста или, обратно, режим на пестене на енергия, които при изчисляване на заетостта могат да повишават или понижават възможната честота или дори кванта на времето на сървъра. Включването на турбобуста намалява производителността на един процесорен нишка поради увеличаване на производителността на друг. В този момент информацията за актуалната честота на процесора не се предава на виртуалната машина и тя смята, че нейното време е откраднато (например, тя е искала 2 GHz, а е получила наполовина по-малко).
Общо, причините за изкривявания могат да бъдат много. В конкретната система можете да откриете нещо друго. Най-добре е да започнете с книги, за които дадох линкове по-горе, и да съберете статистика от хипервизора с инструменти като perf, sysdig, systemtap, и др. .
5. Изводи
- Някакво количество steal може да възникне поради паравиртуализация и може да се счита за нормално. В интернет пишат, че тази величина може да достигне 5-10%. Зависи от приложенията в рамките на виртуалната машина и от това какво натоварване тя дава на физическите устройства. Тук е важно да се обърне внимание на това, как се чувстват приложенията вътре в виртуалките.
- Съотношението между натоварването на хипервизора и steal в рамките на виртуалната машина не винаги е ясно взаимосвързано, и двете оценки на steal могат да бъдат погрешни в конкретни ситуации при различни натоварвания.
- Шедулерът не е благосклонен към процеси, които много искат. Той се опитва да дава по-малко на тези, които искат повече. Големите виртуалки са зло.
- Небольшият steal може да бъде норма и без паравиртуализация (с оглед на натоварването вътре във виртуалката, особеностите на натоварването на съседите, разпределението на натоварването по нишки и други фактори).
- Ако искате да разберете steal в конкретна система, трябва да изследвате различни варианти, да събирате метрики, да ги анализирате внимателно и да размишлявате как да разпределите натоварването равномерно. От всякакви случаи са възможни отклонения, които трябва да бъдат потвърдени експериментално или да се провери в дебъгера на ядрото.
Източник: habr.com
