Ogranicz opróżnianie tła Linux (brudne strony)

26

Płukanie w tle w Linuksie ma miejsce, gdy albo oczekuje się zbyt dużej ilości zapisanych danych (można to zmienić za pomocą / proc / sys / vm / dirty_background_ratio) lub upłynął limit czasu dla zapisów oczekujących (/ proc / sys / vm / dirty_expire_centisecs). O ile nie zostanie przekroczony inny limit (/ proc / sys / vm / dirty_ratio), więcej zapisanych danych może być buforowanych. Dalsze zapisy zostaną zablokowane.

Teoretycznie powinno to stworzyć proces w tle, wypisujący brudne strony bez zakłócania innych procesów. W praktyce przeszkadza to procesowi, który dokonuje odczytu niebuforowanego lub zapisu synchronicznego. Źle. Wynika to z faktu, że opróżnianie w tle faktycznie zapisuje przy 100% prędkości urządzenia, a wszelkie inne żądania urządzeń w tym czasie będą opóźnione (ponieważ wszystkie kolejki i pamięci podręczne zapisu na drodze są zapełnione).

Czy istnieje sposób na ograniczenie liczby żądań na sekundę wykonywanych przez proces płukania lub w inny sposób skutecznie nadać priorytet innym urządzeniom we / wy?

Korkman
źródło
Może to byłoby dobre pytanie, aby wysłać na listę mailingową jądra Linuxa vger.kernel.org/vger-lists.html#linux-kernel
Jakiego harmonogramu IO używasz?
3dinfluence
Próbowałem różnych (por. Termin, termin), ale myślę, że działają one niezawodnie tylko wtedy, gdy nie uwzględniono pamięci podręcznej zapisu z podtrzymaniem bateryjnym. Jak jedna macierz dyskowa, zjadam 1 GiB danych przy szybkości magistrali PCIe (RAM), a następnie uderzam w ścianę rzeczywistości. Kilka sekund zerowego We / Wy dla wszystkich jednostek LUN. Przepłukiwanie (przynajmniej w tle) do przybliżonego oszacowania rzeczywistej prędkości urządzenia rozwiązałoby problem zatoru.
korkman
1
Niedawno dowiedziałem się, że / sys / block / sdX / queue / nr_requests jest istotnym dostrajaniem. Zmniejszenie go do minimum (= 4 w moim przypadku) znacznie poprawia opóźnienie równoczesnego ładowania: Sysbench fsync losowe zapisy na sekundę skoczyły z 4 (!) Do 80-90 podczas pisania z prędkością magistrali z dd. Wydajność nieobciążona wydaje się niezmieniona. Harmonogramy są takie same, noop lub termin wydaje się optymalny. Może tak być w przypadku większości konfiguracji BBWC.
korkman

Odpowiedzi:

20

Po wielu testach porównawczych z sysbench doszedłem do tego wniosku:

Aby przeżyć (pod względem wydajności) sytuację, w której

  • zły proces kopiowania zalewa brudne strony
  • i sprzętowa pamięć podręczna zapisu jest obecna (być może również bez tego)
  • a synchroniczne odczyty lub zapisy na sekundę (IOPS) są krytyczne

po prostu zrzuć wszystkie windy, kolejki i brudne pamięci podręczne stron. Prawidłowe miejsce dla brudnych stron znajduje się w pamięci RAM tego sprzętowego bufora zapisu.

Dostosuj dirty_ratio (lub nowe dirty_bytes) tak nisko, jak to możliwe, ale miej oko na sekwencyjną przepustowość. W moim szczególnym przypadku 15 MB było optymalne ( echo 15000000 > dirty_bytes).

Jest to bardziej hack niż rozwiązanie, ponieważ gigabajty pamięci RAM są teraz używane tylko do buforowania odczytu zamiast brudnej pamięci podręcznej. Aby brudna pamięć podręczna działała dobrze w tej sytuacji, moduł czyszczący w tle jądra systemu Linux musiałby uśredniać, z jaką prędkością urządzenie bazowe akceptuje żądania i odpowiednio dostosowywać czyszczenie tła. Niełatwe.


Dane techniczne i testy porównawcze:

Testowany podczas ddzerowania dysku, sysbench wykazał ogromny sukces , zwiększając 10 wątków fsync zapisuje przy 16 kB z 33 do 700 IOPS (limit bezczynności: 1500 IOPS) i pojedynczy wątek od 8 do 400 IOPS.

Bez obciążenia IOPS pozostały bez zmian (~ 1500), a przepustowość nieznacznie zmniejszona (z 251 MB / s do 216 MB / s).

dd połączenie:

dd if=/dev/zero of=dumpfile bs=1024 count=20485672

w przypadku sysbench plik_pliku testowego.0 został przygotowany do rozrzedzenia za pomocą:

dd if=/dev/zero of=test_file.0 bs=1024 count=10485672

sysbench call dla 10 wątków:

sysbench --test=fileio --file-num=1 --num-threads=10 --file-total-size=10G --file-fsync-all=on --file-test-mode=rndwr --max-time=30 --file-block-size=16384 --max-requests=0 run

wywołanie sysbench dla jednego wątku:

sysbench --test=fileio --file-num=1 --num-threads=1 --file-total-size=10G --file-fsync-all=on --file-test-mode=rndwr --max-time=30 --file-block-size=16384 --max-requests=0 run

Mniejsze rozmiary bloków pokazały jeszcze bardziej drastyczne liczby.

- file-block-size = 4096 z 1 GB dirty_bytes:

sysbench 0.4.12:  multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Extra file open flags: 0
1 files, 10Gb each
10Gb total file size
Block size 4Kb
Number of random requests for random IO: 0
Read/Write ratio for combined random IO test: 1.50
Calling fsync() after each write operation.
Using synchronous I/O mode
Doing random write test
Threads started!
Time limit exceeded, exiting...
Done.

Operations performed:  0 Read, 30 Write, 30 Other = 60 Total
Read 0b  Written 120Kb  Total transferred 120Kb  (3.939Kb/sec)
      0.98 Requests/sec executed

Test execution summary:
      total time:                          30.4642s
      total number of events:              30
      total time taken by event execution: 30.4639
      per-request statistics:
           min:                                 94.36ms
           avg:                               1015.46ms
           max:                               1591.95ms
           approx.  95 percentile:            1591.30ms

Threads fairness:
      events (avg/stddev):           30.0000/0.00
      execution time (avg/stddev):   30.4639/0.00

- file-block-size = 4096 z 15 MB dirty_bytes:

sysbench 0.4.12:  multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Extra file open flags: 0
1 files, 10Gb each
10Gb total file size
Block size 4Kb
Number of random requests for random IO: 0
Read/Write ratio for combined random IO test: 1.50
Calling fsync() after each write operation.
Using synchronous I/O mode
Doing random write test
Threads started!
Time limit exceeded, exiting...
Done.

Operations performed:  0 Read, 13524 Write, 13524 Other = 27048 Total
Read 0b  Written 52.828Mb  Total transferred 52.828Mb  (1.7608Mb/sec)
    450.75 Requests/sec executed

Test execution summary:
      total time:                          30.0032s
      total number of events:              13524
      total time taken by event execution: 29.9921
      per-request statistics:
           min:                                  0.10ms
           avg:                                  2.22ms
           max:                                145.75ms
           approx.  95 percentile:              12.35ms

Threads fairness:
      events (avg/stddev):           13524.0000/0.00
      execution time (avg/stddev):   29.9921/0.00

- file-block-size = 4096 z 15 MB dirty_bytes w bezczynnym systemie:

sysbench 0.4.12: test porównawczy wielowątkowej oceny systemu

Running the test with following options:
Number of threads: 1

Extra file open flags: 0
1 files, 10Gb each
10Gb total file size
Block size 4Kb
Number of random requests for random IO: 0
Read/Write ratio for combined random IO test: 1.50
Calling fsync() after each write operation.
Using synchronous I/O mode
Doing random write test
Threads started!
Time limit exceeded, exiting...
Done.

Operations performed:  0 Read, 43801 Write, 43801 Other = 87602 Total
Read 0b  Written 171.1Mb  Total transferred 171.1Mb  (5.7032Mb/sec)
 1460.02 Requests/sec executed

Test execution summary:
      total time:                          30.0004s
      total number of events:              43801
      total time taken by event execution: 29.9662
      per-request statistics:
           min:                                  0.10ms
           avg:                                  0.68ms
           max:                                275.50ms
           approx.  95 percentile:               3.28ms

Threads fairness:
      events (avg/stddev):           43801.0000/0.00
      execution time (avg/stddev):   29.9662/0.00

System testowy:

  • Adaptec 5405Z (to 512 MB pamięci podręcznej zapisu z ochroną)
  • Intel Xeon L5520
  • 6 GiB RAM przy 1066 MHz
  • Płyta główna Supermicro X8DTN (chipset 5520)
  • 12 dysków Seagate Barracuda o pojemności 1 TB
    • 10 w oprogramowaniu Linux RAID 10
  • Jądro 2.6.32
  • System plików XFS
  • Debian niestabilny

Podsumowując, jestem teraz pewien, że ta konfiguracja będzie działać dobrze w sytuacjach bezczynności, dużego obciążenia, a nawet pełnego obciążenia dla ruchu w bazie danych, który w innym przypadku byłby zagłodzony przez ruch sekwencyjny. Przepustowość sekwencyjna jest wyższa niż dwa łącza gigabitowe, które i tak można dostarczyć, więc nie ma problemu, aby ją nieco zmniejszyć.

Korkman
źródło
Jaka jest twoja metodologia, aby dojść do części „15 MB dla dirty_buffers jest optymalna”?
Marcin
1
Próba i błąd. Na przykład, zmień połowę kwoty następnym razem itp., Dopóki nie skończyłem z zaledwie 15 MB i OK IOPS. Obecne jądro 3.2 może zachowywać się zupełnie inaczej, BTW.
korkman
2
Chciałem tylko podziękować za postawienie mnie na właściwej drodze. Miałem podobne problemy z węzłem XenServer. Okazało się, że jest to pamięć podręczna PHP-FPM / APC powodująca brudne strony. Dostosowanie modelu pamięci podręcznej APC rozwiązało dla nas problem. DiskIO spadło z 20% wykorzystania do 0.
jeffatrackaid
Logicznie dirty_bytespowinno być wystarczająco wysokie, aby nie blokować procesorów podczas pisania procesów, jeśli proces pisze średnio z przepustowością urządzenia. Jeśli kod aplikacji wykonuje cykle wielkich obliczeń, a następnie zapisuje ogromne ilości danych, to bardzo trudno będzie je zoptymalizować, ponieważ średnie krótkookresowe znacznie różnią się od średnich średnich długookresowych. Prawidłowym rozwiązaniem byłoby dostosowanie dirty_bytesustawień specyficznych dla procesu , ale Linux nie obsługuje takich rzeczy, o ile wiem.
Mikko Rantalainen
3

Chociaż dostrajanie parametrów jądra zatrzymało problem, w rzeczywistości możliwe są problemy z wydajnością wynikające z błędu kontrolera Adaptec 5405Z, który został naprawiony w aktualizacji oprogramowania układowego z 1 lutego 2012 r. Informacje o wersji mówią „Naprawiono problem, w wyniku którego oprogramowanie układowe mogło się zawieszać podczas dużego obciążenia we / wy”. Być może rozłożenie I / O tak jak ty wystarczyło, aby zapobiec uruchomieniu tego błędu, ale to tylko przypuszczenie.

Oto informacje o wersji: http://download.adaptec.com/pdfs/readme/relnotes_arc_fw-b18937_asm-18837.pdf

Nawet jeśli nie dotyczyło to konkretnej sytuacji, pomyślałem, że może to przynieść korzyści użytkownikom, którzy napotkają ten post w przyszłości. W naszym wydaniu dmesg zobaczyliśmy kilka takich komunikatów, które ostatecznie doprowadziły nas do aktualizacji oprogramowania układowego:

aacraid: Host adapter abort request (0,0,0,0)
[above was repeated many times]
AAC: Host adapter BLINK LED 0x62
AAC0: adapter kernel panic'd 62.
sd 0:0:0:0: timing out command, waited 360s
sd 0:0:0:0: Unhandled error code
sd 0:0:0:0: SCSI error: return code = 0x06000000
Result: hostbyte=DID_OK driverbyte=DRIVER_TIMEOUT,SUGGEST_OK
sd 0:0:0:0: timing out command, waited 360s
sd 0:0:0:0: Unhandled error code
sd 0:0:0:0: SCSI error: return code = 0x06000028
Result: hostbyte=DID_OK driverbyte=DRIVER_TIMEOUT,SUGGEST_OK
sd 0:0:0:0: timing out command, waited 360s
sd 0:0:0:0: Unhandled error code
sd 0:0:0:0: SCSI error: return code = 0x06000028

Oto numery modeli kontrolerów Adaptec RAID, które są wymienione w informacjach o wersji oprogramowania układowego z wysoką poprawką zawieszenia we / wy: 2045, 2405, 2405Q, 2805, 5085, 5405, 5405Z, 5445, 5445Z, 5805, 5805Q, 5805Z, 5805ZQ, 51245, 51645, 52445.

sa289
źródło
1
Wow, dziękuję za twój wkład. Chociaż tak nie było w moim przypadku, dajesz mi jeszcze jeden powód, aby całkowicie unikać HW RAID i przejść do konfiguracji tylko HBA. HW RAID nadal ma przewagę BBWC, ale z takimi rzeczami, jak przenoszenie bufora do jądra, nawet to znika. Wadą dla HW RAID jest dokładnie ten rodzaj błędów oprogramowania, które opisujesz. Miałem inny system z konfiguracją DRBD i dużym obciążeniem We / Wy powodującym reset oprogramowania układowego, więc nie jest to rzadkie (może to być właśnie ten błąd).
korkman
1

Jądro zawierające „WBT”:

Ulepszenia w warstwie blokowej , LWN.net

Dzięki ograniczeniu zapisu zwrotnego [warstwa blokowa] próbuje uzyskać maksymalną wydajność bez nadmiernego opóźnienia we / wy przy użyciu strategii zapożyczonej z harmonogramu sieci CoDel. CoDel śledzi zaobserwowane minimalne opóźnienie pakietów sieciowych, a jeśli przekroczy ono wartość progową, zaczyna upuszczać pakiety. Odrzucanie zapisu jest niezadowolone w podsystemie I / O, ale podobna strategia jest taka, że ​​jądro monitoruje minimalne opóźnienie zarówno odczytów, jak i zapisów, a jeśli przekracza wartość progową, zaczyna zmniejszać ilość zapisu zwrotnego w tle to się robi. To zachowanie zostało dodane w 4.10; Axboe powiedział, że zaobserwowano całkiem dobre wyniki.

WBT nie wymaga przejścia na nową warstwę blokową blk-mq. To powiedziawszy, nie działa z programami planującymi We / Wy CFQ lub BFQ. Możesz używać WBT z harmonogramami deadline / mq-deadline / noop / none. Wierzę, że działa również z nowym harmonogramem we / wy „kyber”.

Oprócz skalowania rozmiaru kolejki w celu kontrolowania opóźnienia, kod WBT ogranicza liczbę żądań zapisu zwrotnego w tle jako proporcję obliczonego limitu kolejki.

Konfiguracja środowiska wykonawczego jest w /sys/class/block/*/queue/wbt_lat_usec.

Dostępne są opcje konfiguracji kompilacji

/boot/config-4.20.8-200.fc29.x86_64:CONFIG_BLK_WBT=y
/boot/config-4.20.8-200.fc29.x86_64:# CONFIG_BLK_WBT_SQ is not set
/boot/config-4.20.8-200.fc29.x86_64:CONFIG_BLK_WBT_MQ=y

Zgłoszenie problemu zostało potwierdzone w 100% przez autora WBT - dobra robota :-).

Blok [PATCHSET]: buforowane ograniczanie zapisu zwrotnego

Od zarania dziejów nasz bufor buforowany w tle jest do niczego. Kiedy wykonujemy buforowane zapisywanie w tle, powinno to mieć niewielki wpływ na aktywność na pierwszym planie. Taka jest definicja aktywności w tle ... Ale tak długo, jak pamiętam, pisarze z buforowanymi buforami tak się nie zachowywali. Na przykład, jeśli zrobię coś takiego:

$ dd if=/dev/zero of=foo bs=1M count=10k

na moim laptopie, a następnie spróbuj uruchomić Chrome, to w zasadzie nie uruchomi się przed zakończonym buforowaniem zapisu. Lub w przypadku obciążeń zorientowanych na serwer, gdy instalacja dużego RPM (lub podobnego) niekorzystnie wpływa na odczyty bazy danych lub synchronizację zapisów. Kiedy tak się dzieje, ludzie krzyczą na mnie.

Wyniki niektórych ostatnich testów można znaleźć tutaj:

https://www.facebook.com/axboe/posts/10154074651342933

Zobacz poprzednie posty, aby uzyskać większy opis zestawu poprawek.

sourcejedi
źródło
Cieszę się, że problem został rozpoznany i rozwiązany w jądrze. Pamiętaj, że blk-mq jest dość nowy i może jeszcze nie tak dojrzały .
korkman
@korkman westchnienie, chyba zmienię cytat, aby uniknąć fałszywej implikacji. Zgadzam się, że jest to coś dodanego w ciągu ostatnich kilku lat, wciąż mogą występować regresje wydajności lub gorzej. AFAIR opiekun odrzuca naprawę uszkodzenia danych w tym sensie, że jest to przypadek. Jeśli używasz wersji jądra, w których opracowano blk-mq, dyskusyjne jest to, ile przy użyciu warstwy blokowej „starszej” pozwoli uniknąć błędów. Błąd zawieszenia, który naprawiłem, był błędem, który powstał w programie blk-mq, następnie został przebudowany lub coś w tym stylu. github.com/torvalds/linux/commit/1dc3039bc87a
sourcejedi
0

Jaka jest Twoja średnia dla Dirty in / proc / meminfo? Zwykle nie powinno to przekraczać twojego / proc / sys / vm / dirty_ratio. Na dedykowanym serwerze plików mam parametr dirty_ratio ustawiony na bardzo wysoki procent pamięci (90), ponieważ nigdy go nie przekroczę. Twoja brudna_racja jest zbyt niska, kiedy ją uderzysz, wszystko wyskakuje, podnieś ją.

Luke
źródło
Problem nie polega na tym, że procesy nie są blokowane przy trafianiu typu dirty_ratio. Nic mi nie jest. Ale proces „w tle” zapisujący brudne dane na dyskach wypełnia kolejki bez litości i zabija wydajność IOPS. To się nazywa głodowanie IO. W rzeczywistości ustawienie bardzo niskiego poziomu dirty_ratio_bytes (np. 1 MB) pomaga dużo, ponieważ opróżnianie nastąpi prawie natychmiast, a kolejki pozostaną puste. Wadą jest prawdopodobnie niższa przepustowość sekwencyjna, ale to w porządku.
korkman
Wyłączyłeś wszystkie windy? Co jeszcze poprawiłeś z systemu waniliowego?
Łukasz
1
Zobacz moją odpowiedź. Koniec historii polegał na usunięciu brudnego buforowania i pozostawieniu tej części kontrolerowi HW. Windy są trochę nieistotne z zainstalowaną pamięcią podręczną HW. Kontroler ma własne algorytmy windy, więc posiadanie dowolnej windy w oprogramowaniu tylko zwiększa koszty.
korkman
Elevevator w oprogramowaniu to kompromis: poświęcenie opóźnienia w celu poprawy przepustowości. Wyobraź sobie na przykład 100 000 operacji zapisu w kolejce oprogramowania przesłanej w losowej kolejności; jeśli winda oprogramowania może zamówić te operacje przy użyciu ogromnego bufora, może w końcu wysłać do urządzenia tylko 5K znacznie większych żądań. Jednak w rezultacie opóźnienie należy zwiększyć o 100 tys. Operacji, ponieważ może się zdarzyć, że pierwsze 2 tys. Operacji i ostatnie 1 tys. Operacji są rzeczywiście blisko siebie na urządzeniu. Bez dodatkowego opóźnienia ich scalenie nie będzie możliwe.
Mikko Rantalainen