# Systemmätvärden

## Vad det är

Systemmätvärden är mätningar av en tjänst i drift, var och en tagen vid ett visst ögonblick och
sparad som ett värde med en tidsstämpel och några etiketter, så att samma storhet kan läsas av igen
en minut, en dag eller en månad senare. En namngiven storhet är ett mätvärde. Sparad som en följd av
värden över tid blir den en tidsserie, och OpenTelemetry räknar mätvärden som en av sina signaler,
bredvid spårningar och loggar. Antal besvarade förfrågningar, använt minne och jobb som väntar i en
kö är typiska mätvärden.

Det som skiljer mätvärden från de andra signalerna är aggregeringen. En logg sparar en rad per
händelse, och en spårning följer en enda förfrågan genom systemet. Ett mätvärde viker ihop många
mätningar till några få statistiska tal över ett tidsfönster: ett antal, en summa, ett aktuellt
värde, en fördelning över intervall. Dokumentationen för OpenTelemetry kallar resultatet aggregerad
statistisk information, och det är både styrkan och begränsningen: ett mätvärde säger hur många
förfrågningar som misslyckades den senaste minuten, och en logg säger vilka.

OpenTelemetry och Prometheus är överens om ett litet antal former, och att välja rätt form är det
mesta av designarbetet:

- En **räknare** (”counter”) ackumulerar och går bara uppåt, som mätarställningen i en bil:
  besvarade förfrågningar, skickade byte, upptäckta fel. Prometheus tillåter ett undantag, en
  återställning till noll när processen startar om.
- En **upp-och-ned-räknare** (”up-down counter”), som OpenTelemetry kallar den, ackumulerar men kan
  också gå nedåt, t.ex. längden på en kö när arbete kommer in och lämnar den.
- En **mätare** (”gauge”) är ett aktuellt värde som läses av i samma stund som någon läser det, som
  bränslemätaren i samma bil: använt minne, en temperatur, pågående förfrågningar.
- Ett **histogram** sorterar mätningar i intervall och sparar deras antal och summa, så att det kan
  svara på hur många förfrågningar som tog mindre än en sekund.

Prometheus har också en summary, som räknar ut kvantiler inne i programmet. Datamodellen i
OpenTelemetry behåller den bara som en äldre typ, eftersom sådana sammanfattningar inte alltid går
att slå ihop på ett meningsfullt sätt.

Textformatet som Prometheus hämtar visar delarna tillsammans: en hjälprad, en typrad och sedan en
rad per kombination av etiketter med namnet, etiketterna, värdet och en valfri tidsstämpel i
millisekunder sedan epoken.

```text
# HELP http_requests_total The total number of HTTP requests.
# TYPE http_requests_total counter
http_requests_total{method="post",code="200"} 1027 1395066363000
http_requests_total{method="post",code="400"} 3 1395066363000
```

## Varför det spelar roll

Mätvärden är billiga nog att sparas för allting. Minnet de kräver växer med antalet olika
kombinationer av etiketter, inte med trafiken, och dokumentationen för OpenTelemetry säger det med
just de orden, som en kontrast till loggar. En räknare som har ökats en miljard gånger är
fortfarande ett enda tal. Det är det som låter ett team räkna varje förfrågan i stället för ett
urval, och spara räkningarna länge nog för att jämföra den här månaden med den förra.

De gör diskussioner till mätningar. Om en server är stor nog, om en release gjorde svaren
långsammare, hur snart en disk blir full: alla har ett svar i en serie som spelades in innan någon
frågade. Larm byggs på samma tal, eftersom en larmregel är ett villkor över ett mätvärde som någon
har bedömt vara värt att vakna för.

Mätvärden lever också längre än koden som skickar ut dem, så formen är värd att få rätt.
Namngivningsguiden för Prometheus ber om en enhet och en storhet per mätvärde, i basenheter som
sekunder och byte i stället för millisekunder eller megabyte, med enheten som ett suffix i plural
och `_total` på ett ackumulerande antal. Namn som `http_request_duration_seconds` och
`process_cpu_seconds_total` säger då redan på ytan vad de innehåller.

Hur summorna färdas spelar också in. Prometheus rapporterar kumulativa summor, så luckor från en
insamling som fallerar då och då jämnas ut, till priset av minne hos avsändaren i proportion till
dess kombinationer av etiketter. StatsD rapporterar deltan, alltså förändringen sedan förra
rapporten, och flyttar därmed den kostnaden ut ur processen.

## Så ser det ut i praktiken

Företagets egen produktionsserver är en maskin med en kärna och 512 MB minne, varav ungefär 464 MB
går att använda, och där blev minnet det argument som avgjorde besluten. Mätvärdena hämtas bara på
begäran, av sju kommandon som läser av servern utan att ändra något och skriver ut resultatet som
Markdown. När frågan kom upp om
[samma server på 512 MB också kunde bära en onion-tjänst](/sv/portfolio/ran-the-whole-company-on-one-512mb-host-109/)
avgjordes den av tre mätvärden, tagna som stickprov under ett dygn i stället för hämtade ur en
åsikt: det tillgängliga minnet höll sig över ungefär 310 MB av 464, swapanvändningen var 2,6 % och
processorn stod i vila 99,7 % av tiden.

De rapporterna behövde senare säga vad deras tal var värda.
[Sex insamlare som bara läser fick ange det de aldrig läste](/sv/portfolio/made-six-collectors-state-what-they-never-read-167/),
när det stod klart att en blind insamling och en frisk server gav samma sida: en spegel vars daemon
hade bytt loggformat gav samma nolla som en spegel som ingen besökte. Tröskelvärdena anpassades
efter de 116 stickprov som metrikrapporten redan hade mätt, med de observerade intervallen
registrerade bredvid gränserna, och rapporten skiljer på tre utfall: en överträdelse, ingen
överträdelse och ej bedömd eftersom ingenting mätte den. Varje insamlare rapporterar sin körtid och
sin blindhet, t.ex. lästa filer mot oläsbara filer, även när svaret är noll. Gränserna är
dagsgenomsnitt, så en server som når ett tak under en minut passerar ingenting där, och det är
dödmansgreppet på femton minuter som fångar det.

De mest användbara mätvärdena kommer ofta från problemet snarare än från maskinen.
[Anteckningen om ett biljettsläpp med begränsat lager](/sv/notes/selling-limited-stock-without-overselling/)
samlar väntetider på lås, reservationer som löpt ut och avståndet mellan grindens räkning och
databasens på en och samma dashboard. Den kör invarianten `available + held + sold = total`
schemalagt, visar den i ett diagram och larmar vid varje avvikelse. Vart och ett av de talen kommer
ur kunskapen om hur just den försäljningen går fel.

## Var det går fel

Systemmätvärden går sällan sönder med ett brak. Grafen fortsätter att ritas, och talet på den
betyder i tysthet något annat än det som namnet säger.

**Ett värde som sjunker publiceras som en räknare.** Sidan om mätvärdestyper hos Prometheus säger
att en räknare inte ska användas för något som kan minska, t.ex. antalet processer som körs: det är
en mätare. Frågefunktionerna tolkar varje nedgång i en räknare som en omstart och korrigerar för
den, så ett värde som sjunker med avsikt visar sig som ökningar som aldrig hände.

**Enheterna glider isär mellan tjänsterna.** En tjänst rapporterar en varaktighet i millisekunder,
en annan i sekunder, och en panel som jämför dem slår fel med en faktor tusen. Namngivningsguiden
säger att ett mätvärde måste avse en enda enhet och bör använda basenheter. Att räkna om en gång,
vid källan, är billigare än att komma ihåg skillnaden i varje fråga.

**En summa över etiketterna betyder ingenting.** Tumregeln i namngivningsguiden är att summan eller
medelvärdet över alla etiketter på ett mätvärde ska vara meningsfullt. Guidens eget exempel:
kapaciteten hos flera köer hör ihop i ett mätvärde, medan en kös kapacitet och dess aktuella längd
inte gör det.

**Det som aldrig mättes läses som noll.** En insamlare som har slutat läsa sin indata lämnar en
nolla, eller en rad som saknas, och den ser exakt ut som ett lugnt system. Datamodellen i
OpenTelemetry har en flagga för en punkt utan registrerat värde, dess motsvarighet till markören för
inaktuella värden i Prometheus, eftersom data som saknas och värdet noll är olika fakta. Rapportera
dem olika, och ge ”ej bedömd” ett eget utfall, som insamlarna ovan gör.

**Fönstret döljer toppen.** En mätare är ett stickprov vid ett ögonblick, och datamodellen i
OpenTelemetry rapporterar bara det sista värdet i varje intervall, så en topp mellan två stickprov
lämnar inga spår. Ett dagsgenomsnitt jämnar på samma sätt ut en minut vid taket. Välj fönstret efter
det fel som måste synas, och håll en snabb kontroll bredvid en långsam när båda spelar roll.

**Överflöd räknar för lågt i en filtrerad fråga.** SDK:t för OpenTelemetry håller som standard reda
på högst 2 000 olika kombinationer av attribut per mätvärdesström och viker ihop alla ytterligare
till en enda datapunkt märkt `otel.metric.overflow=true`. Summan förblir korrekt, men överflödet
ersätter hela kombinationen och inte bara dess brusiga del. I dokumentationens eget exempel bär en
räknare för förfrågningar attributen `url.path` och `success`, och när den har svämmat över räknar
en fråga efter `success=false` för lågt, och ett larm på felfrekvensen som bygger på den kan sluta
utlösas. Håll attributen till små, kända mängder och håll utkik efter markören för överflöd.

## Läs mer

- [OpenTelemetry: Metrics](https://opentelemetry.io/docs/concepts/signals/metrics/) —
  instrumentsorter, aggregering och gränsen för kardinalitet.
- [OpenTelemetry: Metrics data model](https://opentelemetry.io/docs/specs/otel/metrics/data-model/)
  — mätare, summor, histogram, temporalitet och flaggan för saknat värde.
- [Prometheus: Metric types](https://prometheus.io/docs/concepts/metric_types/) — counter, gauge,
  histogram och summary.
- [Prometheus: Metric and label naming](https://prometheus.io/docs/practices/naming/) — basenheter,
  suffix för enheter och `_total`.
- [Prometheus: Histograms and summaries](https://prometheus.io/docs/practices/histograms/) — var
  kvantiler räknas ut, och vilka som går att kombinera.
- [Prometheus: Exposition formats](https://prometheus.io/docs/instrumenting/exposition_formats/) —
  textformatet rad för rad.

<https://engineer.company/sv/glossary/metrics/>
