[vpsFree.cz: community-list] Sprava pameti na vpsAdminOS

Pavel Snajdr snajpa at snajpa.net
Thu Aug 13 13:02:18 CEST 2020


Ahojte,

sliboval jsem (vetsinou off-list), ze shnu pak resenici s pameti na 
vpsAdminOS, tak tady to je :)

Kdyz chce programator dneska z aplikace pracovat s velkym souborem, je 
docela rozsirenym pristupem, si takovy soubor namapovat do pameti pomoci 
mmap(2) syscallu.

To zpusobi, ze se soubor ocitne ve virtualnim pametovem prostoru 
procesu, tj. ten program si pak muze sahat do toho souboru prostym 
pristupovanim do pameti (nabizi se teda snadny ukladani napr. Cckovych 
structu do souboru, pristup pres pointerovou aritmetiku, atd.).

Linux cachuje takovy napamovany soubor po strankach, protoze samotnou 
pamet spravuje po strankach (1 stranka pameti je na x64 velka 4 kB, huge 
pages jsou potom dalsi extra story na jindy...). Jakmile aplikace chce 
precist nejaka data, Linux na pozadi, pokud uz to neudelal, pro ta data 
alokuje stranku fyzicke pameti, aby ta data mela realne, kde sedet, 
precte je do te stranky z disku (nebo kde ten soubor je) a pak tu 
stranku namapuje do prislusneho mista virtualniho pametoveho prostoru 
naseho procesu, ktery ta data cte.

Jadro vede mapovane stranky v evidenci pomoci LRU listu, coz je datova 
struktura, seznam, ktery se vyznacuje tim, ze vede v evidenci, ktera 
polozka byla pouzita naposled (tak, ze se meni pri jejim pouziti jeji 
poradi na zacatek seznamu).

Kdyz vsechno funguje jak ma, v realne fyzicke pameti jsou pouzivana 
ctena data a jeste nezapsane "pospinene" (dirty) stranky, do kterych se 
psalo, tj. je u nich naplanovano, aby se co nejrychleji dostaly na disk 
(pokud teda cely soubor nebyl otevreny s flagem O_SYNC, nebo podobne, co 
by vynutilo kazdou zmenu zapsat na disk ihned, nez Linux vrati kontrolu 
aplikaci pri tom zapisu do mapovaneho souboru; to neni tak caste a to je 
nam ted "jedno").

Zapis je nastesti vyreseny dobre, Linux ma na to mechanismus, kteremu 
rika "writeback throttle"; kdyz detekuje, ze se zacina RAM plnit vic, 
nez je zdravo, zacne aplikaci ty zapisujici pristupy adekvatne 
zpomalovat. Tohle "impedancni prizpusobeni" funguje vcelku dobre, navic 
funguje dostatecne dobre i pod memory cgroup.

Memory cgroup je mechanismus, kterym omezujeme pridelenou pamet 
kontejnerum pod Linuxem - je to volitelna sada dalsich pocitadel vyuziti 
pameti, nad zakladni systemove, plus vydeleni ukazatelu na LRU, 
writeback a dalsi cache, aby se dalo pekne vest takovehle seznamy 
stranek v oddelene, mimojine aby bylo jasne, co komu patri, kdyz dojde 
cas tu pamet jednou odklidit. Ale taky, aby se dalo hlidat maximalni 
vyuziti pameti na ruzne caches - zdaleka nejen - kvuli prave mapovanym 
souborum.

Potud vsechno dobre.

To nam tak system nabehne, pospousti se na nem stovka VPSek, vsechny 
aplikace se krasne rozbehnou, nektere si namapujou soubory, nektere do 
nich vesele zapisuji data...

System muze bezet klidne mesice bez problemu, vsechno stiha, v pohode. 
Ty seznamy jsou bezne docela kratke, takze sbirka jadernych threadu 
"kswapd" je na pozadi pekne stiha prochazet a odklizet, jak se postupne 
nektere memory cgroupy dostavaji s pameti do uzkych.

Koneckoncu, 4 GB RAM (na jeden kontejner) prelozeno na 4 kB stranky 
znamena teoretickou maximalni delku jednoho seznamu 1M polozek. To se na 
2+ gigahertzovych CPU preci stihne projit rychle, ze.

No a pak se stane, ze po treba dvou mesicich behu systemu najednou 
zoufaly clen pise, ze mu v kontejneru dochazi pamet, pritom at pocita, 
jak pocita, nemuze se dopocitat, ze by to zabiraly aplikace - je videt, 
ze je to tim, ze caches nechteji odcouvavat.

Hm, docela spatenka, jak to mame opravit, kdyz to trva tak dlouho, nez 
se problem projevi? :-D

Tady nekde bych mel podotknout, ze abych byl schopny to takhle pekne 
vysvetlit, musel jsem doprojit celou cestu do vyresena, takze ted se to 
jevi zpetne jako trivka, ale nez jsem prisel na to, z ktere strany ten 
problem pujde aspon nejak resit...

Kdyz se clovek na takovy trpici system prihlasi, vidi tam zpravidla 
kswapd0 na 100% a kdyz ma ta masina dva fyzicke CPU, tak tam vidi 
vetsinou i kswapd1 v tom samem stavu.

V dmesgu jsou videt out of memory hlasky z jednotlivych kontejneru, jak 
narazeji na neodkliditelne caches a jadro zoufale zabiji stare procesy, 
aby udelalo misto pro dalsi.

V tech OOM hlaskach je videt pokazde i stack trace, odkud ta OOM udalost 
z jadra prisla - vetsina z nich byla vyvolana kvuli cteni do mmaped 
souboru, coz se pozna tak, ze v tom stacku jsou videt funkce pridavajici 
LRU stranky na seznam te memory cgroupe.

Tak si rikam, hm, to ma preci snadne reseni, nebudeme uctovat mapovanou 
pamet do memory cgroup clenu, ale nechame ji v root memory cgroup...

Okay, to by mohlo fungovat, ze?

..a zase, kswapd0/1 na 100%...

To uz jsem se zacal seriozneji zajimat, co se to vlastne deje, co delaji 
tak dlouho a jak to cele funguje, kdyz to neslo smaznout "izy hackem".

Napad to byl dobry, fungoval by, nebyt mensi drobnosti:

kswapd, kdyz odklizeji caches na pozadi, prohledavaji memory cgroupy 
stylem "dej mi takovou, ktera zere nejvic a tu odklidime, kdyz to nebude 
stacit, pujdem na dalsi".

Tj. pokud se objevi jedna cgroup, ktera je vetsi a ma toho vzdycky vic k 
odklizeni, muze se vzdycky kswapd zahojit na ni a k dalsim se ani 
nedostat.

Jedine, kdy se odklizi pamet uplne primo z te memory cgroupy, je tzv. 
"direct reclaim", cesta kodu primo v momente, kdy je potreba alokovat - 
ale v tu chvili neni tolik casu na uklizeni, tak se jadro zas tak 
nesnazi a nekdy to muze vzdat predcasne a rict, ze pamet nenaslo a 
vyvola OOM situaci v postizene memory cgroupe.

Hmm... okay, takhle by to neslo, tak zkusme mmaped pamet neuctovat 
cgroupam vubec a nechme ji v zakladnich systemovych seznamech...

A po trochu zapaseni, bo se v jadre s memory cgroup nepocita, ze by 
nahodou mmaped pamet nebyla uctovana zadne memory cgroupe, je vyreseno, 
odchod na parek!

...do chvile, nez tim posleme celou masinu out-of-memory a OOM chyby 
zacnou prichazet odkudkoliv, ne jen z mmaped readu odzpod z 
mem-cgroup...

Totiz kdyz byly mmaped soubory uctovany na jeden seznam, ktery neni v 
memory cgroupe, myslelo si jadro, ze ma hodne volnou ruku v tom, co si 
muze dovolit nechat nacachovane - ale v tom je potom mensi caveat se 
ZFS... postupny nahodny random access pattern k datum mmaped souboru 
nadela z ARC slab caches fragmentovane reseto, jeste kdyz se drzi ty 
kousky z tech puvodne nactenych dat pri zivote "pripinovanim" na jeden 
velky seznam, ktery nema duvod couvat, protoze host ma preci vsechnu 
pamet k dispozici bez limitu :D

No pak a chudaci kswapd, kdyz si s tim bordelem maji nejak poradit a 
odklidit to, *obzvlast* kdyz jsou jen dva a kdyz pod nima mame (konecne 
spravne nastavene se spravnym ashiftem) NVMe pole... na te staging node 
(nyni node1.stg) se tak darilo zaplnit RAM az skoro do mrtva.

Takze co s tim? :)

Snadna reseni dosla, bude potreba odklizet ty seznamy 
per-limitovana-memory-cgroup.

Na nekolik iteraci jsem nakonec dospel k patchi, ktery spusti 
per-NUMA-node "ksoftlimd" thready, pro kazdou memory cgroupu, ktera ma 
nastaveny soft_limit.

Ksoftlimd pak dela presne toto - prochazi seznamy svoji memory cgroupy a 
drzi si je okolo soft_limitu.

Kswapd maji o praci s memory cgroupama min, pokud je jadro nastavene v 
rezimu, ze ma ksoftlimd poustet automaticky (da se tez spoustet jen 
rucne).

My jsme zatim defaultne zvolili soft_limit jako watermark, nad ktery se 
ma ksoftlimd snazit vic odklizet, nastavujeme ho na 80% pameti 
kontejneru - ale do budoucna mozna tohle jeste predelam na nejakou vetsi 
automatiku, podle toho, jak kde se ukazou pripadne nedostatky.

Tedy, vysledna situace je, ze pokud aplikace zerou min, jak 80% pameti, 
ale je co drzet v RAM jako cache, bude mit kontejner vyuzito okolo tech 
80% - bude to videt normalne jako aplikacni pamet a zbytek jako caches. 
Uz by se nemelo stat, ze vyuziti stoupne az ke 100% kvuli caches a ze 
dojde k OOM a zabijeni procesu.

Zaverem bych jeste zminil ty patche:

Pokus mmaped soubory nauctovat root mem cgroupe:

https://github.com/vpsfreecz/linux/commit/d42232f89795

Pokus mmaped soubory mem cgroupam neuctovat vubec (popis commitu je blbe 
a celkove je nedocisteny, nebyl jsem s tim spokojeny a nechtel jsem tim 
travit vic casu, radsi jsem koumal, co dal, at the time...) ->

https://github.com/vpsfreecz/linux/commit/c10ae4a7ef95

A finalne, aktualne nasazena verze ksoftlimd patche:

https://github.com/vpsfreecz/linux/commit/e04b3f9cda1d

A uplne-uplne zaverem: linux kernel neni advanced black magic. Je to jen 
strasne velka a nekdy dost neforemna kupa C kodu, ktery potrebuje 
schopne a ochotne instalatery.

V koncinach memory cgroup + memory managementu je teda hodne, co 
zlepsovat, a vubec to neni raketova veda... Teda obecne, na 
kontejnerizace v Linuxu je dost co resit.

Takze kdybyste s tim jadernym vyvojem nekdo chtel pomoct, stavte se na 
IRC, nebo v Base48 v Brne pokecat, neco vymyslime, bude to zabava, trust 
me ;)

/snajpa


More information about the Community-list mailing list