Sofatid Til forsiden

Under panseret

Slik er Sofatid bygget

Ingen servere å skalere, ingen pods og ingen autoskalerer. Her er hvordan Cloudflare Workers fungerer, hva som skjer når trafikken plutselig øker, og hvor flaskehalsene egentlig er – med Sofatid som eksempel.

Sofatid er en app for å holde styr på filmer og serier, se hvor de strømmes i Norge og få tips fra venner. Den kan få mange brukere på kort tid – en video på TikTok er nok. Spørsmålet er da: hva skjer når tusen personer prøver appen samme kveld? Svaret krever at man forstår hvordan plattformen den kjører på, er bygget opp.

1. Den vanlige måten: servere og pods

En tradisjonell nettjeneste kjører på en server – en maskin, ofte leid i skyen, som står i ett datasenter, for eksempel i Frankfurt. Programmet starter, blir liggende og venter på forespørsler hele døgnet, og man betaler for maskinen også når ingen bruker den.

Når én server ikke er nok, pakkes programmet i en container: en ferdig pakke med programmet og alt det trenger. Mange like containere kjøres side om side, styrt av et system som Kubernetes. Én kjørende container (eller en liten gruppe av dem) kalles en pod. En autoskalerer følger med på belastningen og starter flere pods når det blir travelt, og stopper noen når det roer seg.

Modellen fungerer, men har noen kjente ulemper:

  • Det tar tid å starte en pod – fra noen sekunder til et halvt minutt. Kommer trafikken brått, henger systemet etter, og de første brukerne får det tregt.
  • Autoskaleringen må stilles inn: minst og høyst antall pods, og når nye skal startes. Feil innstilling gir enten høy regning eller treg app.
  • Alt står ett sted. En bruker i Tromsø snakker med en maskin i Frankfurt, og hver tur fram og tilbake tar tid.
  • Man betaler for tomgang: pods som venter på trafikk, koster penger.

2. Cloudflares måte: koden ligger overalt

Cloudflare har datasentre i over 300 byer, også i Oslo. Når Sofatid rulles ut, lastes koden opp til alle datasentrene på noen sekunder. Når noen åpner appen, havner forespørselen i datasenteret nærmest dem – for de fleste nordmenn Oslo, iblant Stockholm eller København – og koden kjøres der. Det kalles å kjøre på kanten (edge): nær brukeren, ikke i ett stort datasenter langt unna.

Det finnes ingen server prosjektet eier, og ingen pods å styre. Derfor kalles det serverless. Serverne finnes selvfølgelig, men de er Cloudflares ansvar.

Pods i ett datasenter, sammenlignet med isolater i mange datasentre Til venstre ett datasenter med tre pods og en ny pod som bruker sekunder på å starte. Til høyre fire byer med Cloudflare-datasentre, der hver har et Sofatid-isolat ved siden av isolater fra andre kunder. Tradisjonelt: pods Ett datasenter (f.eks. Frankfurt) Pod Pod Pod Ny pod ved mye trafikk starter på sekunder – brukerne venter Alle brukere, uansett hvor de er, går hit. Cloudflare Workers: isolater Oslo Sofatid annen annen annen Stockholm Sofatid annen annen København Sofatid annen … 300+ byer ved bruk annen Koden ligger overalt. Isolater starter på millisekunder, der brukerne er – og bare når de trengs.
Til venstre: én plassering, og nye pods tar sekunder å starte. Til høyre: koden ligger i alle Cloudflares datasentre, og hvert datasenter kjører isolater fra mange kunder side om side.

3. Isolater i stedet for pods

Hjertet i Workers heter et isolat (V8 isolate). V8 er JavaScript-motoren i Chrome. Når man har ti faner åpne, kjører hver fane sin JavaScript helt adskilt fra de andre – én nettside kan ikke se hva en annen gjør. Hver slik avlukket sone er et isolat.

Cloudflare bruker samme teknikk på serverne sine. På én maskin i Oslo kjører én stor prosess, og inni den ligger tusenvis av isolater med kode fra ulike kunder – ett for Sofatid, ett for en nettbutikk og så videre – skjermet fra hverandre akkurat som fanene i en nettleser.

Det gir tre store fordeler sammenlignet med pods:

  • Et isolat starter på noen få millisekunder. En pod bruker sekunder – hundrevis til tusenvis av ganger lenger. Cloudflare starter ofte isolatet mens nettleseren og serveren fortsatt forhandler om krypteringen, så brukeren merker ingenting.
  • Et isolat er lite. Det deler motoren og mye annet med de andre isolatene i samme prosess, så hver kunde koster lite ekstra minne.
  • Ingen tomgang. Bruker ingen Sofatid i Sydney, finnes det ikke noe Sofatid-isolat der. Kommer det en forespørsel, startes et på millisekunder.

Kald start

Når et isolat må startes fordi det ikke allerede kjører, kalles det en kald start. I pod-verdenen er dette et velkjent problem fordi det tar sekunder. I Workers tar det millisekunder og spiller nesten ingen rolle. Når appen er i jevnlig bruk, er isolatet i Oslo som regel allerede «varmt».

4. Hva skjer når mange bruker appen samtidig?

Ett isolat håndterer mange forespørsler samtidig. JavaScript gjør én ting om gangen, men nesten all tid i en typisk forespørsel går med til å vente: på databasen, på filmdatabasen TMDB, på OMDb. Mens én forespørsel venter, tar isolatet seg av en annen. Et typisk kall i Sofatid bruker noen få millisekunder ren regnetid (CPU); resten er venting.

Ett isolat med tre forespørsler samtidig Tidslinje for tre forespørsler. Hver har korte røde blokker med regnetid og lange prikkede strekninger der den venter på databasen eller en ekstern tjeneste. Regnetiden til de tre overlapper ikke, så ett isolat rekker alle. Ett isolat, tre forespørsler Rødt = regnetid (CPU). Prikket = venter på database eller tjeneste. Søk Min liste Tittel tid →
Regnetiden er kort og overlapper ikke. Ett isolat rekker derfor mange forespørsler samtidig, fordi det jobber med én mens de andre venter.

Blir det for mye for ett isolat, starter Cloudflare flere. Det skjer automatisk – på samme maskin, på andre maskiner i datasenteret og i andre datasentre. Det finnes ingen innstilling for antall instanser og ingen autoskalerer å konfigurere. Trafikken fordeles også naturlig, fordi brukere i Bergen, Oslo og Trondheim kan treffe ulike datasentre.

Det tar ikke tid å skalere opp. Nye isolater starter på millisekunder, så en brå bølge tas imot uten oppvarmingstid. Dette er den største praktiske forskjellen fra pods.

Man betaler per bruk. Workers Paid koster 5 dollar i måneden og inkluderer 10 millioner forespørsler og 30 millioner millisekunder CPU-tid. Over det koster det rundt 30 cent per million forespørsler ekstra. Sofatid bruker i dag noen få prosent av det inkluderte.

5. Minne: hva husker et isolat?

Hvert isolat har inntil 128 MB minne. Det høres lite ut, men er mye for et program som stort sett henter og videresender data.

Det viktige: et isolat kan huske ting mellom forespørsler, men man kan ikke stole på det. Isolatet kan bli stoppet når som helst, og to brukere kan treffe hvert sitt isolat med hver sin kopi av minnet.

Sofatid bruker minnet bevisst som en snarvei, aldri som lager:

  • Søkeforslag: titteloversikten er delt i biter etter de første bokstavene (for eksempel alle titler med et ord som begynner på «ben»). En bit som nettopp er lest, holdes ferdig tolket i minnet i 30 minutter, så neste søk på «benj» i samme isolat slipper å lese den på nytt.
  • Rangering: hvilke titler som ligger i brukernes lister, og hvilke som er norske produksjoner, hentes fra databasen høyst hver halvtime per isolat.

Finnes det ikke i minnet, hentes det på vanlig måte. Innlogging lagres derimot ikke i minnet: da kunne en bruker vært logget ut i ett isolat og fortsatt innlogget i et annet.

Workers har også en grense for CPU-tid per forespørsel (30 sekunder ren regnetid som standard på betalt plan – venting teller ikke) og for antall kall ut mot andre tjenester per forespørsel. Sofatid er langt unna begge. Det tyngste appen gjør, er bildeanalyse med Claude, og det er nesten bare venting.

6. Der flaskehalsene faktisk er

Når selve koden skalerer nesten ubegrenset, flytter problemene seg til det koden snakker med.

Veien en forespørsel tar En telefon sender forespørselen til Cloudflare i Oslo. Der kjører Sofatid-isolatet med minnet sitt, og ved siden av ligger Cache API og KV i samme datasenter. Fra Oslo går kall videre til databasen D1 i Stockholm, og til eksterne tjenester: TMDB, OMDb, Claude og Resend. Telefon i Norge ~20 ms Cloudflare-datasenter i Oslo Sofatid-isolat koden + minne (snarveier) skalerer av seg selv Cache API svar fra TMDB, forslag, plakater ingen skrivegrense KV IMDb-score, søk, bilder mye lesing D1 (database) i Stockholm-regionen brukere, lister, venner én spørring om gangen Utenfor Cloudflare TMDB, OMDb Claude (bilder) Resend (e-post) egne grenser Grønt ligger i samme datasenter som koden. Rødt og hvitt er der flaskehalsene kan oppstå.
Workeren og de lokale lagrene (grønt) skalerer med trafikken. Databasen har ett hjem, og eksterne tjenester har egne grenser – det er der man må være nøye.

D1, databasen

Brukere, lister, venner og varsler ligger i D1, Cloudflares database bygget på SQLite. Den fungerer annerledes enn koden:

  • Den ligger ett sted. Koden kjører i Oslo, men databasen har et fast hjem – for Sofatid i Stockholm-regionen. Hvert databasekall er en kort tur dit, typisk noen titalls millisekunder.
  • Den behandler én spørring om gangen. Tar en spørring 1 millisekund, klarer databasen rundt 1 000 i sekundet. Tar den 10 millisekunder, er det 100 i sekundet. Dette er den viktigste begrensningen i hele oppsettet.

Regnestykket for Sofatid: selv med 5 000 brukere er bare en liten del aktive samtidig, og hver forespørsel gjør typisk noen få raske spørringer. Det er godt innenfor det D1 tåler – så lenge spørringene er raske. Derfor har databasen indekser der det trengs, spørringene leser ikke mer enn nødvendig, og søkeforslagene spør ikke databasen for hvert tastetrykk. Titteloversikten ligger i KV og i minnet, og bare plakatene hentes fra D1, med et mellomlager foran.

Skulle databasen en dag bli for treg, finnes det løsninger, som lesekopier i flere regioner og mer i cache. Det er langt fram.

KV, nøkkel–verdi-lageret

KV er et enkelt lager: en nøkkel og en verdi. Sofatid bruker det til IMDb-scorer (fra IMDbs datasett, oppdatert hver natt), titteloversikten for søk, profilbilder og miniatyrbilder.

KV er laget for mye lesing og lite skriving. Lesing er rask, fordi verdiene caches i datasenteret nær brukeren. Skriving sprer seg sakte – det kan ta opptil et minutt før en endring er synlig overalt. Det kalles eventual consistency («blir riktig etter hvert»). Det passer for data som oppdateres én gang i døgnet, men ikke for noe brukeren nettopp har endret. Lister og innstillinger ligger derfor i D1.

Cache API

Et mellomlager i hvert datasenter for svar som tar tid å lage: detaljer fra TMDB, søkeforslag og plakater. Det er gratis og har ingen skrivegrense, men hvert datasenter har sitt eget, og det kan tømmes når som helst. En bom betyr bare et nytt kall.

Flere brukere gjør appen raskere. Med mer trafikk blir cachen varmere: et søk på «breaking» koster ett kall til TMDB første gang, og går deretter fra cachen for alle i samme datasenter.

Tjenester utenfor Cloudflare

  • TMDB – plakater, handling på norsk og hvor titler strømmes i Norge. Har grenser på antall kall i sekundet; cachen skjermer godt.
  • OMDb – Rotten Tomatoes og Metacritic. Har en daglig grense. Kallet har en kort tidsgrense og er valgfritt: henger OMDb, vises tittelsiden likevel, bare uten disse to scorene.
  • Claude fra Anthropic – gjenkjenning av cover når man tar bilde. Betales per bilde; hver bruker har en månedskvote.
  • Resend – e-post, for eksempel kode ved registrering.

Alle kall ut har tidsgrenser. Uten det kan ett hengende kall holde en side i et halvt minutt, og appen tror at nettet er borte. Det skjedde én gang da OMDb hang en morgen – siden da har hvert eksternt kall en grense på noen sekunder.

7. Grenser satt med vilje

Noen grenser er lagt inn for å beskytte appen, ikke fordi plattformen krever dem:

  • Fartsgrenser (rate limiting) per bruker og per IP-adresse: hindrer at en robot eller en feil i appen spiser opp kvotene hos TMDB eller Claude, eller prøver passord i høyt tempo. Mobiloperatører deler IP-adresser mellom mange kunder, så grensene per IP er rause.
  • Tak på nye kontoer per døgn: stopper robotangrep og uventede e-postkostnader.

Lærdom før en kjent pågang: taket på nye kontoer er det eneste i Sofatid som bevisst sier nei til nye brukere. Kommer det en video som kan gi hundrevis av registreringer på en kveld, heves taket i admin først. Selve appen tåler mye mer.

8. Å se hva som skjer

Når alt skalerer av seg selv, er det viktigste å se hvordan det går. Sofatid har derfor:

  • Et «Nå»-panel i admin som oppdateres hvert 30. sekund: brukere, nye kontoer, feil og hvor mange som stoppes av grenser, time for time.
  • Fartsmålinger fra appen: hvor lang tid søkeforslag, søk og åpning av en tittel tar for brukerne – median og de tregeste ti prosentene. Ingenting om hvem som målte.
  • En helsesjekk hver time som varsler på e-post og push ved mange feil, mange stoppet av grenser eller treghet.
  • En feillogg med feil fra serveren og fra appen.

Blir noe tregt ved stor pågang, er det nesten alltid databasen eller en ekstern tjeneste – ikke koden. Fartsmålingene og feilloggen viser hvilken.

9. Oppsummert

Pods (tradisjonelt)Cloudflare Workers
Hvor koden kjørerEtt datasenter300+ byer, nær brukeren
Hva som kjørerContainere (pods)Isolater i en delt prosess
OppstartSekunderMillisekunder
SkaleringAutoskalerer som må stilles innAutomatisk, uten innstillinger
Brå trafikkbølgeTregt i startenTas imot med en gang
BetalingFor maskiner, også i tomgangPer forespørsel og regnetid
MinneDet man betaler for128 MB per isolat, kan forsvinne

For Sofatid betyr det at koden tåler en plutselig bølge uten at noen gjør noe. Databasen er den viktigste delen å følge med på, og eksterne tjenester er beskyttet med cache, tidsgrenser og fartsgrenser. Resten handler om å se hva som skjer – og om å heve taket for nye kontoer før en video går viralt.