Kradzież: kto kradnie czas procesora z maszyn wirtualnych

Kradzież: kto kradnie czas procesora z maszyn wirtualnych

Cześć! Chcę Wam w prosty sposób opowiedzieć o mechanice kradzieży wewnątrz maszyn wirtualnych oraz o kilku nieoczywistych artefaktach, które udało nam się odkryć podczas jego badań, z którymi musiałem się zgłębić jako dyrektor techniczny platformy chmurowej Rozwiązania chmurowe Mail.ru. Platforma działa na KVM.

Czas kradzieży procesora to czas, w którym maszyna wirtualna nie otrzymuje zasobów procesora do wykonania. Czas ten jest liczony tylko w systemach operacyjnych gościa w środowiskach wirtualizacyjnych. Powody, dla których trafiają te najbardziej przydzielone zasoby, tak jak w życiu, są bardzo niejasne. Ale postanowiliśmy to rozgryźć i nawet przeprowadziliśmy szereg eksperymentów. To nie jest tak, że wiemy już wszystko o kradzieży, ale teraz powiemy Ci coś interesującego.

1. Co to jest kradzież

Zatem kradzież jest metryką wskazującą na brak czasu procesora dla procesów wewnątrz maszyny wirtualnej. Jak w opisie w łatce jądra KVMUkrycie to czas, w którym hiperwizor wykonuje inne procesy w systemie operacyjnym hosta, mimo że umieścił proces maszyny wirtualnej w kolejce do wykonania. Oznacza to, że kradzież oblicza się jako różnicę między czasem, w którym proces jest gotowy do wykonania, a czasem, w którym procesowi przydzielono czas procesora.

Jądro maszyny wirtualnej otrzymuje metrykę kradzieży z hiperwizora. Jednocześnie hypervisor nie określa dokładnie, jakie inne procesy uruchamia, po prostu mówi „skoro jestem zajęty, nie mogę dać ci czasu”. W KVM dodano obsługę obliczania kradzieży łaty. Są tu dwa kluczowe punkty:

  • Maszyna wirtualna dowiaduje się o kradzieży z hypervisora. Oznacza to, że z punktu widzenia strat dla procesów na samej maszynie wirtualnej jest to pomiar pośredni, który może podlegać różnym zniekształceniom.
  • Hiperwizor nie dzieli się z maszyną wirtualną informacjami o tym, co jeszcze robi - najważniejsze, że nie poświęca na to czasu. Z tego powodu sama maszyna wirtualna nie jest w stanie wykryć zniekształceń we wskaźniku kradzieży, co można ocenić na podstawie charakteru konkurencyjnych procesów.

2. Co wpływa na kradzież

2.1. Kradzież kalkulacji

Zasadniczo kradzież jest obliczana w przybliżeniu tak samo, jak normalny czas wykorzystania procesora. Niewiele jest informacji na temat tego, jak rozważa się recykling. Prawdopodobnie dlatego, że większość ludzi uważa to pytanie za oczywiste. Ale i tutaj są pułapki. Aby zapoznać się z tym procesem, możesz przeczytać artykuł Brendana Gregga: dowiesz się o wielu niuansach przy obliczaniu wykorzystania oraz o sytuacjach, w których to obliczenie będzie błędne z następujących powodów:

  • Procesor przegrzewa się, powodując pomijanie cykli.
  • Włącz/wyłącz turbo boost, które zmienia częstotliwość taktowania procesora.
  • Zmiana długości przedziału czasu występująca podczas korzystania z technologii oszczędzania energii procesora, takich jak SpeedStep.
  • Problem z obliczeniem średniej: oszacowanie wykorzystania jednej minuty na 80% może ukryć krótkotrwały wzrost na poziomie 100%.
  • Blokada spinu powoduje odzyskanie procesora, ale proces użytkownika nie widzi postępu w jego wykonaniu. W rezultacie obliczone wykorzystanie procesora przez proces będzie wynosić sto procent, chociaż proces nie będzie fizycznie zużywał czasu procesora.

Nie znalazłem artykułu opisującego podobne obliczenia dla kradzieży (jeśli wiesz, podziel się tym w komentarzach). Ale sądząc po kodzie źródłowym, mechanizm obliczeniowy jest taki sam jak w przypadku recyklingu. Po prostu w jądrze dodawany jest kolejny licznik, bezpośrednio dla procesu KVM (proces maszyny wirtualnej), który zlicza czas trwania procesu KVM oczekującego na czas procesora. Licznik pobiera informacje o procesorze z jego specyfikacji i sprawdza, czy wszystkie jego znaczniki są wykorzystane przez proces maszyny wirtualnej. Jeśli to wszystko, to zakładamy, że procesor był zajęty jedynie procesem maszyny wirtualnej. W przeciwnym razie informujemy, że procesor robił coś innego, pojawiła się kradzież.

Proces liczenia kradzieży wiąże się z tymi samymi problemami, co zwykłe liczenie surowców wtórnych. Nie chcę powiedzieć, że takie problemy pojawiają się często, ale wyglądają zniechęcająco.

2.2. Rodzaje wirtualizacji na KVM

Ogólnie rzecz biorąc, istnieją trzy typy wirtualizacji, z których wszystkie są obsługiwane przez KVM. Mechanizm wystąpienia kradzieży może zależeć od rodzaju wirtualizacji.

Transmisja. W tym przypadku działanie systemu operacyjnego maszyny wirtualnej z urządzeniami fizycznego hypervisora ​​wygląda mniej więcej tak:

  1. System operacyjny gościa wysyła polecenie do swojego urządzenia gościa.
  2. Sterownik urządzenia gościa otrzymuje polecenie, generuje żądanie dotyczące BIOS-u urządzenia i wysyła je do hiperwizora.
  3. Proces hypervisora ​​przekłada polecenie na polecenie dla urządzenia fizycznego, dzięki czemu jest ono między innymi bezpieczniejsze.
  4. Sterownik urządzenia fizycznego akceptuje zmodyfikowane polecenie i wysyła je do samego urządzenia fizycznego.
  5. Wyniki wykonania poleceń wracają tą samą ścieżką.

Zaletą tłumaczenia jest to, że pozwala emulować dowolne urządzenie i nie wymaga specjalnego przygotowania jądra systemu operacyjnego. Ale trzeba za to zapłacić przede wszystkim szybkością.

Wirtualizacja sprzętowa. W tym przypadku urządzenie na poziomie sprzętowym rozumie polecenia systemu operacyjnego. To najszybszy i najlepszy sposób. Ale niestety nie jest obsługiwany przez wszystkie urządzenia fizyczne, hypervisory i systemy operacyjne gościa. Obecnie głównymi urządzeniami obsługującymi wirtualizację sprzętową są procesory.

Parawirtualizacja. Najpopularniejsza opcja wirtualizacji urządzeń na KVM i ogólnie najczęstszy tryb wirtualizacji dla systemów operacyjnych gościa. Jego osobliwością jest to, że praca z niektórymi podsystemami hypervisora ​​(na przykład z siecią lub stosem dysków) lub alokacja stron pamięci odbywa się za pomocą API hypervisora, bez tłumaczenia poleceń niskiego poziomu. Wadą tej metody wirtualizacji jest to, że jądro systemu operacyjnego gościa musi zostać zmodyfikowane, aby mogło komunikować się z hiperwizorem za pomocą tego API. Ale zwykle rozwiązuje się to poprzez zainstalowanie specjalnych sterowników w systemie operacyjnym gościa. W KVM to API nazywa się wirtualne API.

W przypadku parawirtualizacji, w porównaniu z rozgłaszaniem, droga do urządzenia fizycznego jest znacznie skrócona poprzez wysyłanie poleceń bezpośrednio z maszyny wirtualnej do procesu hypervisora ​​na hoście. Pozwala to przyspieszyć wykonywanie wszystkich instrukcji wewnątrz maszyny wirtualnej. W KVM odbywa się to poprzez API virtio, które działa tylko w przypadku niektórych urządzeń, takich jak karta sieciowa lub dyskowa. Właśnie dlatego sterowniki virtio są instalowane wewnątrz maszyn wirtualnych.

Wadą tego przyspieszenia jest to, że nie wszystkie procesy uruchamiane wewnątrz maszyny wirtualnej pozostają w niej. Tworzy to pewne efekty specjalne, które mogą skutkować pojawieniem się po kradzieży. Zalecam rozpoczęcie szczegółowego przestudiowania tego problemu od Interfejs API dla wirtualnych wejść/wyjść: virtio.

2.3. „Uczciwy” harmonogram

Maszyna wirtualna na hypervisorze to tak naprawdę zwykły proces, który podlega prawom planowania (dystrybucji zasobów pomiędzy procesami) w jądrze Linuksa, więc przyjrzyjmy się jej bliżej.

Linux używa tak zwanego CFS, Completely Fair Scheduler, który stał się domyślnym harmonogramem od jądra 2.6.23. Aby zrozumieć ten algorytm, możesz przeczytać architekturę jądra Linux lub kod źródłowy. Istotą CFS jest podział czasu procesora pomiędzy procesy w zależności od czasu ich wykonywania. Im więcej czasu procesora wymaga proces, tym mniej czasu procesora otrzymuje. Zapewnia to, że wszystkie procesy są wykonywane „sprawiedliwie” – tak, że jeden proces nie zajmuje stale wszystkich procesorów, a inne procesy również mogą być wykonywane.

Czasami ten paradygmat prowadzi do interesujących artefaktów. Długoletni użytkownicy Linuksa prawdopodobnie pamiętają zawieszanie się zwykłego edytora tekstu na komputerze stacjonarnym podczas uruchamiania aplikacji wymagających dużych zasobów, takich jak kompilator. Stało się tak, ponieważ zadania w aplikacjach komputerowych niewymagające dużych zasobów konkurowały z zadaniami wymagającymi dużych zasobów, takimi jak kompilator. CFS uważa, że ​​jest to niesprawiedliwe, więc okresowo zatrzymuje edytor tekstu i pozwala procesorowi zająć się zadaniami kompilatora. Naprawiono to za pomocą mechanizmu sched_autogroup, ale pozostało wiele innych cech podziału czasu procesora pomiędzy zadaniami. Właściwie nie jest to opowieść o tym, jak źle wszystko jest w CFS, ale próba zwrócenia uwagi na fakt, że „sprawiedliwy” podział czasu procesora nie jest zadaniem najbardziej trywialnym.

Kolejnym ważnym punktem harmonogramu jest wywłaszczanie. Jest to konieczne, aby wyrzucić proces chichotania z procesora i pozwolić innym pracować. Proces wyrzucania nazywany jest przełączaniem kontekstu. W tym przypadku zostaje zachowany cały kontekst zadania: stan stosu, rejestrów itp., po czym proces jest wysyłany do oczekiwania, a na jego miejsce zajmuje inny. Jest to kosztowna operacja dla systemu operacyjnego i jest rzadko używana, ale nie ma w niej nic złego. Częste przełączanie kontekstu może wskazywać na problem w systemie operacyjnym, ale zwykle ma charakter ciągły i nie wskazuje na nic konkretnego.

Tak długa historia jest potrzebna, aby wyjaśnić jeden fakt: im więcej zasobów procesora próbuje zużyć proces w uczciwym Linuxie, tym szybciej zostanie zatrzymany, aby inne procesy mogły również działać. To, czy jest to prawidłowe, czy nie, jest złożonym pytaniem, które można rozwiązać w różny sposób przy różnych obciążeniach. Do niedawna w systemie Windows harmonogram skupiał się na priorytetowym przetwarzaniu aplikacji komputerowych, co mogło powodować zawieszanie się procesów w tle. Sun Solaris miał pięć różnych klas programów planujących. Kiedy uruchomiliśmy wirtualizację, dodaliśmy szóstą, Harmonogram sprawiedliwego udostępniania, ponieważ poprzednie pięć nie działało odpowiednio z wirtualizacją Solaris Zones. Zalecam rozpoczęcie szczegółowego przestudiowania tego zagadnienia od książek takich jak Elementy wewnętrzne Solarisa: architektura jądra Solaris 10 i OpenSolaris lub Zrozumienie jądra Linuksa.

2.4. Jak monitorować kradzież?

Monitorowanie kradzieży wewnątrz maszyny wirtualnej, podobnie jak w przypadku innych wskaźników procesora, jest proste: można użyć dowolnego narzędzia do pomiaru parametrów procesora. Najważniejsze jest to, że maszyna wirtualna jest na Linuksie. Z jakiegoś powodu system Windows nie udostępnia tych informacji swoim użytkownikom. 🙁

Kradzież: kto kradnie czas procesora z maszyn wirtualnych
Dane wyjściowe górnego polecenia: szczegóły obciążenia procesora, w skrajnej prawej kolumnie - kradzież

Trudność pojawia się przy próbie uzyskania tych informacji od hiperwizora. Możesz spróbować przewidzieć kradzież na komputerze hosta, na przykład wykorzystując parametr Load Average (LA) - średnią wartość liczby procesów oczekujących w kolejce wykonawczej. Metoda obliczania tego parametru nie jest prosta, ale ogólnie rzecz biorąc, jeśli LA znormalizowany przez liczbę wątków procesora jest większy niż 1, oznacza to, że serwer Linux jest czymś przeciążony.

Na co czekają te wszystkie procesy? Oczywistą odpowiedzią jest procesor. Ale odpowiedź nie jest do końca poprawna, ponieważ czasami procesor jest darmowy, ale LA wykracza poza skalę. Pamiętać jak upada NFS i jak rośnie LA. To samo może się zdarzyć z dyskiem i innymi urządzeniami wejścia/wyjścia. Ale w rzeczywistości procesy mogą czekać na koniec dowolnej blokady, fizycznej, powiązanej z urządzeniem we/wy, lub logicznej, takiej jak muteks. Dotyczy to także blokowania na poziomie hardware (ta sama odpowiedź z dysku), czy logiki (tzw. prymitywy blokujące, na które składa się masa bytów, mutex adaptacyjny i spinowy, semafory, zmienne warunkowe, blokady rw, blokady ipc ...).

Inną cechą LA jest to, że jest uważany za średnią systemu operacyjnego. Na przykład o jeden plik konkuruje 100 procesów, a wtedy LA=50. Tak duża wartość wydaje się wskazywać na zły system operacyjny. Ale w przypadku innego krzywo napisanego kodu może to być stan normalny, mimo że tylko on jest zły i inne procesy w systemie operacyjnym nie cierpią.

Z powodu tego uśredniania (w czasie nie krótszym niż minuta) określenie czegokolwiek za pomocą wskaźnika LA nie jest najbardziej satysfakcjonującym zadaniem, a wyniki w konkretnych przypadkach są bardzo niepewne. Jeśli spróbujesz to rozgryźć, przekonasz się, że artykuły w Wikipedii i innych dostępnych zasobach opisują tylko najprostsze przypadki, bez głębokiego wyjaśnienia procesu. Wszystkim zainteresowanym przesyłam jeszcze raz tutaj, do Brendana Gregga  - skorzystaj z poniższych linków. Kto jest zbyt leniwy, aby mówić po angielsku - tłumaczenie jego popularnego artykułu o Los Angeles.

3. Efekty specjalne

Przyjrzyjmy się teraz głównym przypadkom kradzieży, z którymi się zetknęliśmy. Opowiem Ci, jak wynikają one z powyższego i jak odnoszą się do wskaźników na hypervisorze.

Recykling. Najprostszy i najczęstszy: ponownie wykorzystano hypervisor. Rzeczywiście, jest dużo uruchomionych maszyn wirtualnych, duże zużycie procesora w nich, duża konkurencja, wykorzystanie LA jest większe niż 1 (znormalizowane przez wątki procesora). Wszystko wewnątrz wszystkich maszyn wirtualnych zwalnia. Rośnie również kradzież przesyłana z hypervisora, konieczna jest redystrybucja obciążenia lub wyłączenie kogoś. Generalnie wszystko jest logiczne i zrozumiałe.

Parawirtualizacja a pojedyncze instancje. Na hypervisorze znajduje się tylko jedna maszyna wirtualna; zużywa jej niewielką część, ale generuje duże obciążenie we/wy, na przykład na dysku. I skądś pojawia się w nim niewielka kradzież, aż do 10% (jak pokazało kilka eksperymentów).

Sprawa jest interesująca. Kradzież pojawia się tutaj właśnie z powodu blokowania na poziomie parawirtualnych sterowników. Wewnątrz maszyny wirtualnej tworzone jest przerwanie, przetwarzane przez sterownik i wysyłane do hypervisora. Ze względu na obsługę przerwań na hypervisorze, dla maszyny wirtualnej wygląda to jak wysłane żądanie, jest gotowe do wykonania i oczekuje na procesor, ale nie ma podanego czasu procesora. Wirtualna dziewczyna uważa, że ​​ten czas został skradziony.

Dzieje się tak w momencie wysłania bufora, trafia on do przestrzeni jądra hypervisora ​​i zaczynamy na niego czekać. Chociaż z punktu widzenia maszyny wirtualnej powinien natychmiast wrócić. Dlatego zgodnie z algorytmem obliczania kradzieży ten czas jest uważany za skradziony. Najprawdopodobniej w tej sytuacji mogą istnieć inne mechanizmy (na przykład przetwarzanie innych wywołań sys), ale nie powinny one się zbytnio różnić.

Harmonogram a mocno obciążone maszyny wirtualne. Kiedy jedna maszyna wirtualna jest bardziej narażona na kradzież niż inne, jest to spowodowane przez program planujący. Im bardziej proces obciąża procesor, tym szybciej program planujący go wyrzuci, aby inne procesy również mogły działać. Jeśli maszyna wirtualna zużywa niewiele, prawie nie zauważy kradzieży: jej proces uczciwie siedział i czekał, musimy dać jej więcej czasu. Jeśli maszyna wirtualna powoduje maksymalne obciążenie wszystkich swoich rdzeni, często jest wyrzucana z procesora i starają się nie dawać jej dużo czasu.

Jeszcze gorzej jest, gdy procesy wewnątrz maszyny wirtualnej próbują uzyskać większy procesor, bo nie radzą sobie z przetwarzaniem danych. Wtedy system operacyjny na hypervisorze, dzięki uczciwej optymalizacji, będzie zapewniał coraz mniej czasu procesora. Proces ten przebiega jak lawina i kradnie skoki w przestworza, chociaż inne maszyny wirtualne mogą go prawie nie zauważyć. Im więcej rdzeni, tym gorsza maszyna, której dotyczy problem. Krótko mówiąc, najbardziej cierpią bardzo obciążone maszyny wirtualne z wieloma rdzeniami.

Niskie LA, ale jest kradzież. Jeśli LA wynosi około 0,7 (tzn. hiperwizor wydaje się być niedociążony), ale wewnątrz poszczególnych maszyn wirtualnych obserwuje się kradzież:

  • Opcja z parawirtualizacją opisana już powyżej. Maszyna wirtualna może odbierać metryki wskazujące kradzież, chociaż hiperwizor działa prawidłowo. Zgodnie z wynikami naszych eksperymentów, opcja kradzieży nie przekracza 10% i nie powinna mieć znaczącego wpływu na wydajność aplikacji wewnątrz maszyny wirtualnej.
  • Parametr LA jest obliczany niepoprawnie. Dokładniej, w każdym konkretnym momencie jest on obliczany poprawnie, ale uśredniony w ciągu jednej minuty okazuje się zaniżony. Na przykład, jeśli jedna maszyna wirtualna na jedną trzecią hiperwizora zużywa wszystkie procesory przez dokładnie pół minuty, wówczas LA na minutę na hiperwizorze będzie wynosić 0,15; cztery takie maszyny wirtualne pracujące jednocześnie dadzą 0,6. A faktu, że przez pół minuty na każdym z nich doszło do dzikiej kradzieży na poziomie 25% według wskaźnika LA, nie da się już wyciągnąć.
  • Znowu z powodu planisty, który zdecydował, że ktoś jadł za dużo i pozwolił temu komuś poczekać. W międzyczasie zmienię kontekst, obsłużę przerwania i zajmę się innymi ważnymi sprawami systemowymi. W rezultacie niektóre maszyny wirtualne nie widzą żadnych problemów, podczas gdy inne doświadczają poważnego spadku wydajności.

4. Inne zniekształcenia

Istnieje jeszcze milion powodów zakłócania sprawiedliwego zwrotu czasu procesora na maszynie wirtualnej. Na przykład hiperwątkowość i NUMA wprowadzają trudności w obliczeniach. Całkowicie mylą wybór jądra do wykonania procesu, ponieważ planista stosuje współczynniki - wagi, które jeszcze bardziej utrudniają obliczenia przy przełączaniu kontekstu.

Występują zniekształcenia spowodowane technologiami takimi jak turbo boost lub odwrotnie, tryb oszczędzania energii, który przy obliczaniu wykorzystania może sztucznie zwiększać lub zmniejszać częstotliwość, a nawet przedział czasu na serwerze. Włączenie Turbo Boost zmniejsza wydajność jednego wątku procesora ze względu na wzrost wydajności innego. W tej chwili informacja o aktualnej częstotliwości procesora nie jest przekazywana do maszyny wirtualnej i uważa ona, że ​​ktoś kradnie jej czas (np. zażądała 2 GHz, ale otrzymała połowę tego).

Ogólnie rzecz biorąc, przyczyn zniekształceń może być wiele. Możesz znaleźć coś innego w konkretnym systemie. Lepiej zacząć od książek do których linki dałem powyżej i pobierania statystyk z hypervisora ​​za pomocą narzędzi takich jak perf, sysdig, systemtap, w tym dziesiątki.

5. Wnioski

  1. W wyniku parawirtualizacji może nastąpić pewna kradzież i można to uznać za normalne. W Internecie piszą, że wartość ta może wynosić 5-10%. Zależy od aplikacji znajdujących się wewnątrz maszyny wirtualnej i od obciążenia, jakie wywiera ona na swoje urządzenia fizyczne. W tym miejscu należy zwrócić uwagę na to, jak aplikacje czują się w maszynach wirtualnych.
  2. Stosunek obciążenia hiperwizora i kradzieży wewnątrz maszyny wirtualnej nie zawsze są ze sobą wyraźnie powiązane; oba szacunki kradzieży mogą być błędne w określonych sytuacjach i przy różnym obciążeniu.
  3. Osoba planująca ma złe podejście do procesów, które zadają dużo pytań. Stara się dawać mniej tym, którzy proszą o więcej. Duże maszyny wirtualne są złe.
  4. Mała kradzież może być normą nawet bez parawirtualizacji (biorąc pod uwagę obciążenie wewnątrz maszyny wirtualnej, charakterystykę obciążenia sąsiadów, rozkład obciążenia między wątkami i inne czynniki).
  5. Jeśli chcesz wykryć kradzież w konkretnym systemie, musisz zbadać różne opcje, zebrać dane, dokładnie je przeanalizować i zastanowić się, jak równomiernie rozłożyć obciążenie. Możliwe są odstępstwa od wszelkich przypadków, które należy potwierdzić eksperymentalnie lub sprawdzić w debugerze jądra.

Źródło: www.habr.com

Dodaj komentarz