Portál AbcLinuxu, 20. května 2024 12:03

Systemd – vlastnosti a schopnosti

23. 3. 2011 | Michal Vyskočil
Články - Systemd – vlastnosti a schopnosti  

Systemd je nejnovější hvězda v tak poklidné a konzervativní oblasti, jako jsou init systémy. V následující sérii článků si probereme jeho vlastnosti. Dnešní díl bude o přístupu systemd k problematice a vlastnostech celého systému.

Obsah

Rethinking PID 1

link

Koncem dubna 2010 Lennart Poettering (možná znáte jeho ostatní projekty – PulseAudio a Avahi) napsal blog Rethinking PID 1. V něm oznámil vznik svého projektu systemd, který mění způsob nazírání na init, čili procesu s PID 1.

Jako hlavní znak dobrého systému Lennart uvádí rychlý start, což je poněkud nešťastné, protože odvádí pozornost od inovativního návrhu a způsobu fungování. Ale budiž.

Skutečně paralelní start démonů

link

Problém paralelizace řeší prakticky každá alternativa, nicméně v praxi to pak dopadá následovně – chceme spustit libvirtd a X11. Oba nicméně potřebují (potřebovali) HAL, který ovšem potřebuje D-BUS démona, který potřebuje spuštěný syslogd. Celé to obrovské úsilí o paralelizaci skončilo tím, že první tři služby se zavádějí postupně a teprve poslední dvě vedle sebe.

Ve snaze odstranit tyto sériové závislosti se systemd dívá na problematiku jinak. Co je skutečně potřeba pro sériové spouštění démonů? Klasické unixové démony obvykle vyžadují přítomnost služby poskytované jiným démonem, což je typicky AF_UNIX socket někde v souborovém systému. Ale může to být i AF_INET, anebo speciální zařízení. Takže třeba D-BUS klient potřebuje unix socket /var/run/dbus/system_bus_socket, k němuž by se mohl připojit a démon zapisující do systémového logu zase očekává socket /dev/log.

Takže, pokud se podaří tyto sockety vytvořit dříve, můžeme oba dva démony jednoduše spustit současně, ačkoli jsou jejich závislosti sériové. Naštěstí v unixových systémech je to prosté – můžeme vytvořit socket před startem vlastního démona a potom mu jej předat prostřednictvím volání exec(). V případě, že nějaký jiný démon potřebuje s takovým socketem pracovat, pak je prostě přidán do fronty požadavků a pozastaven do doby, než se spustí démon, který takové požadavky akceptuje.

Díky tomu systemd nevyžaduje explicitní uvádění závislostí. Celá tato mašinérie jednoduše využívá existující kód v jádře a jako vedlejší efekt nabízí opravdu masivně paralelní start všech služeb.

Odložené spuštění

link

Alternativní a prakticky nevyužívaná strategie pro zkrácení doby startu je odložení doby startu démona až na doby, kdy bude existovat první požadavek na její spuštění. Tento přístup byl implementován desítky let jako démon (x)inetd, ale jako samotný init systém se neujal.

V praxi existuje mnoho případů, kdy není nezbytné startovat služby při startu. Tiskový démon cups není nezbytné spustit dříve, než přijde první požadavek na tisk. Bluetoothd není třeba, pokud neexistuje potřeba komunikovat přes bluetooth, avahi není nutné, když není systém připojen k síti a dokonce ani ssh démona nemusíme spouštět, pokud se na něj zrovna nechce někdo připojit.

Princip, na kterém systemd provádí masivní paralelní start, lze jednoduše použít i pro spouštění na požádání – kdykoli systemd detekuje, že někdo chce použít daný socket, automaticky nastartuje patřičnou službu. Tím jsou splněny dva předpoklady rychlého startu – spouštět služby co nejvíce paralelně a rovněž spouštět pouze ty, které jsou skutečně potřeba. Mimochodem, stejně tak funguje i launchd systému OS X, který byl, jak Lennart uznává, zdrojem inspirace pro systemd.

Stejná logika jde aplikovat i na moderní desktopové démony jako Avahi, bluetoothd a podobně, které namísto socketu komunikují přes D-BUS. Jeho obslužný démon totiž umí aktivovat služby na požádání – tedy spustit obslužného démona až v okamžiku, kdy je proveden první požadavek na jeho rozhraní. Stejně jako v případě socketů jsou dotazy řazeny do fronty a zpracovány v okamžiku, kdy obslužný démon naběhne.

Čili tento přístup umožňuje se nejenom vyhnout zbytečným explicitním závislostem, serializaci při startu – navíc implicitně dokáže spouštět služby na požádání. Slovy Lennarta:

And if that's not great, then I don't know what is great!

A pokud to není skvělé, pak už nevím, co je skvělé!

Paralelní souborové operace

link

Samotné spouštění démonů je pouze část zavádění, která neběží paralelně a kde se čeká na doběhnutí jedné úlohy po druhé. Nejčastěji jde o souborové operace jako připojování disků, jejich kontrola a kontrola kvót. Teprve po této, často zdlouhavé operaci, se pokračuje v samotném zavádění.

Stejně jako v případě socketů a D-BUS, nástroje pro vyřešení takového problému dávno existují. Jak Lennart píše ve svém blogu, tak Harald Hoyer přišel s řešením v podobě autofs. Nahradit skutečné přípojné body (mount points) systémem autofs a potom jednoduše čekat až nějaká aplikace zavolá open() na daný prostor, čímž se její běh přeruší a požadavek opět umístí do fronty, systém mezitím provede kontrolu integrity i uživatelských kvót, přípojný bod nahradí skutečným a probudí doposud zablokovanou aplikaci. Systém autofs navíc dokáže zpět propagovat chyby, pokud nemohl být daný systém z nějakého důvodu připojen. Pochopitelně takové odložené připojení nemá smysl pro kořenový adresář, nebo pseudosystémy jako procfs a sysfs.

Deklarativní popis init skriptů

link

Skriptovací init skripty jsou rychlé a pomalé zároveň. Je rychlé je napsat, ale jsou velice pomalé ke spouštění. V zásadě nezáleží na tom, zda používáme těžkotonážní /bin/bash, nebo odlehčenou alternativu, zavádění bude vždy pomalé. Lennart uvádí, že na jeho systému zavádění systému znamená 77 volání grep, 92 volání awk, 23 cut a 74 sed. Což znamená pro každý takový příkaz opakování fork/exec, nahrání dynamických knihoven, kontrolu lokalizace, parsování argumentů příkazové řádky a podobně. Navíc jsou init skripty velice křehké, citlivé na odchylky v nastaveném prostředí a podobně.

Poměrně zajímavou metrikou toho, kolik procesů muselo naběhnout jenom pro zavádění systému je nabootovat, přihlásit se a v terminálu napsat echo $$ pro zjištění PID aktuálního shellu. Lennart uvádí Linux: 1823, OS X 154.

Naštěstí velká část logiky init skriptů se opakuje, takže může být snadno reimplementovaná v C a poskytována samotným systemd. Systemd nabízí deklarativní popis init skriptu, který je snadné napsat, množství výplňového kódu a počet chyb je redukován. Navíc, nejde o nijak nový princip, (x)inetd obsahují právě takový deklarativní způsob psaní služeb. Pro případy, kdy je logika spouštění příliš složitá na deklarativní popis je možné se v něm odkázat na skript, který dané spuštění vykoná.

Jako vedlejší efekt – protože se o spuštění démona stará přímo systemd a ne nějaký shellový kód, není potřeba používat triky jako double-fork pro vyvázání se z aktuálního terminálu. Když už nic, tak procesy spuštěné systemd mají jako rodiče přímo PID 1. Dobrý démon pro systemd má pouze obslužnou smyčku, loguje do stderr a nepoužívá magii, takže v konečném důsledku vypadá více jako běžná aplikace, kterou je snadné ladit.

Ačkoli jsme už na konci našeho původního seznamu, Lennart jde ještě dál a přidává další důležitou vlastnost pro dobrý init systém.

Sledování procesů

link

Dobrý systém spouštějící služby je také musí umět sledovat. Restartovat, pokud spadnou a sesbírat užitečné informace získané z pádu, poskytnout je systému pro práci s core soubory a zapsat zprávu do systémového logu.

Také musí být schopen kompletně vypnout danou službu, což nemusí být zcela jednoduché. V unixu stačí udělat dvojitý fork a tím se dostat z dosahu kontroly rodičovského procesu, což je mimochodem přesně způsob, jak pracují démoni. Takže splašený cgi skript nemusí být ukončen prostým ukončením Apache.

Naštěstí kernel obsahuje potřebnou technologii – Control Groups, která byla do jádra přidána pro potřeby kontejnerů a nastavování limitů pro jaderné prostředky pro určité skupiny procesů, na rozdíl od tradičního setrlimit vázaného na proces. Výhodou je, že neprivilegované procesy se ze své kontrolní skupiny nemohou dostat. Tím je pro systemd velice snadné procesy kontrolovat. Pro každý proces je jeho skupina viditelná v /proc/$PID/cgroup a navíc jsou skupiny procesů dostupné v sysfs.

Ovládání prostředků

link

A v neposlední řadě, pokud už init systém dokáže procesy sledovat, mohl by umět i kontrolovat jejich prostředí. Klasické init skripty se obvykle omezují na omezení v podobě uživatele a skupiny, vzácně pak nastavují limity přes ulimit/setrlimit. Schopnosti Linuxu, jak nastavit prostředky, jsou mnohem větší – je možné nastavit plánovač procesoru nebo IO, capability bounding set, CPU affinity a podobně.

Například spouštění updatebIOPRIO_CLASS_IDLE bude mít pozitivní důsledky na interaktivitu systému, protože požadavky tohoto procesu se začnou vykonávat pouze v případě, že neexistují jiné.

Ostatní vlastnosti

link

Status update

link

S tím, jak je systemd navržen a funguje, je jasné, že existuje spousta míst, kde se jeho funkce překrývá s funkcí jiné služby. A také to, že existuje spousta nových vlastností, které nebyly v původním článku zmíněny, nebo prostě byly přidány až později, anebo byly zmíněny, ale nedokončeny. Proto vydal Lennart (zatím) dva články s názvem Status Update, kde ukazuje změny, které se v mezičase udály.

Závěrem

link

Důvodem, proč je systemd současná „hvězda“ init systémů, je fakt, že se nejedná pouze o yet another sysvinit alternative. Vlastnosti jako socket/path based aktivace služeb, kontrola prostředí a integrace se spoustou dalších technologií, supervize procesů, které systemd nabízí, jsou alespoň v linuxovém světě jedinečné.

Lennart dále uvádí, že stejně jako launchd, může systemd nahradit současné aplikace pro správu uživatelských relací, jako gnome-session nebo kdeinit. Kontrola stavu procesů, paralelní spouštění a schopnost ukládat aktuální stav a zase jej obnovit – to vše mají oba typy programů společné.

V dalším díle se podíváme systemd na zoubek o něco více.

Seriál Systemd (dílů: 7)

První díl: Systemd – úvod a představení System V init, poslední díl: Systemd – .service jednotky, náhrada init skriptů.
Předchozí díl: Systemd – úvod a představení System V init
Následující díl: Systemd – principy

Další články z této rubriky

Úvod do Dockeru (1)
Paralelizace běžných činností v konzoli pomocí GNU Parallel
Unixové nástroje – 26 (triky pro práci v Bashi)
Unixové nástroje – 25 ((s,c)fdisk, gdisk, parted a findmnt)
Linux: systémové volání splice()

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.