Zdá se, že jste již vyzkoušeli mnoho věcí, které bych vám na začátku navrhl (vyladění konfigurace swapu, změna plánovačů I/O atd.).
Kromě toho, co jste se již pokusili změnit, bych doporučil podívat se na změnu poněkud mozkově mrtvých výchozích hodnot pro chování zpětného zápisu VM. To je spravováno následujícími šesti hodnotami sysctl:
vm.dirty_ratio
:Řídí, kolik zápisů musí čekat na zpětný zápis, než bude spuštěn. Zvládá zpětný zápis na popředí (pro jednotlivé procesy) a je vyjádřen jako celé číslo v procentech paměti RAM. Výchozí hodnota je 10 % RAMvm.dirty_background_ratio
:Řídí, kolik zápisů musí čekat na zpětný zápis, než bude spuštěn. Zvládá zpětný zápis na pozadí (v celém systému) a je vyjádřen jako celé číslo v procentech paměti RAM. Výchozí hodnota je 20 % RAMvm.dirty_bytes
:Stejné jakovm.dirty_ratio
, kromě vyjádřeného jako celkový počet bajtů. Buď toto nebovm.dirty_ratio
bude použito, podle toho, co bylo napsáno tak, aby trvalo.vm.dirty_background_bytes
:Stejné jakovm.dirty_background_ratio
, kromě vyjádřeného jako celkový počet bajtů. Buď toto nebovm.dirty_background_ratio
bude použito, podle toho, co bylo napsáno tak, aby trvalo.vm.dirty_expire_centisecs
:Kolik setin sekundy musí uplynout, než se spustí čekající zpětný zápis, když by jej již nespustily výše uvedené čtyři hodnoty sysctl. Výchozí hodnota je 100 (jedna sekunda).vm.dirty_writeback_centisecs
:Jak často (v setinkách sekundy) bude jádro vyhodnocovat špinavé stránky pro zpětný zápis. Výchozí hodnota je 10 (jedna desetina sekundy).
Takže s výchozími hodnotami každou desetinu sekundy jádro udělá následující:
- Všechny upravené stránky zapište do trvalého úložiště, pokud byly naposledy upraveny před více než sekundou.
- Zapište všechny upravené stránky procesu, pokud celkové množství upravené paměti, která nebyla zapsána, překročí 10 % paměti RAM.
- Zapište všechny upravené stránky v systému, pokud celkové množství upravené paměti, která nebyla zapsána, překročí 20 % paměti RAM.
Takže by mělo být docela snadné pochopit, proč vám výchozí hodnoty mohou způsobovat problémy, protože váš systém se možná pokouší zapsat až 4 gigabajty dat do trvalého úložiště každou desátou sekundy.
Obecným konsensem v těchto dnech je upravit vm.dirty_ratio
být 1 % RAM a vm.dirty_background_ratio
být 2 %, což u systémů s méně než 64 GB RAM vede k chování ekvivalentnímu původnímu zamýšlenému.
Některé další věci, na které byste se měli podívat:
- Zkuste zvýšit
vm.vfs_cache_pressure
trochu sysctl. To řídí, jak agresivně jádro získává zpět paměť z mezipaměti souborového systému, když potřebuje RAM. Výchozí hodnota je 100, nesnižujte ji na hodnotu nižší než 50 (budete dostanete opravdu špatné chování, pokud půjdete pod 50, včetně podmínek OOM), a nezvyšujte to na mnohem více než asi 200 (mnohem výše a jádro bude ztrácet čas tím, že se bude snažit získat zpět paměť, kterou opravdu nemůže). Zjistil jsem, že zvýšení na 150 skutečně viditelně zlepšuje odezvu, pokud máte přiměřeně rychlé úložiště. - Zkuste změnit režim přetížení paměti. To lze provést změnou hodnoty
vm.overcommit_memory
sysctl. Ve výchozím nastavení bude jádro používat heuristický přístup, aby se pokusilo předpovědět, kolik RAM si může skutečně dovolit odevzdat. Nastavení na 1 deaktivuje heuristiku a řekne jádru, aby se chovalo, jako by mělo nekonečnou paměť. Nastavením na 2 říkáte jádru, aby se nezavázalo k více paměti, než je celkové množství odkládacího prostoru v systému plus procento skutečné RAM (řízenovm.overcommit_ratio
). - Zkuste vyladit
vm.page-cluster
sysctl. To řídí, kolik stránek se najednou vymění nebo vymění (je to logaritmická hodnota se základem 2, takže výchozí hodnota 3 se převede na 8 stránek). Pokud skutečně swapujete, může to pomoci zlepšit výkon swapování stránek dovnitř a ven.
Problém byl nalezen!
Ukazuje se, že je to problém s výkonem v linuxovém programu pro navrácení paměti, když existuje velký počet kontejnerů/paměťových cgroups. (Odmítnutí odpovědnosti:mé vysvětlení může být chybné, nejsem vývojář jádra.) Problém byl opraven v 4.19-rc1+ v této sadě oprav:
Tato sada patchů řeší problém s pomalým shrink_slab() vyskytujícím se na počítačích s mnoha zmenšovači a paměťovými cgroups (tj. s mnoha kontejnery). Problém je v tom, že složitost shrink_slab() je O(n^2) a s rostoucím počtem kontejnerů roste příliš rychle.
Mějme 200 kontejnerů a každý kontejner má 10 mountů a 10cgroups. Všechny úlohy kontejneru jsou izolované a nedotýkají se připojení cizích kontejnerů.
V případě globální rekultivace musí úkol opakovat všechny memcg a zavolat všechny zmenšovače s vědomím memcg pro všechny z nich. To znamená, že úloha musí navštívit 200 * 10 =2 000 zmenšovačů na každý memcg, a protože existuje 2 000 memcg, celkový počet volání do_shrink_slab() je 2 000 * 2 000 =4 000 000.
Můj systém byl zasažen obzvláště tvrdě, protože používám velké množství kontejnerů, což pravděpodobně způsobilo, že se problém objevil.
Moje kroky pro odstraňování problémů, v případě, že jsou užitečné pro každého, kdo čelí podobným problémům:
- Všimněte si
kswapd0
používám tuny CPU, když můj počítač zadrhává - Zkuste zastavit kontejnery Docker a znovu zaplnit paměť → počítač se nezasekává!
- Spusťte
ftrace
(podle nádherného blogu Julie Evan s vysvětlením), chcete-li získat stopu, podívejte se nakswapd0
má tendenci uvíznout vshrink_slab
,super_cache_count
alist_lru_count_one
. - Google
shrink_slab lru slow
, najděte sadu patchů! - Přepněte na Linux 4.19-rc3 a ověřte, že je problém vyřešen.