Blog ·
Een timeout is geen stopknop
Een deadline beëindigt je wachten, niet het werk. Wat een grens van een uur doet met een lange backup, en hoe je een uitkomst vastlegt die niemand kent.
Door Provibr
Elk commando op afstand heeft een deadline nodig. Daarover bestaat geen discussie: een proces dat eeuwig kan wachten gaat op een dag eeuwig wachten, en één vastgelopen verzoek houdt een worker, een verbinding en een rij in je wachtrij bezet tot iemand iets herstart.
Veel minder vanzelfsprekend is wat die deadline werkelijk doet. Hij beëindigt het wachten aan je kant. Hij beëindigt, in het algemene geval, het werk aan de andere kant niet. Alles wat moeilijk is aan langlopende bewerkingen zit in dat gat.
Wij draaien een agent op de hypervisors van klanten en sturen die commando's. Een backup van een virtuele machine is het commando dat ons dat gat serieus deed nemen, want een backup kan eerlijk gezegd een uur duren, en een uur is precies waar onze eigen grenzen liggen.
De grens is geen voorkeur
Onze agent klemt elke commando-deadline op één uur. Het platform mag om meer vragen; het krijgt het niet. Die klem is één enkele min() op de waarde die in het verzoek binnenkomt, met nul als "niet ingesteld" en een val-terug van twee minuten als het veld ontbreekt.
Die klem heeft een gevolg dat mensen missen wanneer ze timeouts in een configuratiebestand zetten. Gelooft het platform in een deadline waar de agent niet in gelooft, dan heb je twee systemen die het oneens zijn over wanneer een commando dood is, en die onenigheid komt naar boven als het slechtst denkbare symptoom: de agent geeft op, rapporteert en gaat verder, terwijl het platform de rij nog openhoudt en wacht op een antwoord dat nooit zal komen in de vorm die het verwacht.
De regel waar we op uitkwamen is saai en toch het opschrijven waard. Elke timeout aan de platformkant wordt gekozen met het plafond van de agent in de kamer. Onze deadlines voor backup en terugzetten staan op precies één uur omdat dat het plafond is, en van enkele tientallen commando-deadlines zijn zij de enige twee die het raken.
Deadlines zijn geen kwestie van smaak
Zo zien onze commando-deadlines er werkelijk uit, en dit is waarom elk getal is wat het is.
| Commando | Deadline | Waarom dat getal |
|---|---|---|
| Hardware lezen, firewallregels lezen | 30 s | Eén leesactie. Duurt het langer, dan is er iets anders stuk. |
| Firewallregels schrijven | 120 s | Eén API-aanroep per regel, in beide richtingen, bij het maximum aantal regels. |
| Herstelpunten opsommen | 60 s | Eén aanroep per backupopslag op de node, en een mapopslag met duizenden archieven leest zijn eigen index van schijf. |
| Zelfupdate van de agent | 300 s | Downloaden, hashen, wegschrijven. Ruim bemeten voor een trage lijn bij de klant. |
| Een backup maken | 3600 s | Het plafond van de agent. |
| Een backup terugzetten | 3600 s | Hetzelfde plafond, eerder geraakt: terugzetten verplaatst ruwweg twee keer zoveel bytes als de backup verplaatste. |
| Een verse cloudmachine klaarmaken | 1200 s | Pakketupdates op een image dat weken oud kan zijn, en daarna de installatie. |
| Een paneelmigratie draaien | 1800 s | Twee panelen volledig uitgelezen, weggeschreven en nageteld. |
Twee van die rijen zijn eerder een verhaal dan een getal.
Die van de cloudmachine viel vroeger terug op de standaard van twee minuten. Twee minuten is genoeg voor een image dat toevallig actueel is en te weinig voor al het andere, dus meldde het platform een mislukking terwijl de installatie binnen in de machine gewoon doorliep en een paar minuten later klaar was. De bestelling werd als mislukt gemarkeerd. De machine draaide. Dat is de ergste soort onjuistheid: geen fout maar een tegenspraak, en de klant is degene die hem moet oplossen.
Die van de migratie is de langste deadline die niet de bovengrens van de agent is, en de redenering erachter is een telling en geen gevoel. De migrator doet één API-aanroep per gebruiker en één per server tegen het doelpaneel. Bij duizend servers zijn dat duizend aanroepen heen en duizend antwoorden terug, met een volledige leesactie van beide kanten ervoor en een natelling erna.
De kosten van een misser zijn niet symmetrisch
Dit is het beginsel onder beide verhalen. Een deadline die te kort is en een deadline die te lang is falen op volstrekt verschillende manieren, en wie ze behandelt als twee kanten van dezelfde knop krijgt elke keer het verkeerde getal.
Te lang: een bewerking die werkelijk gestorven is houdt een rij nog wat langer open. Iemand wacht. Er raakt niets beschadigd, er ontstaat niets dubbel, en het opruimen achteraf is een non-gebeurtenis.
Te kort: je legt een mislukking vast voor werk dat geslaagd is. Nu spreken je administratie en de werkelijkheid elkaar tegen, en elk herstelpad dat je hebt (opnieuw proberen, opnieuw aanmaken, terugbetalen, alarmeren) richt zich op een probleem dat niet bestaat en maakt er een tweede bij.
Die twee zijn niet even erg, dus horen ze geen even grote marge te krijgen. Voor alles wat echte resources aanmaakt, verplaatst of verwijdert kiezen wij bewust de ruime kant, en schrijven we op waarom.
Twee klokken die op verschillende momenten beginnen
In elk systeem met een commandowachtrij zit een subtiliteit die makkelijk te missen en makkelijk te meten is. Ons platform berekent de deadline als een absoluut moment, op het ogenblik dat de commandorij wordt weggeschreven. De agent berekent zijn deadline als een tijdsduur, die begint zodra hij aan de uitvoering begint.
Dat zijn verschillende klokken. Is de agent offline, of bezet, of blijft het commando dertig seconden in de wachtrij liggen, dan heeft het platform al dertig seconden van zijn budget uitgegeven en de agent niet. Het platform geeft als eerste op.
Dat is de goede volgorde, en het is de moeite waard om hardop te zeggen waarom. De deadline van het platform beantwoordt de vraag die de klant werkelijk stelt: hoe lang is het geleden dat ik klikte? Die van de agent beantwoordt een andere: hoe lang mag dit stuk werk draaien? De kloktijd vanaf de klik is het getal waar een supportgesprek over gaat. Er één getal van maken zou netter zijn en zou de verkeerde vraag beantwoorden.
Er zit ook nog een derde klok verstopt. Bij onze agent gebeurt het wachten op een plaats binnen de gelijktijdigheidslimiet buiten de uitvoeringsdeadline om. Een commando dat in de rij staat achter een ander commando tegen dezelfde integratie verbruikt tijdens dat wachten zijn eigen budget niet. Zitten je deadlines krap, controleer dan welke van je klokken het wachten in de rij meetelt; het antwoord is zelden dat uit de documentatie.
Wat de deadline werkelijk afbreekt
Wanneer de deadline van de agent verloopt, geeft hij een annuleringssignaal en stopt hij met wachten. Wat die annulering bereikt is je eigen code: de pollus die aan de hypervisor vroeg hoe het met de taak ging.
Hij bereikt de hypervisor niet. De backup loopt door. Hij zal klaar zijn, of hij zal mislukken, volledig zonder ons. Van dat afbreken is niets doorgereisd naar de opslagarray.
Dit is geen beperking die je weg moet ontwerpen. Het is de eerlijke vorm van het probleem, en de nuttige zet is de uitkomst waarheidsgetrouw vastleggen in plaats van te doen alsof. De indeling die het contact met productie overleefde kent drie uitkomsten en geen twee.
- Mislukt. We weten dat er niets gebeurd is. De klant kan het opnieuw proberen, en er valt niets op te ruimen.
- Onbekend. We zijn gestopt met luisteren voordat er een antwoord was. Er kan iets bestaan.
- Moet nagelopen worden. We hebben positieve reden om te denken dat er iets bestaat dat we niet kunnen verantwoorden.
Een terugzetactie die verloopt is het scherpste geval. Er kan nu een machine draaien op de hypervisor waar onze database geen rij voor heeft. Die als mislukt markeren zou een leugen zijn die een machine verbergt; hem als geslaagd markeren zou een leugen zijn die er een verzint. Hij wordt gemarkeerd als iets dat bekeken moet worden, en het paneel vraagt de klant te gaan kijken in plaats van een knop aan te bieden die een tweede machine naast de eerste zou bouwen.
Die regel staat in de code als een lijst van de zekere gevallen, niet van de onzekere. Vier specifieke foutcodes betekenen dat het werk nooit begonnen is, want alle vier komen uit controles die de agent uitvoert voordat hij zijn eerste aanroep doet. Al het andere, inclusief elke foutcode die we later toevoegen en vergeten in te delen, valt standaard onder onzeker. De richting doet ertoe: een vergeten code die stil als mislukt wordt geboekt laat een bestaande machine uit de administratie verdwijnen, en een vergeten code die als onzeker wordt geboekt kost iemand alleen een blik.
Een onzekere uitkomst heeft een weg naar zekerheid nodig
Een status die "iemand moet dit nakijken" betekent is alleen eerlijk als iemand, of iets, het werkelijk nakijkt. De onze is een worker die periodiek aan elke machine met backuphistorie vraagt om zijn herstelpunten opnieuw op te sommen, zodat een archief dat stilletjes verdween bij de aanbieder een melding wordt in plaats van een lijst die korter werd op de dag dat een klant toevallig keek.
Op die lus zit een bewuste zuinigheidseis, want elke opsomming is een commando dat draait op de host van iemand anders. Hij bezoekt alleen machines met een beleid of met minstens één bekend herstelpunt, en hij neemt per ronde een begrensde portie. Zodra dat niet meer volstaat is de juiste oplossing een cursor, geen groter getal.
De lus moet er bovendien tegen kunnen dat twee van je eigen servers besluiten hem op dezelfde seconde te draaien. Dat doen we met een duurzame idempotentiesleutel die bestaat uit de machine en het vensternummer, niet uit een tijdstempel: twee servers tikken nooit op dezelfde milliseconde, maar ze zitten met zekerheid binnen hetzelfde venster van zes uur, dus een tijdstempel zou niets ontdubbelen.
Wat wij je zouden aanraden op te schrijven
Kies je deadlines voor werk op afstand, dan brengen vier vragen je een heel eind.
- Wat is het harde plafond, en wie handhaaft het? Zijn twee onderdelen het oneens, dan wint in de praktijk de kleinste en is de grootste fictie.
- Wanneer begint elke klok? De wachttijd in de rij zit in het budget of niet, en beide antwoorden zijn te verdedigen. Het niet weten niet.
- Wat breekt het verlopen af? Is het antwoord "ons eigen wachten", zeg dat dan hardop, want de rest van het ontwerp volgt eruit.
- Aan welke kant valt een niet-ingedeelde uitkomst? Maak onzekerheid de standaard, en laat zekerheid het ding zijn dat je moet opschrijven.
Niets hiervan maakt een lange backup korter. Het maakt de administratie ervan waar, en dat is het deel dat je om twee uur 's nachts zit te lezen.