Parenteser

Betraktninger fra Mat-teamets grønne enger

NATS key/value store

Sist lærte vi hvordan det å persistere emner i NATS åpnet for en haug med nye bruksmønstre. Men hvordan åpner det egentlig for at du i mange tilfeller kan bytte ut Redis med NATS?

Når du oppretter en konsument for en strøm i NATS angir du hvilke meldinger du ønsker å få levert med --deliver: all, new, last, subject, 1h, msg, eller sequence. I forrige innlegg brukte vi all til å lese alle meldinger siden tidenes morgen. Men hva om vi heller hadde brukt last?

En key/value store i NATS er bare en strøm der nøklene er emner som starter med navnet på en key/value bucket, og hvor du alltid konsummerer meldinger med last-strategien – altså, hvor du til enhver tid får siste verdi for en gitt nøkkel. Så enkelt og samtidig så genialt!

Siden key/value stores er strømmer så har du også tilgang til alle flaggene vi så på sist. Vil du ha en cache? Gi verdiene en TTL ved å sette --max-age. Vil du ha historikk på nøklene? Be NATS om å ta vare på så mange versjoner du har disk til. Verden er din østers, som det heter.

Det er verdt å nevne her at NATS i skrivende stund mangler støtte for least recently used-semantikk, slik feks Redis har, men dette er visstnok under arbeid.

Et eksempel

La oss starte med å lage en bøtte for key/values:

nats kv add chat-channels

Med chat-channels-bøtta opprettet kan vi skrive noen verdier til den:

nats kv put chat-channels \
    public.general \
    '{"id": "3d5570f5-1651-4f54-9657-534dba9a78b8",
      "members": ["christian", "magnar"],
      "isPublic": true}'

nats kv put chat-channels \
    public.random \
    '{"id": "9d22fb55-bf76-4385-a955-33a944644e98",
      "members": ["christian", "magnar", "slackbot"],
      "isPublic": true}'

Vi kan hente ut dataene igjen med nats kv get:

nats kv get chat-channels \
    public.general \
    --raw \

{"id": "3d5570f5-1651-4f54-9657-534dba9a78b8",
 "members": ["christian", "magnar"],
 "isPublic": true}

Vel og bra. Det er en key/value store. For å få et innblikk i hvordan NATS implementerer disse kan vi sette opp en abonnent på alle meldinger i NATS før vi skriver nøklene:

nats subscribe '>'

Hvis du nå gjentar put-operasjonene over vil du se flere meldinger for hver, hvor den mest interessante er denne:

[#4] Received on "$KV.chat-channels.public.general" with reply "_INBOX.0C7AtbDyU37lmByZTGAMRw.XLKKqeCX"
{"id": "3d5570f5-1651-4f54-9657-534dba9a78b8",
      "members": ["christian", "magnar"],
      "isPublic": true}

Her ser vi at key/value-paret sendes som en helt vanlig melding på emnet $KV.chat-channels.public.general, altså $KV.<bucket>.<key>. Vi kan finne strømmen også, hvis vi bruker -a til stream ls for å be NATS om å også inkludere systemstrømmer:

nats stream ls -a

Name             │ Created             │ Messages │ Size  │ Last Message
                 |                     |          |       |
KV_chat-channels │ 2024-04-02 22:12:38 │ 2359 B │ 2m43s

Det er ikke så nyttig å bruke denne direkte – de spissede key/value-verktøyene er bedre egnet. Men jeg fant det veldig opplysende at key/value stores rett og slett er litt bekvemmelighet på toppen av strømmer, som igjen “bare” er persistens på toppen av NATS sin emnebaserte meldingsutveksling. Så fokusert og simpelt, men allikevel så bredt anvendbart.

Bonus-poeng: Object store

NATS kommer forresten også med en object store ala S3, altså en key/value store der verdiene er større elementer (NATS sin key/value kan ikke ha verdier på større enn 64MB). Hvordan tror du den er implementert?

Kjør opp en terminal som kun ser på headerne på meldingene (med mindre du er veldig glad i binær output):

nats subscribe '>' --headers-only

Opprett så en object store og last opp en eller annen stor fil (jeg fant en video av en CSS-animasjon):

nats object add photos
nats object put photos ~/Downloads/wiggle.mp4

Du vil se at det går en hel del meldinger på formen:

[#827] Received on "$O.photos.C.8nio3J3KG4xr7ZlZkOpJB6" with reply "_INBOX.zIeGkC.bc859g"

Object storen er selvfølgelig også bare en strøm, hvor verdien er splitta ut over flere keys.

Christian

Om Køer og NATS

Nyttig å vite om NATS er en serie med bloggposter om det distribuerte meldingssystemet NATS. Lyst til å lese videre? Her er det neste innlegget i serien:

En samtale mellom NATS og Clojure

Det finnes foreløpig ikke noe offisielt NATS-bibliotek for Clojure, så hvordan i huleste får vi parentes-frelste emnebasert meldingsutveksling inn i systemene våre?