Operační systémy
Obsah Soubory
markdown

Architektury-jadra.md

12 kB 148 řádků Změněno Zobrazit na GitHubu Stáhnout
markdown
# Architektury jádra: monolit, mikrojádro a co z toho vyhrálo V lednu 1992 poslal Andrew Tanenbaum do diskusní skupiny comp.os.minix příspěvek s nadpisem „LINUX is obsolete". Autor MINIXu v něm vysvětlil, že monolitické jádro je návrat do sedmdesátých let a že mikrojádra ten spor už vyhrála. Torvalds odpověděl a debata se táhla týdny. Po třiceti letech je vidět, že pravdu měl každý z nich, jen jinde. Monolit vyhrál na serverech, desktopech a v telefonech. Mikrojádro vyhrálo tam, kde pád ovladače stojí životy: v autech, v letecké technice a - což je pěkná ironie - uvnitř každého moderního procesoru Intel běží MINIX. Tahle stránka vysvětluje, čím se ty architektury liší a proč se ten rozdíl nedá zredukovat na „rychlost proti spolehlivosti". Neřeší samotnou hranici mezi režimy - to je na [jádru a uživatelském režimu](Jadro-a-uzivatelsky-rezim) - ani jeden přechod přes ni, což je [systémové volání](Systemova-volani). Bez těch dvou stránek zůstane zbytek jen názvoslovím. ## Hranice ochrany, ne architektura Uvnitř jádra sdílí veškerý kód jeden adresní prostor, běží v privilegovaném režimu a smí sáhnout na cokoli. Venku má vlastní adresní prostor a každý kontakt s okolím musí projít přes jádro. Tohle je nejdůležitější věc na celé stránce: **otázka nezní „monolit, nebo mikrojádro", ale co je uvnitř hranice ochrany.** Každý kus kódu uvnitř může položit celý stroj. Každý kus kódu venku platí za každý přechod hranice. Celý ten třicetiletý spor je o tuhle jednu směnu. ## Monolitické jádro: co všechno je uvnitř V Linuxu je uvnitř [plánovač](Planovani-procesu), [správa paměti](Sprava-pameti) i s tabulkami stránek, [souborové systémy](Souborovy-system), síťový zásobník, obsluha [přerušení](Preruseni-a-vyjimky) a ovladače všeho, co se dá k počítači připojit. Zdrojový strom má přes třicet milionů řádků a největší část zabírají právě ovladače. **Uvnitř je volání obyčejný skok.** Když síťový zásobník potřebuje paměť, zavolá funkci: jednotky nanosekund, žádné přepnutí, žádné kopírování. Odtud plyne výkon monolitu. **Cena je, že chyba nemá kam spadnout.** Ovladač, který zapíše mimo své pole, přepíše datovou strukturu plánovače. Nulový ukazatel v ovladači není výjimka procesu, ale [panika jádra](Start-systemu). ### Moduly nejsou mikrojádro Nejčastější omyl kolem architektur zní: Linux má moduly, takže je vlastně mikrojádro. **Není.** ```bashlsmod                   # zavedené moduly a kolik věcí každý z nich používámodinfo xfs             # závislosti, parametry, licence a podpis modulusudo modprobe -r xfs    # vysunutí; selže, dokud je svazek připojený``` Modul se zavádí a odebírá za běhu, ale jakmile je uvnitř, běží ve **stejném adresním prostoru se stejnými právy** jako zbytek jádra. Vidí všechny symboly, může měnit cokoli, a když spadne, položí stroj stejně jako kód přeložený napevno. **Modul je otázka zavádění, ne ochrany.** Distribuce ho používá proto, aby jedno jádro nabootovalo na tisících různých strojů. S izolací nemá nic společného. Rada „přelož si ovladače napevno kvůli výkonu" je zbytek doby, kdy zavádění modulů něco stálo. Po zavedení je to tentýž kód se stejnými právy. ## Mikrojádro: co zůstane, když zbytek vystrčíš ven V jádře zůstane jen to, co bez privilegovaného režimu nejde: plánování, správa adresních prostorů a předávání zpráv. Zbytek - ovladače, souborové systémy, síť - jsou běžné procesy s vlastní pamětí. Ovladač disku, který sáhne mimo, dostane od jádra chybu, umře jako kterýkoli jiný proces a dozorčí proces ho restartuje. Systém běží dál. **Cena je IPC.** Operace, která byla v monolitu skokem, je teď [meziprocesová komunikace](Meziprocesova-komunikace): přechod do jádra, předání zprávy, [přepnutí kontextu](Prepinani-kontextu) na obslužný proces a totéž zpátky. Jedno čtení ze souboru překročí hranici čtyřikrát místo jednou a jeden přechod stojí zhruba 50-100 ns, s mitigacemi Spectre a Meltdown i pětinásobek. Ten argument byl v roce 1992 silnější než dnes: L4 z roku 1993 srazilo cenu zprávy o řád a ukázalo, že pomalý byl Mach, ne myšlenka. ### Kde mikrojádro doopravdy vyhrálo **QNX** - infotainment a přístrojové štíty v autech, průmyslové řízení, zdravotnická technika. Certifikace podle norem funkční bezpečnosti se na malé důvěryhodné bázi dělá řádově snáz. **seL4** - mikrojádro o zhruba deseti tisících řádcích C se strojově ověřeným důkazem, že implementace odpovídá své specifikaci. Není to důkaz, že postavený systém je bezpečný - jen že jádro dělá právě to, co je ve specifikaci. **MINIX 3** - od generace Skylake (2015) běží varianta MINIXu 3 uvnitř Intel Management Engine, tedy na samostatném procesoru v čipsetu prakticky každého moderního Intelu. O tom jádru přitom skoro nikdo neví a nikdo nad ním nemá kontrolu. ## Hybridy: Windows NT a XNU Windows NT navrhl Dave Cutler jako vrstvený systém s mikrojádrovými rysy: podsystémy prostředí v uživatelském režimu a jasně vymezené vrstvy uvnitř. XNU v macOS je doslova složenina - jádro odvozené z Machu pro správu paměti a zprávy, nad ním BSD vrstva pro procesy, souborové systémy a sokety. **Obojí si vzalo z mikrojádra strukturu a z monolitu adresní prostor.** Komponenty jsou oddělené rozhraními, ale běží vedle sebe se stejnými právy. BSD vrstva v XNU s Machem nemluví zprávami, volá funkce. ### Proč grafika skončila v jádře i tam NT 4.0 v roce 1996 přesunul grafický podsystém a správce oken z uživatelského procesu dovnitř jádra, do `win32k.sys`. Důvod byl jediný: každé vykreslení znamenalo přechody hranice a na tehdejším hardwaru to bylo vidět. Windows tím získalo rychlost a jednu z nejplodnějších oblastí zranitelností ve své historii - chyba v kreslení fontu je najednou chyba v ringu 0. macOS jde dnes opačným směrem a od verze 10.15 (2019) tlačí ovladače ven přes DriverKit. **Kdykoli se ale výkon a izolace potkají na horké cestě, vyhraje výkon.** ## Tři architektury vedle sebe | Vlastnost | Monolit | Mikrojádro | Hybrid ||---|---|---|---|| Volání mezi částmi | skok, jednotky ns | zpráva, stovky ns až µs | podle vrstvy || Pád ovladače | položí stroj | restart služby, běží dál | většinou položí stroj || Důvěryhodná báze | miliony řádků | tisíce až desítky tisíc | miliony řádků || Ladění | výpis z paniky | debugger na proces | výpis z paniky || Kde běží | **Linux, BSD, Android** | **QNX, seL4, Intel ME** | **Windows NT, macOS** | Z toho plyne, co se v praxi děje: **rozhoduje se podle toho, co stojí selhání, ne podle toho, co stojí volání.** Na serveru je pád stroje nepříjemnost, v řídicí jednotce brzd jiná kategorie problému. ## Exokernel a unikernel: jedna aplikace, jedno jádro Exokernel z devadesátých let posunul myšlenku opačným směrem: jádro jen bezpečně rozděluje hardware a veškerou abstrakci si aplikace linkuje jako knihovnu. Unikernel je jeho praktický potomek - aplikace a knihovní systém se přeloží do jednoho obrazu, který běží v jediném adresním prostoru přímo nad hypervizorem. Obraz má jednotky megabajtů, startuje v desítkách milisekund a systémová volání nestojí nic, protože žádná hranice není. **Pro tvůj server to není.** Nemáš shell, nemáš `ps`, nemáš druhý proces, kterým bys to opravil, a chyba v aplikaci má rovnou přístup ke všemu. Smysl to dává na specializované virtuální stroje s tisíci jednoúčelových instancí. Všechno ostatní se dělá [kontejnery](Virtualizace-a-kontejnery). ## Kam se to posunulo v praxi Linux je monolit a zůstane jím. Přesto z něj systematicky tlačí věci ven. **FUSE** - souborový systém jako obyčejný proces, v jádře od roku 2005. Tak fungují sshfs i ntfs-3g. Cena je několik přechodů hranice na operaci, výhoda je, že chyba v cizím formátu neshodí stroj. Detaily jsou u [VFS a montování](VFS-a-montovani). **Ovladače v uživatelském prostoru** - SPDK a DPDK obcházejí jádro úplně. Rozhraní `vfio` s pomocí IOMMU předá zařízení procesu, ten si ho ovládá sám a data putují bez jediného systémového volání. Vyplatí se to při milionech paketů za vteřinu, kdy je cena přechodů hlavní položkou rozpočtu. Víc u [vstupu a výstupu](Vstup-a-vystup). ### eBPF: cizí kód v jádře, který smí projít jen ověřovatelem eBPF je nejzajímavější odpověď na celý ten spor. Nahraješ do jádra vlastní program, ale ověřovatel před spuštěním dokáže, že skončí, že nesahá mimo povolenou paměť a že volá jen povolené funkce. ```bashsudo bpftool prog show    # jaké programy právě běží v jádře a odkud se tam vzaly``` Ochranu tady nedělá hranice adresního prostoru, ale **statická kontrola před spuštěním**. Potkáš to v [nástrojích a diagnostice](Nastroje-a-diagnostika), aniž bys tušil, že řešíš architekturu jádra. **Je to konvergence, ne kapitulace.** Monolit si bere z mikrojádra izolaci tam, kde se vyplatí, a mikrojádrové systémy si berou z monolitu rychlé cesty. Ani jedna strana necouvla, obě jen přestaly platit plnou cenu. ## Jeden ovladač, 8,5 milionu strojů 19. července 2024 vydal CrowdStrike aktualizaci datového souboru pro svůj bezpečnostní senzor. Ten soubor nebyl program, ale zpracovával ho ovladač běžící v jádře Windows a ten na něm spadl. Následovala modrá obrazovka při každém startu, zhruba 8,5 milionu strojů, zrušené lety a stojící nemocnice. **Poučení je přesně to, o čem je celá tahle stránka: kód uvnitř hranice nemá kam spadnout.** Kdyby tatáž chyba potkala proces v uživatelském prostoru, restartoval by se. Podrobnosti patří na [jádro a uživatelský režim](Jadro-a-uzivatelsky-rezim). ## Kde ta volba přestává být tvoje Architekturu jádra si nevybíráš. Vybírá ji hardware a to, kde existuje ovladač. **Ovladač napíšeš tam, kde ho podporuje výrobce čipu, a to je v praxi jádro.** Dokumentace, vzorový kód i rozhraní míří dovnitř. Uživatelský prostor je varianta jen u úzké skupiny zařízení. **Na serveru volba neexistuje.** Provozuješ Linux nebo Windows, oba jsou monolit s moduly. Ovlivníš jediné: kolik cizího kódu do jádra pustíš. **Vybírat si smíš u vestavěných zařízení.** Řídicí jednotka v autě, zdravotnický přístroj, průmyslový kontrolér - tam se QNX nebo seL4 vyplatí, protože se počítá cena selhání, ne cena volání. ## Co si odnést **Rozhoduje hranice ochrany, ne jméno architektury.** Uvnitř je všechno rychlé a smrtelné, venku pomalejší a restartovatelné. **Modul není mikrojádro.** `lsmod` ukazuje kód se stejnými právy jako zbytek jádra, jen zavedený za běhu. **Monolit vyhrál tam, kde se počítá propustnost, mikrojádro tam, kde se počítá selhání.** Dvě správné odpovědi na dvě různé otázky. **IPC je celá cena mikrojádra** a od L4 je řádově nižší, než jak se ten argument pořád opakuje. **Hybridy jsou monolity se strukturou.** Oddělené komponenty, jeden adresní prostor, jedna panika. **Linux tlačí věci ven a monolitem být nepřestává.** FUSE, `vfio`, eBPF - konvergence, ne kapitulace. ## Kam dál - **[Jádro a uživatelský režim](Jadro-a-uzivatelsky-rezim)** - ta hranice, o kterou tu celou dobu jde- **[Systémová volání](Systemova-volani)** - jak přechod přes hranici vypadá zevnitř- **[Meziprocesová komunikace](Meziprocesova-komunikace)** - mechanismy, na kterých mikrojádro stojí- **[Vstup a výstup](Vstup-a-vystup)** - kde ovladače v obou světech doopravdy sedí- **[Virtualizace a kontejnery](Virtualizace-a-kontejnery)** - druhý způsob, jak izolovat- **[Start systému](Start-systemu)** - co znamená panika jádra při startu