Fragmentacja pamięci systemu Linux

20

Czy istnieje sposób na wykrycie fragmentacji pamięci w systemie Linux? Jest tak, ponieważ na niektórych długo działających serwerach zauważyłem spadek wydajności i dopiero po ponownym uruchomieniu procesu widzę lepszą wydajność. Zauważyłem to bardziej, gdy korzystam z obsługi ogromnych stron linuksa - czy ogromne strony w Linuksie są bardziej podatne na fragmentację?

W szczególności przyjrzałem się / proc / buddyinfo. Chcę wiedzieć, czy istnieją lepsze sposoby (nie tylko same komendy CLI, jakikolwiek program lub teoretyczne podstawy) by na to spojrzeć.

Raghu
źródło
Nie patrzę tylko na szybkie rozwiązania linii poleceń, wystarczy też każdy prosty program / teoria. Dlatego nie pytałem o awarię serwera.
Raghu
1
Nie rozumiem tutaj jednego punktu. O ile rozumiem fragmentacja pamięci musi prowadzić do braku pamięci, aw konsekwencji do błędów przydziału pamięci. Jednak pytasz o obniżenie wydajności. Czy to dlatego, że masz dużo pamięci zamienionej na dysk? A jeśli tak, co dać vmstatw tej dziedzinie so?
@skwllsp - Zredagowałem moją odpowiedź, aby była bardziej szczegółowa.
Tim Post
@Raghu - nie spodziewałbym się, że większość administratorów systemu zmodyfikuje kod jądra, aby zarządzanie pamięcią zachowywało się inaczej, jednak wykwalifikowani administratorzy Linuksa powinni wiedzieć przynajmniej o tym, jak Linux zarządza pamięcią. To pytanie jest naprawdę na linii. Głosowałem za jego migracją po prostu dlatego, że nie mogę zaproponować (w mojej odpowiedzi) kodu, który odpowie na twoje pytanie. Czytanie z / proc lub używanie vmstatjest powszechnym doświadczeniem użytkownika. Gdybyś pisał program, aby zrobić to samo, byłoby inaczej. Jeśli zamierzasz użyć bash do zebrania tych informacji, edytuj swoje pytanie, nie zostanie ono zamknięte :)
Tim Post
@Tim - Jak zasugerowałem, to nie tylko polecenia bash / cli, które chciałem wiedzieć, potrzebowałem tych informacji, aby pomóc mi w mojej procedurze testowania (do analizy wyników, a nie ich uruchamiania).
Raghu

Odpowiedzi:

12

Odpowiadam na tag . Moja odpowiedź dotyczy tylko Linuksa .

Tak, ogromne strony są bardziej podatne na fragmentację. Istnieją dwa widoki pamięci, jeden tworzony przez proces (wirtualny) i ten, którym jądro zarządza (rzeczywisty). Im większa dowolna strona, tym trudniej będzie pogrupować (i utrzymać ją) sąsiadów, szczególnie gdy twoja usługa działa w systemie, który również musi wspierać innych, którzy domyślnie przydzielają i zapisują znacznie więcej pamięci niż oni faktycznie używam.

Mapowanie jądra (rzeczywistych) przyznanych adresów jest prywatne. Jest bardzo dobry powód, dla którego przestrzeń użytkownika widzi je tak, jak przedstawia je jądro, ponieważ jądro musi być w stanie nadkomitować bez mylenia przestrzeni użytkownika. Twój proces staje się przyjemny, ciągły przestrzeń adresową „Disneyfied”, w której można pracować, nieświadomy tego, co jądro robi z tą pamięcią za kulisami.

Powód, dla którego widzisz obniżoną wydajność na długo działających serwerach, jest najprawdopodobniej dlatego, że przydzielone bloki, które nie zostały wyraźnie zablokowane (np. mlock()/ mlockall()Lub posix_madvise()) i nie zostały zmodyfikowane przez jakiś czas, zostały stronicowane , co oznacza, że ​​Twoja usługa przesuwa się na dysk, gdy musi czytać im. Zmodyfikowanie tego zachowania powoduje, że proces jest złym sąsiadem , dlatego wiele osób umieszcza RDBMS na zupełnie innym serwerze niż web / php / python / ruby ​​/ cokolwiek. Jedynym sposobem, aby to naprawić, jest rozsądnie, zmniejszyć konkurencję dla sąsiadujących bloków.

Fragmentacja jest naprawdę zauważalna (w większości przypadków), gdy strona A jest w pamięci, a strona B została przeniesiona do zamiany. Oczywiście ponowne uruchomienie usługi wydawałoby się „wyleczyć” to, ale tylko dlatego, że jądro nie miało jeszcze okazji przeskoczyć procesu (obecnie) nowo przydzielonym blokom w ramach swojego współczynnika nadmiaru.

W rzeczywistości ponowne uruchomienie (powiedzmy) „apache” pod dużym obciążeniem prawdopodobnie spowoduje wysłanie bloków należących do innych usług bezpośrednio na dysk. Tak więc „apache” poprawiłoby się na krótki czas, ale „mysql” może cierpieć ... przynajmniej do czasu, aż jądro sprawi, że będą cierpieć tak samo, gdy po prostu brakuje wystarczającej pamięci fizycznej.

Dodaj więcej pamięci lub podziel się wymagającymi malloc() klientów :) Nie chodzi tylko o fragmentację, na którą trzeba patrzeć.

Spróbuj vmstatuzyskać przegląd tego, co faktycznie jest przechowywane.

Tim Post
źródło
Dziękuję za Twoją odpowiedź. Użyłem ogromnych stron (rozmiar = 2048 KB każdy) dla mysql - pula buforów innodb - aby zobaczyć, jak dobrze sobie radzi (używając sysbench). Początkowo, gdy czas sprawności procesu (a nawet systemu) był niski, dawał bardzo dobre wyniki. Jednak jego wydajność zaczęła się pogarszać w kilku seriach. Jeśli chodzi o stronę, o której wspomniałeś, z pewnością zauważyłem wysoką aktywność VM, ale przypuszczałem, że mogło to być spowodowane testem porównawczym i opróżnianiem logów innodb (aktywność VM wyższa przy dużych stronach niż bez). Ustawiłem także vm.swappiness na 1. Nie zauważyłem żadnej drastycznej zmiany.
Raghu
Według dokładnego podręcznika „Ogromne strony nie mogą zostać zamienione pod presją pamięci”. Myślę, że jest to dobra odpowiedź w standardowej pamięci w / r / t, ale nie w przypadku stron o dużych rozmiarach.
Dan Pritts,
5

Jądro

Aby uzyskać bieżący indeks fragmentacji, użyj:

sudo cat /sys/kernel/debug/extfrag/extfrag_index

Aby zdefragmentować pamięć jądra, spróbuj wykonać:

sysctl vm.compact_memory=1  

Spróbuj także wyłączyć przezroczyste ogromne strony (inaczej THP) i / lub wyłączyć zamianę (lub zmniejszyć) swappiness ).

Przestrzeń użytkownika

Aby zmniejszyć fragmentację przestrzeni użytkownika, możesz wypróbować inny alokator, np. jemalloc(Ma świetne możliwości introspekcji , co da ci wewnętrzną fragmentację fragmentacji wewnętrznej alokatora).

Możesz przejść do niestandardowego malloc, kompilując z nim swój program lub po prostu uruchamiając program z LD_PRELOAD: LD_PRELOAD=${JEMALLOC_PATH}/lib/libjemalloc.so.1 app (uważaj na interakcje między THP i alokatorami pamięci) )

Chociaż jest to nieco niezwiązane z fragmentacją pamięci (ale związane z kompaktowaniem / migracją pamięci), prawdopodobnie chcesz uruchomić wiele wystąpień usługi, po jednym dla każdego węzła NUMA i powiązać je za pomocą numactl.

SaveTheRbtz
źródło
1
Dlaczego uważasz, że wyłączenie wymiany może pomóc? Wydaje mi się bardziej prawdopodobne, że wyłączenie wymiany będzie jeszcze bardziej boleć.
kasperd
1
Ponieważ w pierwotnym poście nie ma wystarczającej ilości informacji, być może proces po prostu przecieka i zaczyna się zamiana. Nie widzę też żadnych uzasadnionych powodów, aby używać swapa w prawie każdym systemie produkcyjnym (MB tylko dla wspólnych stacji roboczych dla studentów).
SaveTheRbtz
2
Posiadanie wystarczającej ilości przestrzeni wymiany poprawi wydajność. Problemy z wydajnością, które wystąpią, jeśli nie masz wystarczającej przestrzeni wymiany, są wystarczającym powodem do włączenia wymiany.
kasperd
1
@SaveTheRbtz Dobrym powodem do zastosowania wymiany w systemie produkcyjnym jest to, że daje on systemowi więcej opcji, z których będzie korzystał tylko wtedy, gdy uzna, że ​​są one korzystne. Pozwala także na usunięcie zmodyfikowanych stron, do których nie uzyskano dostępu w ciągu kilku godzin (i nigdy nie można uzyskać do nich dostępu), z cennej pamięci fizycznej. Wreszcie, pozwala to systemowi rozsądnie obsługiwać przypadki, w których zarezerwowanych jest znacznie więcej pamięci niż jest używane.
David Schwartz
2
„tylko jeśli uważa, że ​​są one korzystne” - to dodaje dodatkową heurystykę i sprawia, że ​​system jest mniej przewidywalny. Również algorytmy zastępowania stron (używane w swapie i anonimowe mmap) są różnie implementowane w różnych jądrach (np. Linux vs FreeBSD), a nawet w różnych wersjach tego samego systemu operacyjnego (2.6.32 vs 3.2 vs 3.10). ”Zezwala na zmodyfikowane strony [. ..] do wyrzucenia z [...] pamięci fizycznej ”- to ukryje wycieki pamięci. „radzi sobie z przypadkami, w których rezerwuje się znacznie więcej pamięci niż jest używana” - wolny system jest znacznie gorszy niż w dół, więc „rozsądny” jest wątpliwy.
SaveTheRbtz,
4

Korzystanie z dużych stron nie powinno powodować dodatkowej fragmentacji pamięci w systemie Linux; Obsługa dużych stron w systemie Linux dotyczy tylko pamięci współużytkowanej (za pomocą shmget lub mmap), a wszelkie używane ogromne strony muszą zostać specjalnie zażądane i wstępnie przydzielone przez administratora systemu. Raz w pamięci są tam przypięte i nie są wymieniane. Wyzwanie polegające na zamianie ogromnych stron w obliczu fragmentacji pamięci polega właśnie na tym, dlaczego pozostają one przypięte do pamięci (przy przydzielaniu ogromnej strony o wielkości 2 MB jądro musi znaleźć 512 sąsiadujących ze sobą bezpłatnych stron 4KB, które mogą nawet nie istnieć).

Dokumentacja systemu Linux na dużych stronach: http://lwn.net/Articles/375098/

Istnieje jedna okoliczność, w której fragmentacja pamięci może powodować powolne przydzielanie ogromnych stron (ale nie w przypadku, gdy ogromne strony powodują fragmentację pamięci), i to jest, jeśli system jest skonfigurowany do powiększania puli ogromnych stron, jeśli zażąda tego aplikacja. Jeśli / proc / sys / vm / nr_overcommit_hugepages jest większy niż / proc / sys / vm / nr_hugepages, może się to zdarzyć.

jstultz
źródło
Rzeczywiście - i powinno to zasadniczo poprawić wydajność, ponieważ zapobiegnie brakom TLB (wyjaśnienie znajduje się w linkowanym artykule).
Dan Pritts,
0

Jest /proc/buddyinfo co jest bardzo przydatne. Jest to bardziej przydatne z ładnym formatem wyjściowym, takim jak ten skrypt Pythona może:

https://gist.github.com/labeneator/9574294

W przypadku dużych stron potrzebujesz darmowych fragmentów w rozmiarze 2097152 (2MiB) lub większym. W przypadku przezroczystych, dużych stron kompresuje się automatycznie, gdy jądro zostanie o nie poproszone, ale jeśli chcesz zobaczyć, ile możesz uzyskać, uruchom jako root:

echo 1 | sudo tee /proc/sys/vm/compact_memory

Także tak, ogromne strony powodują duże problemy z fragmentacją. Albo nie możesz dostać żadnych dużych stron, albo ich obecność powoduje, że jądro spędza dużo więcej czasu próbując je zdobyć.

Mam rozwiązanie, które działa dla mnie. Używam go na kilku serwerach i moim laptopie. Działa świetnie na maszynach wirtualnych.

Dodaj kernelcore=4G opcję do wiersza polecenia jądra Linux. Na moim serwerze używam 8G. Uważaj na liczbę, ponieważ zapobiegnie to alokacji przez jądro czegokolwiek poza tą pamięcią. Serwery, które potrzebują wielu buforów gniazd lub zapisują dyski strumieniowe na setkach dysków, nie będą lubiły ograniczać się w ten sposób. Wszelkie przydziały pamięci, które należy „przypiąć” do płyty lub DMA, należą do tej kategorii.

Cała pozostała pamięć staje się wówczas „ruchoma”, co oznacza, że ​​można ją spakować w ładne porcje w celu ogromnego przydzielenia strony. Teraz przezroczyste, ogromne strony mogą naprawdę startować i działać tak, jak powinny. Ilekroć jądro potrzebuje więcej 2M stron, może po prostu odwzorować strony 4K w inne miejsce.

I nie jestem do końca pewien, jak to wchodzi w interakcję z bezpośrednim we / wy zero kopii. Pamięć w „strefie ruchomej” nie powinna być przypięta, ale bezpośrednie żądanie IO zrobiłoby to dokładnie dla DMA. Może to skopiować. W każdym razie może to zablokować w strefie ruchomej. W obu przypadkach prawdopodobnie nie jest to dokładnie to, czego chciałeś.

Zan Lynx
źródło