Teraz vám prinášame trošku technicky náročnejší článok o problematike s ktorou sa museli naši admini vysporiadať.

Veľmi zjednodušene môžeme rozdeliť pamäť v Linuxe na 2 typy:

  • mapped – aplikácie – stack, data, loadnuté knižnice, alokovaná pamäť za behu app, …
  • unmapped – page cache (disková cache) – cacheujú sa tam súbory pri čítaní/zápise na disky, rieši to kernel nezávisle od aplikácií
  • (a ešte máme nejaké ďalšie ako slab, kde sú TCP/IP stack buffre, directory entries, atď.)

Page cache je v Linuxe nie najlepšie implementovaná.
Jeden z problémov, ktoré ma trápia, je napríklad to, že jeden task pri zápise alebo načítaní veľkého množstva dát odstráni z page cache všetko ostatné a nahradí to tým, čo číta/zapisuje.

Na desktope to tak nevadí.
Predstavme si ale vyťažený server, kde pristupujú stovky klientov a každý jeden démon, na ktorý je pripojený klient, číta iné dáta z disku a masívne sa tam využívajú nacachované data.

Zrazu sa spustí nejaký backup alebo iná aplikácia a začne robiť s objemným množstvom dát.
Stane sa to, že sa dáta potrebné pre tie démony z page cache odstránia, následne démony čakajú na IO z diskov, lebo nemajú dáta nacachované, server laguje a je to pekne v **** 🙂

Ukážka, server zo 16 GB RAM, vytvoríme 6 GB file, zmažeme ho a pozrieme sa na pamäť:

# 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 môžete vidieť – 6GB nám zmizlo z cached a je free.
Vytvorenie 6GB súboru nám odstránilo z cache 6GB nacachovaných dát a následne zmazanie súboru uvoľnilo pamäť z page cache.

V Linuxe už dlho existuje nejaké limitovanie pamäte pre procesy (syscall setrlimit()), napr. builtin príkaz ulimit v shelloch, alebo pam v /etc/security/limits.conf (hlavne pre užívateľov, ktorí sa prihlásia).
To nám ale limituje iba mapped pamäť, nie page cache. Môžete aplikáciu olimitovať povedzme na 100 MB, ale aj tak pri čítaní/zápise veľkého množstva dát vám odcachuje potrebné dáta z page cache.

V nových kerneloch nám pribudla pekná featura tzv. control groups, pomocou nej môžeme nastaviť pre rôzne procesy limity na celkovú použitú pamäť.
Teda mapped aj unmapped, taktiež nastaviť iba konkrétne CPU pri smp systémoch, kde majú dané procesy bežať.
Kernel v Ubuntu má všetko čo je treba, tak si to poďme rovno ukázať, ako sa to konfiguruje.

# mkdir /cgroup
# mount -t cgroup -o cpuset,memory none /cgroup

Týmto sme namountovali hlavnú cgroupu, kde sú všetky procesy.
V /cgroup/tasks je zoznam pidov.

# cat /cgroup/cpuset.cpus
0-3 <--- 2 CPU po 2 jadrá, teda 4 jadrá dokopy.
# cat /cgroup/cpuset.mems
0-1<--- iba pri numa systémoch, každé CPU má vlastnú pamäť, majú to hlavne Opterony,
ale sú aj Xeony z numa podporou.

Vytvoríme si novú cgroup pomocou mkdir

# mkdir /cgroup/test (tu sa nam objavia automaticky vsetky subory ako v /cgroup/)
  Teraz musíme nastaviť CPU a pamäť, lebo defaultne ma nová cgroupa všetko prázdne.
# cat /cgroup/cpuset.cpus >/cgroup/test/cpuset.cpus
# cat /cgroup/cpuset.mems >/cgroup/test/cpuset.mems
  Olimitujeme túto cgroupu na 128 MB RAM.
# echo 128M >/cgroup/test/memory.limit_in_bytes
  Hodíme pid bashu, s ktorým robíme do novej cgroupy, všetky novovytvorené child
procesy budú automaticky v tejto cgroupe.
# echo $$ >/cgroup/test/tasks
  vytvoríme 6GB file
# 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 nám nezmazalo 6 GB z page cache, ale bolo limitované na 128 MB RAM a v prípade, že aplikácia prekročí sama nastavený limit pamäti (nie page cache), tak ju killne OOM killer.

Môžeme ju zrušiť

# rmdir /cgroup/test
rmdir: /cgroup/test: Device or resource busy
  Samozrejme sa nedá, lebo tam máme bash,
  tak ho najskôr prehodíme do hlavnej cgroupy
# echo $$ >/cgroup/tasks
# rmdir /cgroup/test

Page cache je stále zle vyriešené, ale toto je aspoň niečo, čím môžeme olimitovať rôzne aplikácie na serveri.
Ďalšou zaujímavou vecou v cgroups, ktorá ešte nie je priamo v kerneli, je bio-cgroup + dm-ioband – tým sa dá limitovať I/O bandwith, ale netestoval som.

Existujú aj nejaké userspace tooly, ale neskúšal som ani jeden. Niekde na Fedora stránke som videl, že majú aj pam modul pre cgroups, netestoval som ho.

Komentáre