W tym artykule opowiem o sytuacji, która niedawno miała miejsce z jednym z serwerów naszej chmury VPS, stawiając mnie w martwym punkcie na kilka godzin. Od około 15 lat zajmuję się konfiguracją i rozwiązywaniem problemów z serwerami Linux, ale ten przypadek całkowicie wymknął się z mojej praktyki — poczyniłem kilka błędnych założeń i trochę się załamałem, zanim mogłem prawidłowo zidentyfikować przyczynę problemu i ją rozwiązać.
Wstęp
Obsługujemy średniej wielkości chmurę, którą budujemy na standardowych serwerach o następującej konfiguracji — 32 rdzenie, 256 GB RAM i dysk NVMe PCI-E Intel P4500 o pojemności 4TB. Bardzo lubimy tę konfigurację, ponieważ pozwala ona nie martwić się o niedobór IO, zapewniając odpowiednie ograniczenia na poziomie typów instancji VM. Ponieważ NVMe Intel posiada imponującą wydajność, możemy jednocześnie zapewnić pełne dostarczanie IOPS maszynom oraz wykonywać kopie zapasowe magazynu na serwerze kopii zapasowych z zerowym IOWAIT.
Jesteśmy wśród tych starych wyjadaczy, którzy nie korzystają z hiperkonwergentnych SDN i innych stylowych, modnych młodzieżowych rozwiązań do przechowywania wolumenów VM, uważając, że im prostszy system, tym łatwiej go rozwiązywać w warunkach "główny guru wyjechał w góry". W rezultacie przechowujemy wolumeny VM w formacie QCOW2 w XFS lub EXT4, które są wdrażane na LVM2.
Korzystanie z QCOW2 jest również wymuszone przez produkt, który używamy do orkiestracji — Apache CloudStack.
Aby wykonywać kopie zapasowe, tworzony jest pełny obraz wolumenu, jako zrzut LVM2 (tak, wiemy, że zrzuty LVM2 są wolne, ale Intel P4500 nas w tym ratuje). Robimy lvmcreate -s .. i za pomocą dd wysyłamy kopię zapasową na zdalny serwer z magazynem ZFS. Tu jesteśmy jednak trochę postępowi — ZFS potrafi przechowywać dane w skompresowanej formie, a my możemy je szybko przywracać za pomocą DD lub wydobywać pojedyncze wolumeny VM za pomocą mount -o loop ....
Można oczywiście robić także niepełny obraz wolumenu LVM2, montując system plików w trybie
ROi kopiować same obrazy QCOW2, jednak napotkaliśmy na problem, że XFS zaczynał działać źle, co nie działo się od razu, a w sposób nieprzewidywalny. Nie lubimy, gdy hosty-hiperwizory nagle 'zawieszają się' w weekendy, w nocy lub w święta z powodu błędów, które mogą wystąpić w nieokreślonym czasie. Dlatego dla XFS nie używamy montowania migawkowego w trybieROdo wyodrębniania wolumenów, a po prostu kopiujemy cały wolumen LVM2.
Szybkość tworzenia kopii zapasowej na serwerze kopii zapasowych w naszym przypadku zależy od wydajności serwera backupowego, która wynosi około 600-800 MB/s dla niekompresowanych danych, dalszym ograniczeniem jest kanał 10Gbit/s, którym serwer kopii zapasowych jest podłączony do klastra.
Jednocześnie na jeden serwer kopii zapasowych przesyłane są kopie zapasowe z 8 serwerów hiperwizorów. W ten sposób dyskowe i sieciowe systemy serwera kopii zapasowych, będąc wolniejszymi, nie obciążają systemów dyskowych hostów-hiperwizorów, ponieważ po prostu nie mogą obsłużyć, powiedzmy, 8 GB/s, które bez trudu mogą generować hosty-hiperwizory.
Opisany powyżej proces kopiowania jest bardzo ważny dla dalszej narracji, w tym szczegóły — wykorzystanie szybkiego nośnika Intel P4500, wykorzystanie NFS i prawdopodobnie wykorzystanie ZFS.
Historia o tworzeniu kopii zapasowej
Na każdym węźle-hiperwizorze mamy małą partycję SWAP o wielkości 8 GB, a sam węzeł-hiperwizor 'rozpakowujemy' za pomocą DD z wzorcowego obrazu. Dla systemowego wolumenu na serwerach używamy 2xSATA SSD RAID1 lub 2xSAS HDD RAID1 na kontrolerze sprzętowym LSI lub HP. W zasadzie nie obchodzi nas, co tam jest w środku, ponieważ systemowy wolumen działa u nas w trybie 'prawie tylko do odczytu', poza SWAP-em. A ponieważ mamy dużo pamięci RAM na serwerze, która jest w 30-40% wolna, o SWAP-ie nie myślimy.
Proces tworzenia kopii zapasowej. Wygląda to mniej więcej tak:
#!/bin/bash
mkdir -p /mnt/backups/volumes
DIR=/mnt/images-snap
VOL=images/volume
DATE=$(date "+%d")
HOSTNAME=$(hostname)
lvcreate -s -n $VOL-snap -l100%FREE $VOL
ionice -c3 dd iflag=direct if=/dev/$VOL-snap bs=1M of=/mnt/backups/volumes/$HOSTNAME-$DATE.raw
lvremove -f $VOL-snapZwróć uwagę na ionice -c3, w rzeczywistości to urządzenie dla urządzeń NVMe jest całkowicie bezużyteczne, ponieważ harmonogram IO dla nich jest ustawiony na:
cat /sys/block/nvme0n1/queue/scheduler
[none] Jednak mamy szereg legacy-węzłów z tradycyjnymi dyskami SSD RAID, dla nich jest to aktualne, więc przenosi się AS IS. W zasadzie to po prostu ciekawy fragment kodu, który wyjaśnia bezsensowność ionice w przypadku takiej konfiguracji.
Zwróć uwagę na flagę iflag=direct do DD. Używamy direct IO, aby uniknąć zbędnych zamienników buforów IO podczas odczytu. Jednakże, oflag=direct nie robimy tego, ponieważ napotkaliśmy problemy z wydajnością ZFS przy jego użyciu.
Ten schemat stosujemy z powodzeniem od kilku lat bez problemów.
I tu się zaczęło… Odkryliśmy, że na jednym z węzłów przestało działać tworzenie kopii zapasowej, a poprzednia została wykonana z ogromnym opóźnieniem IOWAIT na poziomie 50%. Kiedy próbowaliśmy zrozumieć, dlaczego nie wykonuje się kopiowanie, natknęliśmy się na zjawisko:
Grupa wolumenów "images" nie znalezionaZaczęliśmy myśleć o "końcu Intel P4500", jednak przed wyłączeniem serwera w celu wymiany dysku, konieczne było jeszcze wykonanie kopii zapasowej. Naprawiliśmy LVM2, przywracając metadane z kopii zapasowej LVM2:
vgcfgrestore imagesUruchomiliśmy tworzenie kopii zapasowej i zobaczyliśmy taki obrazek:

Znowu bardzo się zasmuciliśmy - było jasne, że tak żyć nie można, ponieważ wszystkie VPS-y będą cierpieć, a to oznacza, że będziemy cierpieć i my. Co się działo, było całkowicie niejasne - iostat pokazywał skromne IOPS-y i najwyższy IOWAIT. Nie mieliśmy pomysłów, poza "zastąpmy NVMe", ale w porę przyszło olśnienie.
Analiza sytuacji krok po kroku
Dziennik historyczny. Kilka dni wcześniej na tym serwerze było konieczne stworzenie dużej VPS-y z 128 GB RAM. Pamięci wydawało się wystarczająco, ale dla pewności przydzielono jeszcze 32 GB dla partycji swap. VPS została utworzona, skutecznie rozwiązała swoją sprawę, a incydent został zapomniany, a partycja SWAP pozostała.
Charakterystyka konfiguracji. Dla wszystkich serwerów w chmurze parametr vm.swappiness został ustawiony na wartość domyślną 60. A SWAP został utworzony na RAID1 HDD SAS.
Co się działo (zdaniem redakcji). Przy tworzeniu kopii zapasowej DD generował wiele danych do zapisania, które były umieszczane w buforach RAM przed zapisaniem do NFS. Jądro systemowe, kierując się polityką swappiness, przenosiło wiele stron pamięci VPS do obszaru swap, który znajdował się na wolnym woluminie HDD RAID1. To powodowało, że IOWAIT znacznie wzrastał, ale nie z powodu IO NVMe, a z powodu IO HDD RAID1.
Jak problem został rozwiązany. Wyłączono partycję swap 32GB. Zajęło to 16 godzin, o tym, jak i dlaczego tak wolno wyłącza się SWAP można czytać oddzielnie. Zmieniono parametry swappiness na wartość równą 5 we wszystkich chmurach.
Jak mogłoby do tego nie dojśćPo pierwsze, gdyby SWAP był na urządzeniu SSD RAID lub NVMe, po drugie, gdyby nie było urządzenia NVMe, a byłoby wolniejsze urządzenie, które nie generowałoby takiej ilości danych — w ironii, problem wystąpił z powodu zbyt dużej prędkości NVMe.
Po tym wszystkim wszystko zaczęło działać jak wcześniej — z zerowym IOWAIT.
Źródło: habr.com
