# Latens

## Hva det er

Latens er hvor lang tid et system bruker på å begynne å svare: tiden fra en forespørsel forlater
klienten til den første byten av svaret kommer tilbake. Ingeniører kaller det også forsinkelse eller
etterslep, og for en nettverksvei målt dit og tilbake rundturtid, round-trip time (RTT); innen
ytelse på nett heter den samme ideen tid til første byte, time to first byte (TTFB). Svartid er den
større søsteren, som løper til den siste byten av svaret.

Latens er lett å forveksle med gjennomstrømning og båndbredde, og de tre svarer på forskjellige
spørsmål. Båndbredde er hvor mange biter en forbindelse kan bære per sekund. Gjennomstrømning er
hvor mye arbeid et system gjør ferdig per sekund. Latens er hvor lenge ett enkelt stykke arbeid
venter. En nattlig batchjobb kan ha utmerket gjennomstrømning og elendig latens, og en chatserver
det motsatte.

Hvert millisekund av den kommer fra ett av noen få steder:

- **utbredelse**, signalet som krysser avstanden: lys i optisk fiber tilbakelegger omtrent 200 km
  per millisekund, så en vei på 1 000 km koster minst 10 ms tur-retur før noen programvare har
  kjørt;
- **overføring**, å legge bytene ut på ledningen, noe som betyr noe for store nyttelaster på trege
  forbindelser;
- **kø**, venting bak annet arbeid i en buffer i en ruter, en trådpool, en tilkoblingspool eller en
  lås, den ene komponenten som vokser med belastningen;
- **behandling**, selve arbeidet: spørringen, malen, krypteringen;
- **rundturer i protokollen**, samtalen før den første nyttige byten. En ny HTTPS-tilkobling trenger
  først et TCP-håndtrykk og et TLS-håndtrykk, og TLS 1.3 kuttet det fulle håndtrykket sitt ned til
  én enkelt rundtur.

Arbeidsgruppen IP Performance Metrics i IETF slo fast nettverksvarianten i RFC 2681: forsinkelsen
tur-retur løper fra den første biten i en pakke som sendes, til den siste biten i svaret som tas
imot. To av valgene der gjelder for enhver tjeneste. Et svar som aldri kommer, regnes som udefinert,
uformelt uendelig, i stedet for å bli utelatt fra utvalget i det stille. Og statistikken RFC-en
beskriver, er persentiler, medianen og minimumsverdien. Den påpeker også at minimum bare gjenspeiler
utbredelse og overføring, mens alt over minimum tyder på overbelastning, et skille som gjelder like
godt for et API som for en vei mellom rutere.

For én enkelt webforespørsel deler curl ventetiden opp i stegene sine:

```sh
curl -s -o /dev/null "$URL" -w '
dns        %{time_namelookup}
connect    %{time_connect}
tls        %{time_appconnect}
first byte %{time_starttransfer}
total      %{time_total}
'
```

Hvert tall er sekunder siden starten, så det er mellomrommene mellom dem som er kostnadene:
oppslaget av navnet i DNS, åpningen av tilkoblingen, TLS-håndtrykket og så serverens egen tenketid
frem til første byte.

## Hvorfor det er viktig

Latens er det en bruker kjenner; gjennomstrømning er det serverregningen gjenspeiler. Når en side er
treg, er avgjørelsen hvor pengene skal brukes, og de fire årsakene ovenfor har fire forskjellige
løsninger som ikke kan erstatte hverandre. Avstand løses ved å flytte nærmere: caching, et CDN, en
region nær brukerne. Rundturer løses ved å ha færre av dem: gjenbruke tilkoblinger, samle spørringer
i batcher, hente parallelt. Behandling løses ved å gjøre mindre arbeid: en indeks, en bedre
spørreplan. Kø alene løses med kapasitet. En spørring som tar to sekunder på en ledig server, tar to
sekunder på en server som er ti ganger så stor, og derfor er mer maskinvare det riktige svaret på
bare én av de fire.

Gjennomsnitt får problemet til å se mindre ut enn det er, fordi brukerne møter halen. En side som
kaller ti tjenester i backend parallelt, venter på den tregeste. Er hvert kall tregt i 1 % av
tilfellene, treffer 1 − 0,99¹⁰, ca. 9,6 % av sidevisningene, minst ett tregt kall. En sjelden
forsinkelse i delene blir en vanlig forsinkelse i helheten.

Derfor skrives seriøse mål i persentiler, for eksempel at 99 % av forespørslene besvares innen 300
ms over 30 dager, og derfor er den 99. persentilen som regel tallet det er verdt å følge med på.
Medianen sier hvordan tjenesten føles en god dag; de høye persentilene sier hvordan den føles for
kundene som er i ferd med å gå.

## Slik ser det ut i praksis

I en geografisk kartapplikasjon gikk latensen i gjengivelsen av kartlag og i spørringene mot
stedsbaserte data ut over både brukerne og påliteligheten til backend. Databasen under, Microsoft
SQL Server, manglet innebygd geospatial indeksering, så den trege delen var behandling og ikke
avstand.
[Overgangen til PostgreSQL med PostGIS kuttet gjennomsnittlig svartid](/nb/portfolio/improved-geographical-map-application-performance-by-10x-through-6/)
for romlige spørringer, med 10 ganger bedre ytelse som resultat: der en spørring hadde brukt 2,5
sekunder i snitt, brukte den nå under 250 millisekunder. Arbeidet bak var GiST- og SP-GiST-indekser
på de romlige kolonnene, mer enn 50 millioner poster migrert og en konfigurasjon justert for
samtidig tilgang; CPU-belastningen i backend falt med 65 %.

Latens setter også et tak for gjennomstrømningen der det er kamp om én rad. Et
[notat om lynsalg der alle kjøperne skriver til den samme raden](/nb/notes/selling-limited-stock-without-overselling/)
setter taket for én enkelt vare til omtrent hvor mange salg én lås bærer, delt på hvor lenge låsen
holdes. Alt som er tregt inne i låsen, senker det taket: et kall til betaling som gjøres mens låsen
holdes, tar det ned til rundt to salg i sekundet. Selv et sikkerhetstiltak har en pris her. En
synkron standby i PostgreSQL legger latens til hver commit, og det forlenger nettopp den holdetiden
for låsen som taket deles på.

Og for å finne ut hvor tiden går,
[registrerer den egenutviklede overvåkingen på én plattform](/nb/portfolio/built-first-party-error-monitoring-and-tracing-98/)
latensen i API-et i sin egen database og sporer forespørsler med OpenTelemetry, slik at en treg
forespørsel kan følges på tvers av frontenden, API-et og databasen i stedet for å gjettes på.

## Hvor det går galt

**Gjennomsnittet skjuler halen.** Et snitt på 100 ms er forenlig med at én forespørsel av femti tar
tre sekunder. Registrer latensen som et histogram, og les persentilene fra det. Pass så på hvordan
de kombineres: gjennomsnittet av den 99. persentilen fra fem servere er ikke den 99. persentilen for
hele maskinparken. Prometheus poengterer det selv i dokumentasjonen sin: kvantiler som er beregnet
av en summary, kan ikke aggregeres, mens bøttene i et histogram kan summeres først og kvantilen
beregnes etterpå.

**Tidtakeren starter på feil sted.** En server som måler fra øyeblikket håndtereren starter, går
glipp av tiden forespørselen tilbrakte i lastbalansereren, i køen av ventende tilkoblinger eller i
ventingen på en ledig tilkobling fra poolen. Lastgeneratorer som venter på hvert svar før de sender
neste forespørsel, sender færre forespørsler akkurat når systemet står fast, så stoppet synes knapt
i resultatene. Mål fra klienten også, og la serveren melde sin egen andel i en standard header:

```http
Server-Timing: db;dur=53, app;dur=47.2
```

**Samtalen er for pratsom.** En side som kjører én spørring per rad i en liste, betaler én rundtur
per rad. Med databasen i en annen region, 30 ms unna per rundtur, koster hundre rader tre sekunder
før noen spørring har gjort ekte arbeid. Én spørring med en join, eller ett samlet kall, betaler
avstanden én gang.

**Nye forsøk ganger opp belastningen.** En klient som gir opp etter ett sekund og prøver på nytt tre
ganger, gjør én treg server om til fire ganger så mye trafikk, og det gjør den enda tregere. Gi hver
forespørsel en samlet frist, vent eksponentielt lenger mellom forsøkene med en tilfeldig variasjon,
og sett et tak på antallet nye forsøk.

## Les mer

- [RFC 2681: A Round-trip Delay Metric for IPPM](https://www.rfc-editor.org/rfc/rfc2681) —
  forsinkelse tur-retur definert ned til biten, med tapte svar og persentiler uttrykkelig behandlet.
- [RFC 7679: A One-Way Delay Metric for IP Performance Metrics](https://www.rfc-editor.org/rfc/rfc7679)
  — motstykket for forsinkelse én vei, utgitt som internettstandard.
- [Server Timing](https://www.w3.org/TR/server-timing/) — W3C-headeren som lar en server fortelle
  nettleseren hvor tiden ble av.
- [Histograms and summaries](https://prometheus.io/docs/practices/histograms/) — hvorfor kvantiler
  fra en summary ikke kan kombineres, mens bøtter i et histogram kan.
- [RFC 8446: TLS 1.3](https://www.rfc-editor.org/rfc/rfc8446) — utformingen av håndtrykket, også
  rundturen det fjerner.

<https://engineer.company/nb/glossary/latency/>
