Portál AbcLinuxu, 6. května 2025 00:03
Aktuální verze jádra: 3.2-rc4. Citáty týdne: Alan Cox, Russell King, Linus Torvalds. Bufferbloat: Temné buffery v Internetu. Omezení TCP bufferů pro řídící skupiny.
Aktuální vývojovou verzí jádra je 3.2-rc4 vydaná 1. prosince. Linus řekl, že se věci sice uklidňují, ale má obavy. Čekám, kdy to přijde. Davem a GregKH se asi drží stranou – jsou až podezřele potichu a mám pocit, že od nich slyším nějaké zlověstné hihňání. Nebo snad jen přišel čas na moje prášky.
Stabilní aktualizace: během posledního týdne žádné nevyšly. Verze 2.6.32.50 (27 patchů), 3.0.13 (80 patchů) a 3.1.5 (104) patchů jsou nyní v procesu revidování; můžeme je očekávat 9. prosince nebo později.
Jeden z omylů, kvůli kterému pravidelně vyhazujeme kód z jádra, se dá nejlépe popsat jako „uživatelské rozhraní autora“.
-- Alan Cox
Udělal jsi správnou věc – pokud se dotazuješ, tak lidé považují tvou zprávu za nedůležitou a neobtěžují se odpovídat s tím, že doufají, že se nic nestane.
Ale pokud zašleš patch, který odstraňuje platformu, tak to budou brát jako naprosto urgentní věc, protože pokud se jich to dotýká, tak to musí dát najevo, aby tomu zamezili. (I když máš v plánu to dát k zařazení až za nějakých 6 měsíců – ale to nesmíš v prvotní zprávě uvést!)
-- Russell King
Zběsilá bezpečnostní politika je skoro norma. Ale zběsilé funkce vrstvy VFS mě rozčilují.
Jim Gettys a Kathleen Nichols zveřejnili v ACM Queue kompletní, aktualizovaný popis problému „bufferbloat“. Aby ochrana proti ucpání [congestion] v TCP byla lidem používajícím danou linku k užitku, TCP spojení způsobující ucpání linky musí rychle reagovat na změny v poptávce po ucpávané lince, jenže reakční doba TCP je druhou mocninou nadbytečného bufferování. Linka, která je 10násobně přebufferovaná, má nejen 10násobnou latenci, ale její reakce na ucpání je stonásobně dlouhá. Vaše krátké, interaktivní TCP spojení prohraje v souboji s dlouhotrvajícím tokem, který saturoval vaši linku, na celé čáře.
Řídící skupiny jsou užívány k řadě účelů, ale nejdůležitějším smyslem je pro mnoho lidí omezování prostředků skupinám procesů. Řízení spotřeby paměti se v posledních letech dočkalo spousty vývojářského úsilí, ale má dosud řadu nedostatků, přičemž jedním z nich je to, že omezuje pouze paměť v uživatelském prostoru. Některé způsoby práce mohou vést k užití velkého objemu paměti v jádře, což vede v systému k všeobecné tlačenici o paměť, ale řízení paměti nemůže toto využití omezovat. První krok k nápravě tohoto problému si svou cestu do jádra verze 3.3 musí ještě probojovat, ale ukazuje, jak obtížné to může být.
Patch Glaubera Costy pro řízení využití paměti v TCP na základě řídících skupin začíná tím, že do řízení paměti přidává trochu té infrastruktury pro sledování využití paměti v jádře. Je přidána dvojice nových čudlíků: memory.kmem.limit_in_bytes
řídí, kolik jaderné paměti může řídící skupina využít, zatímco memory.independent_kmem_limit
je booleovská hodnota, která rozhoduje, zda se limity jádra budou spravovat odděleně od limitů uživatelského prostoru. Pokud je tento boolean nastaven na false, využití paměti jádrem je jednoduše přičteno k využití v uživatelském prostoru a jaderný limit je ignorován. Přibyla také hodnota memory.kmem.usage_in_bytes
, jejímž přečtením lze zjistit, jaké je aktuální využití paměti.
Infrastruktura je hezká věc, ale je tu jedna taková komplikace: existují tisíce míst v jádře, kde se alokuje paměť a žádné z nich není instrumentováno tak, aby se tyto alokace mohly připsat na účet určité řídící skupiny. Implementace takového účtování napříč jádrem se nemusí nikdy vynořit; rozhodně ne hned zpočátku. Tudíž se vývojáři se záměrem přidat tuto funkčnost musí zaměřit na konkrétní datové struktury. V minulosti se něco dělalo kolem aplikování omezení na dentry cache, ale Glauber si zvolil jiný cíl: buffery použité v implementaci síťového protokolu TCP.
Tyto buffery drží data paketu při jeho průchodu socketem; v některých situacích mohou dosti narůst, takže je logické uplatňovat omezení právě tady. Ještě lepší je ale to, že síťová vrstva už má logiku pro nastavování omezení na velikosti bufferů, když je paměti málo. V současných jádrech se síťový kód snaží maximálně pomoci, kdykoliv se systém zdá být v nedostatku paměti. Mezi jeho reakce patří rozhodování o nezvětšení velikosti okének TCP, zahazování paketů nebo odmítnutí zvětšení bufferu pro odchozí data.
Vzhledem k tomu, že infrastruktura už byla na místě, Glauberovi jen stačilo rozšířit představu toho, co se skrývá pod „nedostatkem paměti“. To znamenalo instrumentovat místa, kde se alokuje a uvolňuje paměť, aby se tyto alokace připsaly k patřičné řídící skupině. Následně se z „nedostatku paměti“ stane kombinace předchozí globální hodnoty a stavu aktuální řídící skupiny s ohledem na omezení paměti jádra. Pokud byl tento limit překročen, síťová vrstva se bude chovat (u socketů dané řídící skupiny), jako by systém jako celek měl nedostatek paměti, ačkoliv globální stav toto nevykazuje.
První patch dělal právě toto a vypadalo to, že se věc dostane do začleňovacího okna 3.2. Narazil ale na drobný zádrhel, jakmile se na to podívali vývojáři od síťování. Správce síťové vrstvy David Miller patch okamžitě odmítl, přičemž si stěžoval na režii, kterou kód přidává do rychlých cest v síťovém kódu, a to i v případech, kdy se celá tato funkčnost nevyužívá. Dodal:
Lidé se každých několik vydání začnou ptát „kde je sakra výkon, co jsem míval“ a je to kvůli plíživým funkčnostem, jako je tato. Tahle funkce socketů a kontrolních skupin je dokonalou ukázkou, kde se tyhlety věci berou.
Opravdu mě rozčiluje, když někdo začne říkat „ale je to přece jen jedno nepřímé volání funkce“ a „ale je to přece jen jeden ukazatel navíc ve struktuře socketu“. Skutečně dřeme, abychom ze struktur _odstraňovali_ položky, zmenšovali je a abychom z rychlých cest odstranili náročné operace.
Existuje mnoho důležitých míst v jádře, kde se alokuje paměť, a nacházejí se v místech, kde to docela dost lítá; síťoví vývojáři blázní, kdykoliv se jedná o přidání režie do takových míst, ale jistě nejsou ve svých obavách sami. Takže bylo třeba najít řešení, které by neznamenalo režii pro systémy, kde se funkce nevyužívá.
Slovo „nevyužívá“ je zde také důležité. Pokud se ukáže omezování paměti alokované v jádře být užitečným, distributoři tuto funkci budou chtít v jádrech, která dodávají, povolit. Ale i tak ji většina uživatelů nevyužije. Takže nestačí odstranit režii jen v případech, kdy byla funkčnost odstraněna z jádra. Takováto funkčnost se skutečně musí vyvarovat tomu, aby měla nějaký negativní dopad, když není využita, ačkoliv byla při kompilaci zapnuta.
Aby Gluber tyto požadavky splnil, musel v patchi udělat rozsáhlé změny. Omezení bufferů TCP je nyní jako celek spravováno odděleně od limitů jádra; při nastavování tohoto limitu přibyl nový čudlík (kmem.tcp.limit_in_bytes
). Všechen kód v rychlých cestách je nyní zahrnut ve statické větvi, což znamená, že pokud kód není povolen, tak je možné jej přeskočit prakticky bez režie. Statická větev je zapnuta jen v případě, že je limit bufferů TCP stanoven pro nekořenovou řídící skupinu. Takže by, jak bylo požadováno, neměl mít znatelný vliv v jádrech, kde je funkčnost zapnuta při kompilaci, ale není aktivní.
V době psaní tohoto textu nebylo ohlášeno rozhodnutí o zařazení těchto patchů do jádra 3.3, ale objem kritiky se vytrvale zmenšuje. Takže věc má šanci se dostat do hlavní řady v příštím začleňovacím okně. Nicméně na Glauberově případu je vidět, jak těžké bude dostat do jádra ještě více „účtování“ paměti; požadavek na neznatelnost dopadu povede k většímu množství práce a záludnějšímu kódu. Už jen proto je nepravděpodobné, že se bude sledovat využití paměti v celém jádře. Vývojáři se budou soustředit jen na těch pár případů, kdy stanovení omezení může přinést zásadní změny v chování a není třeba řešit ty ostatní.
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.