Se zdroji fyzického stroje je to jednoduché - kolik paměti a jak výkonný procesor si koupíte, tolik máte. S virtuálními servery je to složitější. Některé virtualizační technologie to správci hodně zjednoduší a umožní virtuálnímu serveru přidělit paměť, počet procesorů, a tím to končí. Jiné, jako OpenVZ, poskytují správci mnohem jemnější kontrolu nad přidělovanými zdroji.
V předchozích dílech seriálu jsem se opomněl zmínit, že je velmi vhodné použít na VE0 64bitový kernel. Pokud zvolíte 32bitový, musíte počítat s tím, že některé zdroje musí OpenVZ alokovat z prvních 832 MB RAM. To je totiž prostor, který je vždy namapovaný do adresového prostoru kernelu, ostatní paměť je pak přístupná pomocí stránkování, což přístup zpomaluje. Pokud se vás to týká, přečtěte si obecné informace o tzv. Low Memory na LWN.net, a poté o dopadech na OpenVZ. Potřebujete-li provozovat 32bitový software uvnitř CT, není to problém na 64bitovém hostiteli. Problémy mohou nastat jen při kompilaci, pokud si autor ušetřil práci a parsuje výstup uname.
Přidělování a správa zdrojů v OpenVZ
OpenVZ přiděluje zdroje hostitele (VE0) pomocí čtyř mechanismů User BeanCounters, CPU Fair-Share plánovače, diskové quoty, a nakonec priority a accounting I/O operací. První dva mechanismy se vám pokusím vysvětlit v tomto dílu seriálu.
UBC aneb User BeanCounters
UBC jsou základní komponentou řízení zdrojů. Obsahují řadu parametrů, které definují, kolik a jakých zdrojů může container použít. Parametry ovládají především dostupnou paměť, a to i nepřímo, např. v podobě maximálního počtu otevřených souborů.
Rychlý přehled o jednotlivých zdrojích získáte zobrazením souboru /proc/user_beancounters. Ten je k dispozici nejen uvnitř containeru, ale i na VE0. Jen na VE0 je soubor poněkud nepřehledný, protože obsahuje informace o všech CT. Přehlednější informace jsou k dispozici v souboru /proc/bc/<CTID>/resources. Uvádím příklad z containeru:
root@deb6:/# cat /proc/user_beancounters Version: 2.5 uid resource held maxheld barrier limit failcnt 1000: kmemsize 2134853 2355374 14372700 14790164 0 lockedpages 0 0 256 256 0 privvmpages 2658 2707 65536 69632 0 shmpages 0 0 21504 21504 0 dummy 0 0 0 0 0 numproc 11 13 240 240 0 physpages 2047 2047 0 9223372036854775807 0 vmguarpages 0 0 33792 9223372036854775807 0 oomguarpages 2047 2047 26112 9223372036854775807 0 numtcpsock 3 3 360 360 0 numflock 3 4 188 206 0 numpty 1 1 16 16 0 numsiginfo 0 1 256 256 0 tcpsndbuf 52320 0 1720320 2703360 0 tcprcvbuf 49152 0 1720320 2703360 0 othersockbuf 138720 147176 1126080 2097152 0 dgramrcvbuf 0 0 262144 262144 0 numothersock 163 166 360 360 0 dcachesize 200772 208494 3409920 3624960 0 numfile 338 373 9312 9312 0 dummy 0 0 0 0 0 dummy 0 0 0 0 0 dummy 0 0 0 0 0 numiptent 10 10 128 128 0
Sloupec resource představuje název jednotlivých parametrů, sloupec held aktuálně držené množství prostředků a maxheld hodnotu maximálně držených prostředků od startu virtuálního serveru. Sloupce barrier a limit jsou nastavené limity pro jeden každý parametr. Některé parametry využívají obě hodnoty, jiné jen jednu a některé žádnou, ty pak slouží pouze pro accounting. Např. u parametru vmguarpages představuje hodnota limit maximální počet stránek paměti, které smí container alokovat, a hodnota barrier je garantovaný počet stránek, které jsou containeru k dispozici. Mělo by platit barrier <= limit.
Poslední sloupec failcnt je počítadlo, kolikrát nebyl požadavek containeru na ten který zdroj uspokojen. Z uživatelského hlediska je právě on tím nejdůležitějším. Když vidíte, že některý z nich roste, je pravděpodobné, že virtuální server strádá nějakým nedostatkem. V ten okamžik nastává moment, kdy je nutné se ponořit do dokumentace UBC a nastudovat, jestli je nutné s parametrem hýbat. Hodnota failcnt se nedá snadno vynulovat, ale existuje program vzubc, který umožňuje UBC zobrazovat relativně.
V prvním článku jsem vytvořil první virtuální server příkazem:
root@ve0:~# vzctl create 1000 --ostemplate debian-6-amd64 --ipadd 172.16.206.100 --hostname deb6
Neuvedl jsem parametr –config, takže mu byly přiděleny limity ze souboru /etc/vz/conf/ve-basic.conf-sample. Jsou relativně nízké a je docela pravděpodobné, že se uživatel takto připraveného CT seznámí s přibývajícími fazolkami ve sloupci failcnt hodně rychle.
Záleží hodně na účelu, pro který virtuální server vytváříte. Z vlastní zkušenosti vám ale nedoporučuji používat uvedené minimální limity. Jsou celkem nízké. Hodně ořezaný virtuální server znamená, že uživateli severu leccos nebude fungovat. Bude vás kontaktovat a vy to budete muset řešit. No a ve finále skončíte s tím, že budete mít řadu CT s hodně rozdílnými parametry.
Většina parametrů je nějakým způsobem závislá na dostupné operační paměti, zkuste tedy limity nastavit podle toho, kolik operační paměti by zamýšlený virtuální server potřeboval na fyzickém HW. Pro spočtení hodnot jednotlivých parametrů slouží program vzsplit. Např. máte-li fyzický server s 16 GB RAM a předpokládáte-li, že virtuálnímu serveru postačí 1 GB, zadejte:
ve0:~# vzsplit -n 16 -f 1G_RAM Config /etc/vz/conf/ve-1G_RAM.conf-sample was created
vzsplit vytvořil konfigurační soubor /etc/vz/conf/ve-1G_RAM.conf-sample, v němž jsou parametry odpovídající jedné šestnáctině zdrojů hostitele. V uvedeném příkladu má hostitel 16 GB RAM. Virtuální server vytvořený podle tohoto konfiguračního souboru bude mít 1 GB paměti. Použití předpřipraveného souboru je snadné:
root@ve0:~# vzctl create 1010 --config 1G_RAM --ostemplate debian-6-amd64 --ipadd 172.16.206.110 --hostname deb6
Porovnání hodnot pro konfigurační soubor basic a 1G_RAM:
parametr | soubor basic | soubor 1G_RAM | ||
barier | limit | barier | limit | |
numproc | 240 | 240 | 5124 | 5124 |
numtcpsock | 360 | 360 | 5124 | 5124 |
numothersock | 360 | 360 | 5124 | 5124 |
vmguarpages | 33792 | 9223372036854775807 | 677212 | 9223372036854775807 |
kmemsize | 14372700 | 14790164 | 209884672 | 230873139 |
tcpsndbuf | 1720320 | 2703360 | 48973653 | 69961557 |
tcprcvbuf | 1720320 | 2703360 | 48973653 | 69961557 |
othersockbuf | 1126080 | 2097152 | 24486826 | 45474730 |
dgramrcvbuf | 262144 | 262144 | 24486826 | 24486826 |
oomguarpages | 26112 | 9223372036854775807 | 677212 | 9223372036854775807 |
privvmpages | 65536 | 69632 | 2459586 | 2705544 |
lockedpages | 256 | 256 | 10248 | 10248 |
shmpages | 21504 | 21504 | 245958 | 245958 |
physpages | 0 | 9223372036854775807 | 0 | 9223372036854775807 |
numfile | 9312 | 9312 | 81984 | 81984 |
numflock | 188 | 206 | 1000 | 1100 |
numpty | 16 | 16 | 512 | 512 |
numsiginfo | 256 | 256 | 1024 | 1024 |
dcachesize | 3409920 | 3624960 | 45847363 | 47222784 |
numiptent | 128 | 128 | 125 | 125 |
Nastavení limitů hodně ovlivňuje účel, pro který jste si OpenVZ vybrali. Mé zkušenosti, s nimiž píšu tento seriál, vychází z potřeby redukovat množství low end fyzických serverů a koncentrovat služby na kvalitních serverech vyšší třídy s tím, že služby ani jejich správci nemají být příliš omezováni. Limity pak nastavuji tak, aby virtuální server, na který probíhá DoS, nespotřeboval veškeré zdroje platformy. Když virtuální server potřebuje větší zdroje, po žádosti správce je obvykle dostane.
Dostanete-li se do situace, že budete chtít upravit jednotlivé parametry virtuálního serveru, použijte příkaz vzctl, syntaxe:
# vzctl set <ctid> --save --<parametr> <barier>:<limit>
Důležité je nezapomenout parametr –save. Bez něj se hodnoty parametru neuloží do konfiguračního souboru a po restartu CT se vrátí na původně nastavenou hodnotu. Po změně parametru se vyplatí nechat si zkontrolovat závislosti s ostatními parametry. K tomuto účelu slouží program vzcfgvalidate, použití je prosté:
root@ve0:~# vzcfgvalidate /etc/vz/conf/1000.conf Validation completed: success
V případě chyby vypíše srozumitelně, co je třeba změnit, uvádím příklad z našeho produkčního serveru (kterým bych se asi moc chlubit neměl):
# vzcfgvalidate /etc/vz/conf/<CTID>.conf Warning: dcachesize.lim should be > 1536000 (currently, 1097728) Error: tcpsndbuf.lim-tcpsndbuf.bar should be > 409600 (currently, 1000000-700000=300000) Error: othersockbuf.lim-othersockbuf.bar should be > 1280 000 (currently, 1200000-500000=700000) Warning: tcprcvbuf.lim-tcprcvbuf.bar should be > 409600 (currently, 1000000-700000=300000) Error: limit should be = 9223372036854775807 for physpages (currently, 2147483647)
Měl bych tedy zvýšit limit dcachesize, ale hlavně upravit barier a limit u tcpsndbuf, tcprcvbuf a othersockbuf. Když jsou tyto hodnoty příliš nízké, dochází k zamrzání síťových spojení.
Jakmile začnete s hodnotami jednotlivých UBC parametrů manipulovat, studiu dokumentace se nevyhnete. Dokumentace rozděluje parametry do tří skupin, vychází z vnitřní struktury OpenVZ, takže rozdělení nemusí být na první pohled zřejmé:
- primární parametry
- Jejich hodnota ovlivňuje hodnoty sekundárních parametrů. Jedná se o numproc, numtcpsock, numothersock a vmguarpages. Nejčastěji je třeba upravit numproc (maximální počet procesů) a numtcpsock (maximální počet TCP socketů).
- sekundární parametry
- Hodnota těchto parametrů je ovlivňována hodnotou příslušných primárních parametrů, vztahy jsou uvedeny v dokumentaci. Jmenovitě se jedná o kmemsize, tcpsndbuf, tcprcvbuf, othersockbuf, dgramrcvbuf, oomguarpages a privvmpages. Je skutečně třeba dodržovat doporučené limity, ale i tak občas v praxi narážím na narůstající failcnt u tcprcvbuf, případně tcpsndbuf, obvykle ve spojení s nedobrým výkonem TCP spojení, a velmi zřídka dokonce se zamrzáváním spojení. Pomáhá zvýšení hodnoty nad minimální doporučenou hodnotu.
- doplňkové parametry
- O těchto parametrech dokumentace říká, že ovlivňují bezpečnost a stabilitu celého systému, že zlepšují to, jak se aplikace uvnitř containeru vyrovnávají s případným nedostatkem zdrojů. Je jich poměrně hodně: lockedpages, shmpages, physpages, numfile, numflock, numpty, numsiginfo, dcachesize, numiptent, swappages. V praxi se setkáte se situací, že aplikace, která nedostane to, co potřebuje, prostě zkolabuje. Nejčastěji upravuji shmpages (sdílená paměť, Apache ji používá rád a hodně), numfile (počet otevřených souborů) a numiptent (počet položek IP firewallu).
Jednotky, ve kterých se parametr měří, jsou naznačeny v jeho názvu. Parametry obsahující num jsou počty položek. Parametry obsahující v názvu page jsou paměťové stránky, velikost stránky se liší podle systému, na x86 and x86_64 je to 4096 B a na IA64 je stránka velká 16384 B.
Monitoring UBC
V praxi můžete narazit na fakt, že budete potřebovat znát časovou závislost vývoje spotřeby jednotlivých parametrů u konkrétního CT. Mně se hodně osvědčil Munin. Výhodu spatřuji v tom, že jednou nastavím server, který sbírá data z jednotlivých uzlů (hostitelů virtuálních serverů), a jednotliví hostitelé virtuálních serverů pak sami předávají informace o UBC jednotlivých CT, které na nich běží. Před několika lety jsem pro Munin připravil plugin, který používám dodnes. Grafy, které produkuje, se výborně hodí, když je třeba zpětně řešit nějaký problém.
Příklad vývoje velikosti buferů pro jednotlivé sockety:
CPU Fair-Share plánovač
Plánovač OpenVZ zajišťuje přidělování času procesoru ve dvou úrovních. V první úrovni přiděluje čas procesoru jednotlivým CT. Při této činnosti se řídí hodnotou parametru cpuunits, který je přidělen každému jednomu virtuálnímu serveru. Po tomto rozhodnutí je řízení předáno standardnímu linuxovému plánovači, který na základě priorit procesů rozhodne, kterému procesu přidělí čas.
Hodnota cpuunits nemá přímou vazbu na cykly procesoru. Jedná se o poměrnou hodnotu, která získává význam až v poměru vůči součtu všech cpuunits na systému. Jinými slovy můžete použít hodnoty 1 1 1 nebo 200 200 200 a nebo 8888 8888 8888 - a CT dostanou stejný díl času. Pokud uděláte toto:
# vzctl set 1001 --cpuunits 1000 --save # vzctl set 1002 --cpuunits 2000 --save # vzctl set 1003 --cpuunits 3000 --save
pak CT 1001 dostane 1000/6000, neboli 17 % času, CT 1002 dostane 2000/6000, neboli 33 % času a CT 1003 dostane 3000/6000, neboli 50 % času. Toto platí ale pouze tehdy, pokud všechny CT vyžadují čas procesoru. Pokud CT 1003 nevyžaduje CPU, jeho díl se rozdělí mezi ostatní CT, pokud ty CPU potřebují.
Je-li z nějakého důvodu potřeba omezit maximální spotřebovaný čas procesoru určitým CT, je k dispozici parametr cpulimit. Ten udává, kolik procent z jednoho CPU může CT využít, takže hodnota může být větší než 100, pokud chcete přidělit víc než jedno jádro. Dalším parametrem je cpus, kterým můžete omezit počet jader, k nimž bude mít CT přístup (nastavení ovlivňuje i obsah /proc/cpuinfo, a lze ho provádět za běhu).
Bohužel tato možnost je k dispozici pouze v kernelu verze 2.6.18. Mám ji otestovanou na RHEL 5.5 s kernelem 2.6.18–128.2.1.el5.028stab064.8. Na Debian Squeeze s kernelem 2.6.32–5-openvz-amd64 to nefunguje. V roce 2005 jeden z vývojářů přiznal, že opustili svůj plánovač a používají defaultní linuxový.
Soubor /proc/vz/vestat obsahuje statistiku o využití procesoru jednotlivými CT. Sloupce user, nice, system, uptime jsou v jiffies. idle, uptime (druhý výskyt) a used jsou v cyklech procesoru. Pro zajímavost uvádím část výpisu z našeho produkčního serveru:
# cat /proc/vz/vestat Version: 2.2 VEID user nice system uptime idle strv uptime used maxlat totlat numsched 1001 2377472 12039 778289 1407929044 23347007112226694 0 2956770446265516 8340747864432 0 0 1002 11562678 79207885 51819967 3228189174 53062117348749001 0 6779471159378854 301530700545860 0 0 1003 100462869 2428380224 1060215341 6164220823 93118401848819349 0 12945386729084366 7515216979094341 0 0 1004 1440440 0 1739857 6515373490 102929127518504858 0 13682837124463623 7311914244470 0 0 1005 10318933 90338 8912664 12214370580 202231032930022943 0 25651214571771123 50665663063448 0 0 1006 5331847 0 21646446 12539606845 204930997400964221 0 26334238322678234 61678306608473 0 0 1007 78940070 144485 8389905 15102223064 253238230150021975 0 31715949818023758 197645192017021 0 0 1008 35402455 109889 10527892 15103160860 252992838415551643 0 31717919269130391 141679427381790 0 0 1009 4493092 6810 4185957 15133369749 253628805278848224 0 31781360499479364 58063096149059 0 0 1010 21377827 103323 34991401 15133429525 253216433063174771 0 31781486032310792 128684994932897 0 0 1011 45970735 9108323 42381841 15133819159 248486749910943882 0 31782304297116858 209358507834538 0 0 1012 3313472 31764 3609644 15133856927 252897634907919124 0 31782383614523084 48816716280752 0 0 1013 6422412 0 14667208 15133884769 250767746840303880 0 31782442084703238 53807557319602 0 0 ...
Pro reálné použití účtování CPU budete muset do OpenVZ trochu proniknout nebo se zeptat v konferenci. Přiznávám, že jsem takhle detailní accounting nikdy v praxi nepotřeboval.
Zjištění příslušnosti procesu k CT
OpenVZ umožňuje správci nahlédnout do útrob jednotlivých CT, a tak se při správě virtualizačního serveru nemusíte omezovat jen na přidělování a počítání cyklů procesoru. Pomocí klasických linuxových nástrojů můžete procesy monitorovat. Když už identifikujete proces, který spotřebovává víc, než by měl, budete potřebovat zjistit, ke kterému CT patří. K tomu účelu slouží program vzpid. Jeho použití je jednoduché:
root@ve0:~# ps aux --sort pcpu |tail -5 2000 24516 56.6 0.1 12004 10468 ? RN 08:23 80:24 dnetc -hide -ini /usr/local/dnetc/dnetc.ini 2000 24519 57.0 0.1 12016 10468 ? RN 08:23 80:56 dnetc -hide -ini /usr/local/dnetc/dnetc.ini 2000 24517 58.5 0.1 12008 10468 ? RN 08:23 83:04 dnetc -hide -ini /usr/local/dnetc/dnetc.ini 2000 24518 58.6 0.1 12012 10468 ? RN 08:23 83:15 dnetc -hide -ini /usr/local/dnetc/dnetc.ini 2000 24514 60.1 0.1 11996 10464 ? RN 08:23 85:25 dnetc -hide -ini /usr/local/dnetc/dnetc.ini root@ve0:~# vzpid 24514 Pid VEID Name 24514 1001 dnetc
Tímto se s vámi dnes rozloučím a za domácí úkol vám nechám vyřešení tohoto zbytečného pálení energie uživatelem CT 1001. Příští díl seriálu bude o diskové kapacitě a zálohování.