Dva roky ve vývoji Knot DNS

12. 3. 2012
Doba čtení: 7 minut

Sdílet

Před nějakou dobou jste si mohli tady na Root.cz přečíst dva články představující nový autoritativní server z dílny Laboratoří CZ.NIC s názvem Knot DNS. Dnes, nedlouho po vydání ostré verze 1.0.0, si přiblížíme celý proces jeho vývoje a některá důležitá rozhodnutí, ke kterým došlo v jeho průběhu.

Oťukávání

Vývoj Knot DNS začal na podzim roku 2009 řadou experimentů a testů. Srdcem každého autoritativního DNS serveru jsou datové struktury pro zónu, proto jim byla v začátcích věnována největší pozornost. Průzkum dostupných možností nám odhalil zajímavé hašovací schéma – Cuckoo hashing, které je používáno hlavně ve hardwarových vyrovnávacích pamětech. Ukázalo se jako velice vhodné pro naše potřeby, neboť zaručuje konstantní dobu vyhledání položky i v nejhorším případě. Tou dobou již začaly vznikat první řádky budoucího kódu a datová struktura založená na „Kukaččím hašování“ byla takovým pomyslným základním kamenem celého budoucího serveru.

Dále čtěte: seriál o Knot DNS na Root.cz

Kolem této (obecné) datové struktury byl vystavěn první prototyp serveru s velmi jednoduchou síťovou vrstvou, který zatím využíval knihovnu ldns pro ukládání dat specifických pro DNS. Na funkčním prototypu jsme si ověřili vhodnost zvolené datové struktury a také její potenciál pro vysokou rychlost vyhledání potřebných dat pro zodpovězení příchozího dotazu. Hlavní důraz byl kladen na modularitu návrhu, tak aby kteroukoliv část bylo možné kdykoliv nahradit lepší implementací. Tento přístup se nám osvědčil, a velká část tohoto původního návrhu byla zachována i do finální verze.

Na plný plyn

Na podzim roku 2010 přibyli do týmu další vývojáři, a tak bylo možné začít intenzivně pracovat na ostatních částech serveru. Nezávisle na sobě vznikaly jednotlivé funkční celky: síťová vrstva, obsluha vláken a datové struktury pro DNS data, které měly nahradit ldns. Tyto datové struktury byly z počátku vyvíjeny jako samostatná knihovna a také byly samostatně testovány a laděny, ale v pozdějších stádiích vývoje se ukázalo výhodnější z hlediska složitosti návrhu je zaintegrovat přímo do serveru.

Při tvorbě DNS knihovny jsme museli učinit několik klíčových rozhodnutí. Nejvýznamnějším z nich byla volba, jestli budou všechny zóny v jedné hašovací tabulce, nebo bude pro každou zónu samostatná tabulka. Nakonec jsme se rozhodli pro druhou možnost, jelikož nám to umožňuje lépe a rychleji provádět změny v zónách při jejích aktualizacích; ať už způsobené příchozím transferem, či v budoucnu dynamickými aktualizacemi. Toto rozhodnutí bohužel má i svou negativní stránku. Při práci s velkým množství zón (v řádu desetitisíců) dochází ke snížení výkonu serveru. Je to jedna z mála vlastností Knot DNS, kde jsme upřednostnili lepší funkcionalitu serveru před jeho výkonem. Na zvýšení výkonu pro použití Knot DNS v případě načtení obrovského množství zón (statisíce až milióny) budeme pracovat v dalších verzích našeho DNS serveru.

Paket sem, paket tam…

Práce na síťové části začala návrhem a především experimentováním se strategií obsluhy soketů. Pomocí jednoduché sady benchmarků byla jako nejvýkonnější varianta změřena přímá paralelizace blokujícího čtení na soketech. Při implementaci přenosů zóny vyšlo najevo, že tento přístup není příliš vhodný pro použití protokolu TCP; tento drobný zádrhel jsme vyřešili návrhem upraveného modelu, kdy každé vlákno obsluhuje vlastní množinu spojení pomocí multiplexu. Největším problémem při ověřování výkonnosti zvolených modelů byla síťová latence a nejisté chování OS Linux při zaplnění vyrovnávací paměti pro vstupně-výstupní operace na soketech. Ale i s tímto problémem jsme se nakonec úspěšně vypořádali. Síťová vrstva se začala chovat spořádaněji po úpravě velikosti vyrovnávací paměti, a to jak pro čtení, tak pro zápis.

Samotný server byl z počátku koncipován jako správce oddělených vstupně-výstupních modulů, jenže takové zobecnění se časem ukázalo jako nevhodné. Při řešení příchozího dotazu v modulu obsluhy UDP spojení je nutné zachovat přístup k některým datům modulu pro správu přenosů a naopak. Z toho důvodu byl navržen systém na bázi unixových rour, který umožňuje jak předávání požadavků mezi moduly, tak i přirozenou synchronizaci a serializaci požadavků. Protože zatím nejsou moduly odděleny do vlastních neprivilegovaných procesů, rozhodli jsme se pro větší bezpečnost využít bezpečnostních vlastností standardu POSIX 1003.1e. Vlákna v modulech se tak mohou předem vzdát přístupu k souborovému systému, vytváření soketů na privilegovaných portech a dalších možností, které pak nemůže potenciální útočník zneužit.

Já bych všechny ty transfery zrušila

Asi jako poslední z důležitých funkcí autoritativního serveru byly implementovány přenosy zón (AXFR a IXFR). Inkrementální přenosy IXFR se ukázaly být relativně náročné na možnosti datových struktur, které proto musely být pro potřeby transferů částečně upraveny. Tato úprava nás donutila se nad datovými strukturami znovu zamyslet a nakonec v některých případech vedly úpravy datových struktury naštěstí dokonce k jejich optimalizaci. Z hlediska procesu vývoje to pro nás byla důležitá lekce. Přenosy zón by bylo lepší implementovat, alespoň částečně, již v prototypu, což by nám umožnilo se vyvarovat některých chyb již na počátku vývoje.

Testování je matkou… mnoha bugů

Důležitou součástí vývoje Knot DNS bylo samozřejmě testování. Už při implementaci hašovací tabulky jsme začali s implementací unit-testů pro samostatné a detailní testování datových struktur a jejich API. Tato praxe byla dále přejata také do dalších stádií vývoje, a tak vznikaly unit-testy v podstatě průběžně s vlastní implementací jednotlivých modulů. Časem vyvstala potřeba testovat server komplexněji, jako celistvou jednotku. Pro tento účel vznikla sada nezávislých testů založených na DNS knihovně v jazyce Go, taktéž z dílny Laboratoří CZ.NIC., která má tu výhodu nezávislé implementace DNS protokolu. Snižuje se tím nebezpečí zavlečení chyby přítomné v kódu serveru i do oddělených testů. Pomocí těchto testů kontrolujeme základní funkce serveru: zejména odpovídání na různé typy dotazů, přijímání a poskytování přenosů zón.

Na nejvyšším stupni pomyslné hierarchie testů stojí sada nástrojů pro testování interakce mezi Knot DNS a dalšími DNS servery, které zajišťují důležitou interoperabilitu v heterogenním prostředí DNS. V průběhu vývoje jsme přidali navíc ještě nástroje pro testování chování serveru při přijetí poškozených, či náhodných dat a úplně nakonec vznikl i komplexní testovací framework, integrující všechny zmíněné testy. Tento framework je jednoduše rozšířitelný o další funkce a testovací scénáře, které budou časem přibývat.

Finále

Po dvou letech vývoje, na podzim roku 2011, jsme si byli dostatečně jistí poskytovanou funkcionalitou, a proto jsme představili první veřejné vydání Knot DNS (verze označená jako 0.8). Již krátce po prezentaci na RIPE 63 ve Vídni a také u nás na konferenci LinuxAlt v Brně, jsme začali dostávat první zpětnou vazbu od uživatelů, která nám v následujících měsících pomohla vylepšit Knot DNS a opravit mnohé chyby, které jsme nevychytali během předchozího vývoje. Verze 0.9, vydaná na začátku roku 2012, přinesla několik nových funkcí a oprav. Po ní jsme se intenzivně soustředili už jen na testování, hledání chyb a ladění, které nakonec vyústilo v první produkční verzi. Protože vás, své uživatele, máme rádi, byl Release Candidate zveřejněn na Valentýna a finální verze 1.0 pak byla vydána 29. února 2012.

Hlavně neusnout na vavřínech

Vydání první produkční verze samozřejmě neznamená, že by práce na Knot DNS byla hotová. V následujících měsících nás čeká mnoho práce na dalším vylepšování a optimalizaci současného kódu. Jak to tak obvykle bývá, během vývoje se nasbíraly různé nápady, drobné úkoly, a vylepšení. Ty byly doteď odsouvány na vedlejší kolej, protože se vždy našlo něco s vyšší prioritou. Těm bychom se rádi věnovali v nejbližší době.

Pomyslnou Achillovou patou Knot DNS je velké množství zón. Desítky tisíc zón dokážou serveru zavařit při startu i při odpovídání na dotazy. Neznamená to sice, že by Knot DNS nebyl s mnoha zónami použitelný, ale třeba NSD v takovém případě startuje mnohem rychleji (i když to je způsobeno hlavně tím, že má všechny zóny v jedné datové struktuře a v jednom souboru). Domníváme se však, že by se to ještě dalo vylepšit i u Knot DNS.

bitcoin_skoleni

Kromě oprav chyb a zlepšování výkonu máme v plánu také přidávat další funkce DNS protokolu, které jsme nezařadili do finálního vydání – podporu pro velké množství zón jsem již zmiňoval a mezi další plánované funkce jsme zařadili také podporu dynamických aktualizací, nebo podporu pro jiné DNS třídy než IN (např. Chaos). V hlavě máme i několik vylepšení a optimalizací – snížení paměťových nároku serveru, zrychlení odchozích inkrementálních přenosů zón, či další zrychlení samotného odpovídání na dotazy.

Tímto článkem jsme se pokusili přiblížit celý proces vývoje Knot DNS od prvních krůčků až k ostrému vydání této nové implementace autoritativního DNS serveru a od psaní článku se vracíme zpět ke svým programátorským klávesnicím. Věříme, že si Knot DNS získá mnohé spokojené uživatele, kteří přispějí k jeho další podobě testováním, nasazením v produkčním prostředí, a těšíme se také na vaše názory, či návrhy na vylepšení. 

Autor článku

Ľuboš Slovák pracuje jako programátor pro výzkum a vývoj v Laboratořích CZ.NIC, výzkumném a vývojovém centru správce české národní domény.

Marek Vavruša pracuje jako programátor pro výzkum a vývoj v Laboratořích CZ.NIC, výzkumném a vývojovém centru správce české národní domény.