...

Kernel Samepage Merging: KSM dla lepszej wydajności wirtualizacji

Wirtualizacja KSM zmniejsza fizyczne zapotrzebowanie na pamięć RAM poprzez to, że jądro systemu Linux łączy identyczne strony pamięci z różnych maszyn wirtualnych i efektywnie je współdzieli za pomocą mechanizmu „copy-on-write”. W ten sposób zwiększam gęstość maszyn wirtualnych, łagodzę wąskie gardła pamięci RAM i utrzymuję Wydajność w równowadze.

Punkty centralne

Poniższe kluczowe stwierdzenia pomagają mi szybko zrozumieć, na czym polega KSM, i wykorzystywać tę metodę w sposób ukierunkowany na cel:

  • Deduplikacja Identyczne strony pamięci znacznie zmniejszają zużycie pamięci RAM.
  • Kopiowanie przy zapisie umożliwia wspólne przeglądanie stron i rozdziela je dopiero w przypadku wprowadzenia zmian.
  • Precyzyjna regulacja Parametry ksmd pozwalają zrównoważyć obciążenie procesora i oszczędności.
  • Lokalizacja NUMA zapobiega niepotrzebnym opóźnieniom w hostach z wieloma gniazdami.
  • Bezpieczeństwo wymaga selektywnego udostępniania w środowiskach wielodostępnych.

Czym jest KSM? Podstawy i przebieg

Z Łączenie stron pamięci w jądrze systemu Wątek jądra ksmd regularnie przeszukuje anonimowe strony prywatne oznaczone jako „mergeable“ i łączy treści identyczne na poziomie bitów. Korzystam z tego, że często wiele maszyn wirtualnych przechowuje w pamięci identyczne biblioteki, kody programowe lub komponenty systemu operacyjnego. KSM oznacza połączone strony jako Kopiowanie przy zapisie, dzięki czemu wszyscy goście odczytują tę samą stronę fizyczną, dopóki jeden z nich nie wykona operacji zapisu. Dopiero w momencie dostępu zapisu jądro tworzy dla tego procesu własną stronę, podczas gdy strona pierwotna pozostaje dalej współdzielona. Ważne: KSM nie deduplikuje stron systemu plików ani pamięci podręcznej stron, a ja muszę jawnie zwolnić pamięć na potrzeby scalania.

Wykorzystanie w środowiskach wirtualizacyjnych

W hostach z dużą liczbą podobnych maszyn wirtualnych KSM daje największy efekt, ponieważ strony redundantne występują bardzo często. W konfiguracjach KVM i chmurowych scalanie znacznie zmniejsza efektywne obciążenie pamięci RAM na gościa, zwiększając w ten sposób gęstość maszyn wirtualnych na serwerze. Praktyczne doświadczenia wskazują na możliwość uzyskania nawet o 300 % więcej systemów-gości przy odpowiednim dostrojeniu, bez zauważalnego pogorszenia czasu reakcji. Jeśli połączę KSM z Nadmierne zaangażowanie pamięci, dzięki czemu hosty są lepiej obciążone, a dostępna pamięć operacyjna wykorzystywana jest w bardziej ukierunkowany sposób. Dzięki współdzieleniu identycznych stron zmniejszam ryzyko wystąpienia szczytów obciążenia pamięci wymiany i uzyskuję płynne Krzywa wydajności przez wiele instancji.

Konfiguracja w systemie Linux i KVM

Aktywuję KSM za pomocą CONFIG_KSM w jądrze i steruję zachowaniem poprzez sysfs w katalogu /sys/kernel/mm/ksm/. Tam uruchamiam skanowanie (run), ustawiam intensywność (pages_to_scan, sleep_millisecs) i obserwuję zyski stron (pages_sharing). W dystrybucjach klasy korporacyjnej korzystam z usług takich jak ksm i ksmtuned, które automatycznie zwiększają lub zmniejszają intensywność w oparciu o progi wolnej pamięci RAM. Aby uzyskać precyzyjną kontrolę, celowo oznaczam obszary pamięci jako możliwe do scalania za pomocą madvise(MADV_MERGEABLE) lub prctl(PR_SET_MEMORY_MERGE). W środowiskach dynamicznych chętnie łączę KSM z Memory Ballooningaby zoptymalizować Przydzielanie pamięci RAM aby zachować elastyczność.

Osiągi i tuning: właściwa równowaga

Zyskuję przede wszystkim tam, gdzie pamięć RAM stanowi prawdziwe wąskie gardło, a rdzenie procesora pozostałyby niewykorzystane – wtedy KSM ogólną wydajność, ponieważ uruchamiam równolegle więcej maszyn wirtualnych. Wątek ksmd zużywa jednak czas procesora, dlatego zbyt agresywne parametry skanowania mogą zmniejszyć te korzyści. Zaczynam ostrożnie, mierzę wartości pages_sharing i pages_scanned oraz obserwuję opóźnienia pod obciążeniem, zanim zwiększę częstotliwość skanowania. Przy wystarczającej ilości wolnej pamięci RAM ograniczam aktywność ksmd i zwiększam obciążenie dopiero wtedy, gdy zaczyna brakować hostów. W ten sposób zachowuję dobry stosunek między Zysk z pamięci oraz obciążenie procesora.

Bezpieczeństwo i izolacja z obiektywnego punktu widzenia

Ponieważ kilku gości korzysta z tej samej strony fizycznej, biorę pod uwagę potencjalne Kanały boczne, które mogłyby pozyskać informacje na podstawie czasu działania lub wzorców dostępu. W wrażliwych konfiguracjach wielodostępnych (multi-tenant) selektywnie wyłączam współdzielenie stron (Page Sharing) dla określonych instancji lub hostów. Natomiast w przypadku mniej wrażliwych obciążeń z dużą liczbą podobnych gości KSM stanowi niezawodną metodę obniżania kosztów i zwiększania gęstości. Dokumentuję tę decyzję dla każdego klastra i prowadzę listę wyjątków dla szczególnie krytycznych maszyn wirtualnych. W ten sposób zapewniam Przejrzystość i ograniczam powierzchnię ataku, nie tracąc przy tym na wydajności.

NUMA, strony o dużej pojemności i interakcja

W systemach NUMA zwracam uwagę na Miejsce przechowywania i najlepiej pozwalam na scalanie KSM tylko w obrębie jednego węzła, aby operacje dostępu nie przebiegały przez wolne ścieżki. Zmniejsza to opóźnienia i pozwala utrzymać wysoką przepustowość na gniazdo. W połączeniu z technologią Huge Pages ograniczam liczbę nieudanych odwołań do TLB, ale muszę pamiętać, że duże strony zmieniają prawdopodobieństwo wystąpienia identycznych bitowo treści. Niektóre obciążenia bardziej korzystają z Huge Pages, inne z deduplikacji; weryfikuję to za pomocą testów porównawczych. Celem pozostaje maksymalizacja dostępu lokalnego oraz Pamięć zdalna których należy unikać.

Monitorowanie i zrozumienie wskaźników

Oceniam wpływ KSM na podstawie niewielkiej liczby, ale miarodajnych wskaźników: pages_sharing, pages_shared, pages_scanned, pages_unshared oraz full_scans. Jeśli wartość pages_sharing stabilnie rośnie, a obciążenie procesora utrzymuje się na umiarkowanym poziomie, oznacza to, że moja konfiguracja zmierza w pożądanym kierunku. Jeśli wartości pozostają na stałym poziomie, sprawdzam, czy goście w ogóle oznaczają pamięć jako „mergeable”. Dodatkowo obserwuję Host-Swap, opóźnienia maszyn wirtualnych (VM-Latenzen) oraz IO-Wait, aby na czas wykryć skutki uboczne. Pulpity nawigacyjne z szeregami czasowymi pokazują mi trendy, dzięki czemu mogę Korekty podejmuję decyzje w oparciu o dane.

Przykłady z praktyki i potencjał oszczędności

W klastrach testowych, w których znajdowały się dziesiątki podobnych maszyn wirtualnych z systemem Linux, zauważyłem dzięki KSM częściowo dwucyfrowe oszczędności pamięci RAM wyrażone w punktach procentowych, a tym samym zauważalnie wyższa gęstość. Obciążenia Java zawierające wiele identycznych klas i bibliotek przyniosły szczególnie spójne korzyści. Im bardziej jednorodne są instancje, tym bardziej zmniejsza się ich ślad pamięciowy; stosy heterogeniczne zapewniają mniejsze, ale nadal użyteczne wyniki. W połączeniu z prawidłowo skonfigurowanym overcommitem utrzymuję niskie koszty na instancję i obsługuję więcej usług na tym samym sprzęcie. W ten sposób powstaje wyraźny efekt gospodarczy przy przewidywalnej jakości.

KSM a alternatywy: różnice i wzajemne oddziaływanie

Stawiam na Portfolio uzupełniające techniki pamięciowe, które działają różnie w zależności od celu. KSM usuwa nadmiarowość zawartości pamięci RAM, podczas gdy ballooning dynamicznie odzyskuje pamięć dla gości, a Huge Pages zwiększa wydajność procesora. Żadna z tych technik nie zastępuje drugiej; łączę je w sposób ukierunkowany, w zależności od profilu obciążenia i docelowej gęstości. Początkującym poniższy przegląd pomoże szybciej dokonać wyboru. Kolejnym krokiem warto zapoznać się z KVM i Xen w porównaniu, aby Wybór platformy odpowiednio sklasyfikować.

Technologia Zadanie Przewaga Wada Odpowiedni dla
KSM Deduplikacja identycznych stron pamięci RAM Wysoki Oszczędność pamięci RAM w przypadku podobnych maszyn wirtualnych Dodatkowe obciążenie procesora spowodowane skanowaniem Wielu podobnych gości, hosty KVM
Memory Ballooning Dynamiczne odzyskiwanie magazynu gazu Lepiej Wykorzystanie przy zmiennym obciążeniu Każdy gość musi mieć sterownik do balonów Zróżnicowane profile obciążenia
Ogromne strony Większe rozmiary stron w celu zmniejszenia liczby nieudanych odwołań do TLB Wyższy Wydajność procesora w przypadku aplikacji wymagających dużej ilości pamięci Mniejsza szansa na deduplikację Bazy danych, środowiska JVM, silniki działające w pamięci
NUMA-pinning Powiązanie maszyn wirtualnych z lokalnymi węzłami pamięci masowej Stała Opóźnienie oraz przepustowość Mniejsza elastyczność w planowaniu Hosty wieloplatformowe, obciążenia, w których opóźnienia mają kluczowe znaczenie

Praktyczna aktywacja i podręczniki dla hostów

Na poziomie hosta kieruję się pragmatyzmem: uruchamiam ksm/ksmtuned i ustawiam wartości domyślne, które sprawdziły się w praktyce. Przykład:

Włączanie usług # (w zależności od dystrybucji)
systemctl enable --now ksm ksmtuned

Ręczne dostrajanie # (działa natychmiastowo, do momentu ponownego uruchomienia systemu)
echo 1 > /sys/kernel/mm/ksm/run
echo 1000 > /sys/kernel/mm/ksm/pages_to_scan
echo 50 > /sys/kernel/mm/ksm/sleep_millisecs

W libvirt zarządzam współdzieleniem pamięci dla poszczególnych maszyn wirtualnych. Domyślnie QEMU oznacza pamięć RAM gości jako „mergeable”. W przypadku szczególnie wrażliwych maszyn wirtualnych wyraźnie wyłączam współdzielenie:

 

W ten sposób stosuję jasną strategię: szerokie wdrażanie na serwerach z jednorodnymi obciążeniami oraz ukierunkowane wyłączenia w przypadku wyjątków.

Szczegółowe informacje na temat precyzyjnej regulacji parametrów KSM

  • run: 0 = wyłączone, 1 = włączone, 2 = wyłączone i usunięcie powiązań ze stronami, które zostały już usunięte. Używam opcji „2“ wyłącznie do konkretnych testów lub gdy chcę bezpiecznie cofnąć udostępnianie przed okresami konserwacji.
  • liczba_stron_do_zeskanowania: Liczba stron sprawdzanych w jednym cyklu. Wyższe wartości przyspieszają wykrywanie identycznych stron, ale zwiększają obciążenie procesora.
  • sleep_millisecs: Przerwa między cyklami. Dłuższe przerwy zmniejszają obciążenie systemowe, ale osiągnięcie poziomu stabilnych oszczędności zajmuje w tym przypadku więcej czasu.
  • merge_across_nodes: W przypadku hostów NUMA ustawiam tę wartość na 0, aby scalanie odbywało się wyłącznie w obrębie jednego węzła NUMA. Pozwala to zachować lokalność.
  • use_zero_pages: Jeśli ta opcja jest włączona, procesy efektywnie współdzielą strony zerowe z stroną zerową jądra. Zapewnia to „pewne“ oszczędności bez kosztów związanych z mechanizmem COW.

Za pomocą ksmtuned dynamicznie reguluję ustawienia na podstawie progów pamięci RAM. Gdy tylko zaczyna brakować wolnej pamięci, ksmtuned zwiększa prędkość skanowania (Npagen-Boost); gdy obciążenie spada, ponownie zmniejsza tę prędkość. W ten sposób uzyskuje się adaptacyjną, „oddychającą“ konfigurację bez konieczności ręcznej interwencji.

Interakcja z THP, Huge Pages i zjawiskiem ballooningu (zagłębienie tematu)

Transparent Huge Pages (THP) oraz Ogromne strony optymalizują wydajność procesora, podczas gdy KSM zmniejsza nadmiarowość w pamięci RAM. Biorę przy tym pod uwagę:

  • KSM działa na standardowych stronach o rozmiarze 4 KB. Stron THP (zazwyczaj o rozmiarze 2 MB) nie da się zduplikować. Im intensywniej działa THP, tym mniej danych ma do dyspozycji KSM.
  • W przypadku obciążeń, w których kluczowe znaczenie ma opóźnienie lub które są ograniczone wydajnością procesora, preferuję THP/Huge Pages. W przypadku hostów z ograniczoną pamięcią RAM i jednorodnymi maszynami wirtualnymi stawiam na KSM.
  • Funkcja Ballooning uzupełnia działanie KSM: sterownik Balloon zwraca wolną pamięć gazową do hosta. Jednocześnie KSM zmniejsza zapotrzebowanie poprzez konsolidację identycznych stron. Razem wygładzają one szczytowe obciążenia i zapobiegają przedwczesnemu swapowaniu.

Podejmuję decyzję na podstawie wyników testów: testy porównawcze z włączoną i wyłączoną funkcją THP/Huge Pages oraz z aktywnym KSM pokazują mi, która kombinacja zapewnia najlepszy stosunek kosztów do wydajności.

Modele zabezpieczeń i nowoczesne funkcje procesora

W środowiskach, w których ścisłe rozdzielenie klientów konsekwentnie wyłączam funkcję współdzielenia dla każdej maszyny wirtualnej i każdego hosta. Minimalizuje to boczne kanały przepływu informacji wynikające ze współdzielonych stron i ułatwia kontrole zgodności. Nowoczesne Szyfrowanie pamięci Na poziomie hosta/gościa (np. klucz na maszynę wirtualną) uniemożliwia to w praktyce sensowne scalanie KSM między gośćmi, ponieważ identyczne treści nie są już przechowywane w fizycznej pamięci RAM w postaci bitowo identycznej. W takich klastrach rezygnuję z intensywnego skanowania i utrzymuję ksmd raczej w trybie pasywnym, aby nie marnować zasobów procesora na próżno.

W przypadku mniej wrażliwych, ale jednorodnych klastrów pozostaję przy KSM jako ustawieniu domyślnym. Dokumentuję zasady dla każdego klastra: „Domyślnie włączone, wyjątki za pomocą nosharepages“ lub „Domyślnie wyłączone, udostępnianie tylko dla zdefiniowanych pul“ – oba rozwiązania są prawidłowe, o ile są wdrażane w sposób przejrzysty i powtarzalny.

Odpowiedniość obciążenia i antywzorce

KSM sprawdza się doskonale w przypadku jednolitych obciążeń z dużą liczbą instancji (np. wiele identycznych serwerów aplikacji, usług opartych na JVM, agentów). Mniejsze korzyści odnoszą:

  • Bardzo zmienne, krótkotrwałe alokacje (np. wiele małych, szybko zmieniających się buforów), ponieważ prawdopodobieństwo wystąpienia zjawiska COW jest wysokie.
  • Dane skompresowane, zaszyfrowane lub pseudolosowe – rzadko zdarzają się identyczne strony.
  • Duże bazy danych w pamięci z agresywnym odświeżaniem stron, gdy dane szybko się zmieniają. W takich przypadkach często przeważają zalety Huge Pages/THP.

W farmach kontenerowych KSM może również działać, o ile procesy oznaczają pamięć jako „mergeable”. W praktyce jednak skupiam się na KSM przede wszystkim w przypadku maszyn wirtualnych, ponieważ tam QEMU już ustawia niezbędne flagi madvise.

Rozwiązywanie problemów i typowe przeszkody

  • udostępnianie stron utknęło w martwym punkcie: Sprawdzam, czy QEMU/maszyny wirtualne faktycznie tworzą pamięć, którą można scalac (brak dyrektywy nosharepages w pliku XML libvirt), oraz czy działa ksmd. Jeśli wyniki pozostają niezmienne, obciążenie jest prawdopodobnie zbyt zróżnicowane.
  • Zbyt duże obciążenie procesora: Zwiększam wartość sleep_millisecs i/lub zmniejszam wartość pages_to_scan. Dodatkowo mogę wyłączyć scalanie między obszarami NUMA, aby zmniejszyć obszar przeszukiwania.
  • Nieoczekiwane skoki opóźnień: Sprawdzam, czy zdarzenia COW korelują ze szczytami obciążenia. W takich przypadkach zmniejszam częstotliwość skanowania lub tymczasowo wyłączam dane maszyny wirtualne z udziału w zasobach.
  • Przekroczenie limitu prowadzi do eskalacji w pamięci wymiany: KSM nie zastępuje planowania wydajności. Zawsze utrzymuję rezerwę wolnej pamięci RAM i reguluję ksmd wyłącznie jako bufor, a nie jako rozwiązanie awaryjne.

Planowanie, dobór rozmiarów i automatyzacja

Aby uzyskać przewidywalne wyniki, definiuję wartości docelowe dla każdego hosta:

  • Headroom: Stały procentowy bufor wolnej pamięci RAM, poniżej którego ksmtuned zaczyna działać bardziej agresywnie. W ten sposób przesuwam deduplikację na okresy rzeczywistego zapotrzebowania.
  • Sprawiedliwość: W przypadku nierównomiernego obciążenia dzielę pule (np. według projektu/środowiska), aby jednorodne maszyny wirtualne mogły wspólnie czerpać korzyści, a heterogeniczne nie „osłabiały“ ich wydajności.
  • Wartości graniczne: Ustalam limity maksymalnej częstotliwości skanowania i regularnie sprawdzam, czy oszczędności uzasadniają obciążenie procesora.

W dziedzinie automatyzacji traktuję KSM jako powtarzalny, wersjonowany zbiór procedur (np. moduły Systemd lub fragmenty kodu Cloud Init). W ten sposób zapewniam, że nowe hosty są uruchamiane z identycznym zestawem parametrów, a wszelkie odchylenia są szybko wykrywane.

Podsumowanie dla administratorów

Używam KSM, gdy hosty obsługują wiele podobnych maszyn wirtualnych, a pamięć RAM jest zasobem ograniczającym. Wówczas deduplikacja zapewnia największy efekt, podczas gdy za pomocą ksmtuned i parametrów sysfs precyzyjnie kontroluję obciążenie procesora. W konfiguracjach NUMA ograniczam scalanie do poziomu lokalnego, łączę KSM z ballooningiem i ogromnymi stronami pamięci oraz mierzę efekty za pomocą wskaźników pages_sharing i opóźnień. W przypadku wrażliwych systemów-gości celowo wyłączam współdzielenie i w przejrzysty sposób dokumentuję wyjątki. W ten sposób zwiększam gęstość, zapewnić niezawodne czasy reakcji i trwale obniżyć koszty w euro na instancję.

Artykuły bieżące

Serwer Linux z wizualizacją wskaźników dotyczących zjawiska „pressure stall” w centrum danych
Administracja

Linux PSI do precyzyjnej analizy wydajności i monitorowania

Linux PSI (Pressure Stall Information) pokazuje, w jakim stopniu procesor, pamięć i operacje wejścia/wyjścia spowalniają działanie systemu. Dowiedz się, jak włączyć PSI i wykorzystać je do precyzyjnego monitorowania wydajności.