Learning
Všechny články
Engineering17. srpna 2026 6 min

Nudná technologie přestává být nudná mimo hlavní cestu

SQLite šestnáct let neztratilo zápis, dokud ho někdo nepoužil jinak

Volba nudné technologie tě chrání jen na vyšlapané cestě

SQLite je učebnicový příklad nudné technologie. Statisíce testů, miliardy instalací, dekády v produkci. Přesto v něm Tailscale za šest měsíců napočítalo devatenáct případů poškozené databáze. Chyba v SQLite ležela nedotčená zhruba šestnáct let. Nešlo o to, že by SQLite bylo nespolehlivé — šlo o to, že Tailscale ho používalo způsobem, kterým ho nepoužívá skoro nikdo jiný.

Spolehlivost softwaru není vlastnost knihovny. Je to vlastnost kombinace knihovny a způsobu použití. A ta kombinace nemá odpracované miliardy hodin, i když ta knihovna ano.


Kde přesně vznikl závod

SQLite v režimu WAL nezapisuje změny rovnou do hlavního souboru databáze. Nové stránky nejdřív přistanou ve write-ahead logu, což umožní číst souběžně se zápisem. Jenže do WALu nemůžou přibývat donekonečna. Periodicky proto běží checkpoint: proces, který stránky z WALu překopíruje zpátky do hlavního souboru.

Většina aplikací nechá checkpointování na SQLite samotném. Tailscale to dělá jinak. V control plane má každý shard vlastní SQLite databázi, ke které exkluzivně přistupuje jeden Go proces, a checkpoint si řídí ručně — aby mohl dělat časté a konzistentní zálohy do S3. Ručně a hlavně velmi agresivně.

Tím se rozšířilo okno pro chybu, která do té doby prakticky nemohla nastat. Když zápis přijde v přesně určený okamžik během checkpointu, checkpointovací proces se splete: myslí si, že některé stránky už z WALu do hlavního souboru přetekly, jenže nepřetekly. Ty stránky se do souboru nikdy nedostanou a data jsou nenávratně pryč. Bez chyby, bez varování.


Jak se to vůbec dalo najít

Symptomy byly bezradné. Žádná změna v kódu tomu neodpovídala, problém se nedržel jednoho shardu, zákazníka ani funkce. To, co ukázalo směr, byl vlastní záchranný mechanismus: Tailscale loguje transakce, aby je mohl přehrát. V těch logách bylo vidět, že data zapsaná a commitnutá jednou transakcí byla pro pozdější transakce neviditelná. Zápis zmizel bez chybové hlášky.

Zbytek dohledali autoři SQLite pomocí tmstmpvfs — shimu, který obalí vrstvu virtuálního filesystému a nechá vidět, co checkpoint reálně dělá se soubory. Tam bylo vidět, že SQLite hlásí zkopírování většího počtu stránek, než kolik jich ve WALu vůbec bylo. Oprava pak přidala do checkpointovací funkce kontrolu, jestli WAL mezitím neresetovalo jiné vlákno, a vyšla v SQLite 3.51.3.

Tailscale ale udělal ještě jednu věc, která stojí za zkopírování: i po opravě nechal v kódu instrumentaci, která hlásí, kdykoli se zápisová transakce a WAL-reset překryjí. Dva měsíce po nasazení se alert konečně ozval. Ne jako incident — jako potvrzení, že závod v produkci reálně nastává a že ho oprava chytá.


Jak si spočítat vlastní expozici

Z toho plyne praktické měřítko. Riziko není úměrné jen tomu, jak zralá je knihovna, ale součinu dvou věcí: jak neobvyklý je tvůj způsob použití a jak často ho provádíš. Tailscale nedělalo nic nezdokumentovaného ani nepodporovaného. Dělalo jen podporovanou věc mnohem častěji než kdokoli jiný, a tím se posunulo do oblasti, kterou provoz ostatních uživatelů nikdy neprošlapal.

Praktický důsledek: u každé závislosti si všimni, kde se tvoje použití liší od defaultu. Ruční řízení něčeho, co si knihovna normálně řídí sama. Frekvence o řád vyšší než u ostatních. Vypnutá ochrana, kterou máš nahrazenou vlastní. Přesně tam neplatí, že to za tebe už někdo odladil.


Co si z toho odnést

Nudná technologie je dobrá volba, ale ta nudnost se vztahuje na hlavní cestu, ne na tebe. Jakmile z ní sejdeš — ruční checkpoint, netypická frekvence, vlastní správa něčeho automatického — vracíš se do neprošlapaného terénu a zralost projektu ti přestává platit jako záruka.

Nejcennější detail celého příběhu není oprava, ale ta instrumentace ponechaná po ní. Když víš, že tvoje použití je netypické, vyplatí se přímo měřit, jestli k nebezpečné kombinaci dochází — ne čekat, až se ozve poškozená databáze. A zápis, který zmizí bez chyby, ti odhalí jedině nezávislý log, se kterým můžeš stav rekonstruovat.

Zdroje

Poslech místo čtení — 2 zdroje k načtení.