Velmi zjednodusene mozeme rozdelit pamat v linuxe na 2 typy:
mapped - aplikacie - stack, data, loadnute kniznice, alokovana pamat za behu app, ...
unmapped - page cache (diskova cache) - cahuju sa tam fajly pri citani/zapise na disky, riesi to kernel nezavisle od aplikacii
(a este mame nejake dalsie ako slab, kde su tcp/ip stack buffre, directory entries, atd.)
Page cache je v linuxe nahovno implementovana.
Jeden z problemov, ktore ma trapia, je napriklad to, ze 1 task pri zapise alebo nacitani velkeho mnozstva dat odstrani z page cache vsetko ostatne a nahradi to tym, co cita/zapisuje.
Na desktope to tak nevadi.
Predstavme si ale vytazeny server, kde pristupuju stovky klientov a kazdy jeden demon, na ktory je pripojeny klient, cita ine data z disku a masivne sa tam vyuzivaju nacachovane data.
Zrazu sa spusti nejaky backup alebo ina aplikacia a zacne robit s objemnym mnozstvom dat.
Stane sa to, ze sa data potrebne pre tie demony z page cache odstrania,
nasledne demony cakaju na IO z diskov, lebo nemaju data nacachovane, server laguje a je to pekne v riti :)
Ukazka, server zo 16GB ram, vytvorime 6GB fajl, zmazeme ho a pozreme sa na pamat:
# dd if=/dev/zero of=foo bs=1M count=6144
6144+0 records in
6144+0 records out
6442450944 bytes (6.4 GB) copied, 67.489 seconds, 95.5 MB/s
# free -m
total used free shared buffers cached
Mem: 15928 15872 55 0 0 12946
-/+ buffers/cache: 2926 13001
Swap: 949 520 428
# rm foo
# free -m
total used free shared buffers cached
Mem: 15928 9630 6297 0 0 6865
-/+ buffers/cache: 2765 13163
Swap: 949 520 428
Ako mozete vidiet - 6GB nam zmizlo z cached a je free.
Vytvorenie 6GB suboru nam odstranilo z cache 6GB nacachovanych dat
a nasledne zmazanie suboru uvolnilo pamat z page cache.
V linuxe uz dlho existuje nejake limitovanie pamate pre procesy (syscall setrlimit()), napr. builtin prikaz ulimit v shelloch, alebo pam v /etc/security/limits.conf (hlavne pre uzivatelov, ktori sa prihlasia).
To nam ale limituje iba mapped pamat, nie page cache. Mozete aplikaciu olimitovat povedzme na 100MB, ale aj tak pri citani/zapise velkeho mnozstva dat vam odcachuje potrebne data z page cache.
V novych kerneloch nam pribudla pekna featura tzv. control groups, pomocou nej mozeme nastavit pre rozne procesy limity na celkovu pouzitu pamat.
Teda mapped aj unmapped, taktiez nastavit iba konkretne cpu pri smp systemoch, kde maju dane procesy bezat.
Kernel v ubuntu ma vsetko co je treba, tak si to podme rovno ukazat, ako sa to konfiguruje.
# mkdir /cgroup
# mount -t cgroup -o cpuset,memory none /cgroup
Tymto sme namountovali hlavnu cgroupu, kde su vsetky procesy.
V /cgroup/tasks je zoznam pidov.
# cat /cgroup/cpuset.cpus
0-3 <--- 2 cpucka po 2 jadra, teda 4 jadra dokopy
# cat /cgroup/cpuset.mems
0-1<--- iba pri numa systemoch, kazde cpucko ma vlastnu pamat, maju to hlavne opterony, ale su aj xeony z numa podporou
Vytvorime si novu cgroup pomocou mkdir
# mkdir /cgroup/test (tu sa nam objavia automaticky vsetky subory ako v /cgroup/)
Teraz musime nastavit cpucka a pamat, lebo defaultne ma nova cgroupa vsetko prazdne.
# cat /cgroup/cpuset.cpus >/cgroup/test/cpuset.cpus
# cat /cgroup/cpuset.mems >/cgroup/test/cpuset.mems
Olimitujeme tuto cgroupu na 128MB ram.
# echo 128M >/cgroup/test/memory.limit_in_bytes
Hodime pid bashu, s ktorym robime do novej cgroupy, vsetky novovytvorene child procesy budu automaticky v tejto cgroupe.
# echo $$ >/cgroup/test/tasks
vytvorime 6GB fajl
# dd if=/dev/zero of=foo bs=1M count=6144
6144+0 records in
6144+0 records out
6442450944 bytes (6.4 GB) copied, 108.919 seconds, 59.1 MB/s
# free -m
total used free shared buffers cached
Mem: 15928 15696 231 0 0 13417
-/+ buffers/cache: 2278 13649
Swap: 949 556 392
# rm foo
# free -m
total used free shared buffers cached
Mem: 15928 15553 374 0 0 13291
-/+ buffers/cache: 2262 13665
Swap: 949 556 392
Voila, dd nam nezmazalo 6GB z page cache, ale bolo limitovane na 128MB ram
a v pripade, ze aplikacia prekroci sama nastaveny limit pamati (nie page cache), tak ju killne OOM killer.
Mozme ju zrusit
# rmdir /cgroup/test
rmdir: /cgroup/test: Device or resource busy
Samozrejme sa neda, lebo tam mame bash,
tak ho najskor prehodime do hlavnej cgroupy
# echo $$ >/cgroup/tasks
# rmdir /cgroup/test
Page cache je stale nahovno, ale toto je aspon nieco, cim mozme olimitovat rozne aplikacie na serveri.
Dalsou zaujimavou vecou v cgroups, ktora este nie je priamo v kerneli, je bio-cgroup + dm-ioband - tym sa da limitovat I/O bandwith, ale netestoval som.
Existuju aj nejake userspace tooly, ale neskusal som ani jeden. Niekde na fedora stranke som videl, ze maju aj pam modul pre cgroups, netestoval som ho.
este k tomu page cache
idealne by bolo samozrejme zriesit nejake limity per process, s tym ze by sa dynamicky menili a ARC pre nacachovane data ( ARC aka adaptive replacement cache je nejaky mix LRU a LFU, vid http://en.wikipedia.org/wiki/Cache_algorithms )
lebo rozne workloady, rozne spravanie sa
napr na servery kde nam bezi iba mysqld, tak nech si pouzije celu page cache
ale na servery nam bezi 300 imapd deamonov, tak kazdy by mal mat nejaky limit aby toho neodstranil z page cache moc
tesim sa na otestovanie ZFS v opensolarise a jeho ARC, podla slajdov co som videl to vyzera celkom zaujimavo
Toto je sikovne, diky za clanok :-).
Nenapises nejaky aj o manazovani tej mapped pamate? (kde ide co nastavit, tooly, atd)
mozno niekedy ;)
Vynikajuci napad rozobratia tak nestandardnej problematiky. Vzdy ma zaujimalo, kolko Ti trvalo dotiahnutie sa na takuto uroven detailnej znalosti tohto systemu. Podla mna o linuxe do takejto podrobnosti vie len male percento uzivatelov. Mohol by si mi trochu nacrtnut Tvoje kroky a dobu studia?
z linuxom sa hram vyse 10 rokov a spravujem servery nejakych 4,5 rokov
ono sa to na cloveka postupne nalepi ak neustale riesi nejake problemy preco to nejde, ide to pomaly, atd. :)
Vyborne, pacilo sa mi to -- zrozumitelne a jasne ;-)
Ine systemy maju page cache napisanu lepsie?
--
On neni mrtev, on jenom spi!