Poutave vysvetleni, dobra prace diky.
čt 13. 8. 2020 v 13:02 odesílatel Pavel Snajdr <snajpa(a)snajpa.net>
napsal:
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 [1]
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 [2]
A finalne, aktualne nasazena verze ksoftlimd patche:
https://github.com/vpsfreecz/linux/commit/e04b3f9cda1d [3]
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
_______________________________________________
Community-list mailing list
Community-list(a)lists.vpsfree.cz
http://lists.vpsfree.cz/listinfo/community-list [4]
_______________________________________________
Community-list mailing list
Community-list(a)lists.vpsfree.cz