Vi i Badoo overvåker stadig nye teknologier og vurderer om vi skal bruke dem i systemet vårt eller ikke. Vi ønsker å dele en av disse studiene med samfunnet. Det er dedikert til Loki, et loggaggregeringssystem.
Loki er en løsning for lagring og visning av logger, og denne stabelen gir også et fleksibelt system for å analysere dem og sende data til Prometheus. I mai ble en annen oppdatering utgitt, som aktivt promoteres av skaperne. Vi var interessert i hva Loki kan gjøre, hvilke muligheter det gir, og i hvilken grad det kan fungere som et alternativ til ELK, stabelen vi bruker nå.
Hva er Loke
Grafana Loki er et sett med komponenter for et komplett loggesystem. I motsetning til andre lignende systemer, er Loki basert på ideen om å kun indeksere loggmetadata - etiketter (akkurat som i Prometheus), og komprimere selve loggene side om side i separate biter.
Før jeg går inn på hva du kan gjøre med Loki, vil jeg avklare hva som menes med "ideen om kun å indeksere metadata". La oss sammenligne Loki-tilnærmingen og indekseringsmetoden i tradisjonelle løsninger, for eksempel Elasticsearch, ved å bruke eksemplet på en linje fra nginx-loggen:
Tradisjonelle systemer analyserer hele raden, inkludert felt med mange unike user_id- og item_id-verdier, og lagrer alt i store indekser. Fordelen med denne tilnærmingen er at du kan kjøre komplekse spørringer raskt, siden nesten alle dataene er i indeksen. Men du må betale for dette ved at indeksen blir stor, noe som gir seg utslag i minnekrav. Som et resultat er fulltekstindeksen for logger sammenlignbar i størrelse med selve loggene. For å raskt søke gjennom den, må indeksen lastes inn i minnet. Og jo flere logger, jo raskere øker indeksen og jo mer minne bruker den.
Loki-tilnærmingen krever at bare de nødvendige dataene trekkes ut fra strengen, hvor antallet verdier er lite. På denne måten får vi en liten indeks og kan søke i dataene ved å filtrere dem etter tid og indekserte felt, og deretter skanne resten med regulære uttrykk eller understrengsøk. Prosessen virker ikke den raskeste, men Loki deler opp forespørselen i flere deler og utfører dem parallelt, og behandler en stor mengde data på kort tid. Antallet shards og parallelle forespørsler i dem kan konfigureres; dermed avhenger mengden data som kan behandles per tidsenhet lineært av mengden ressurser som tilbys.
Denne avveiningen mellom en stor rask indeks og en liten parallell brute-force-indeks lar Loki kontrollere kostnadene for systemet. Den kan konfigureres og utvides fleksibelt etter dine behov.
Loki-stabelen består av tre komponenter: Promtail, Loki, Grafana. Promtail samler inn logger, behandler dem og sender dem til Loke. Loke beholder dem. Og Grafana kan be om data fra Loke og vise dem. Generelt kan Loki ikke bare brukes til å lagre logger og søke gjennom dem. Hele stabelen gir store muligheter for å behandle og analysere innkommende data ved hjelp av Prometheus-måten.
Du finner en beskrivelse av installasjonsprosessen her.
Loggsøk
Du kan søke i loggene i et spesielt grensesnitt Grafana — Explorer. Spørringene bruker LogQL-språket, som er veldig likt PromQL som brukes av Prometheus. I prinsippet kan det betraktes som et distribuert grep.
Søkegrensesnittet ser slik ut:
Selve spørringen består av to deler: velger og filter. Velger er et søk etter indekserte metadata (etiketter) som er tilordnet loggene, og filter er en søkestreng eller regexp som filtrerer ut postene definert av velgeren. I det gitte eksempelet: I krøllete parentes - velgeren, alt etter - filteret.
{image_name="nginx.promtail.test"} |= "index"
På grunn av måten Loki fungerer på, kan du ikke lage forespørsler uten en velger, men etiketter kan gjøres vilkårlig generiske.
Velgeren er nøkkelverdien til verdien i krøllete klammeparenteser. Du kan kombinere velgere og spesifisere forskjellige søkebetingelser ved å bruke =, !=-operatorene eller regulære uttrykk:
{instance=~"kafka-[23]",name!="kafka-dev"}
// Найдёт логи с лейблом instance, имеющие значение kafka-2, kafka-3, и исключит dev
Et filter er en tekst eller regexp som vil filtrere ut alle dataene som mottas av velgeren.
Det er mulig å få ad hoc-grafer basert på de mottatte dataene i metrikkmodus. For eksempel kan du finne ut hyppigheten av forekomst i nginx-loggene til en oppføring som inneholder indeksstrengen:
En fullstendig beskrivelse av funksjonene finnes i dokumentasjonen LogQL.
Loggparsing
Det er flere måter å samle logger på:
Ved hjelp av Promtail, en standardkomponent i stabelen for å samle tømmerstokker.
Bruk Fluentd eller Fluent Bit som kan sende data til Loki. I motsetning til Promtail har de ferdige parsere for nesten alle typer tømmerstokker og kan håndtere flerlinjelogger også.
Vanligvis brukes Promtail for parsing. Den gjør tre ting:
Finner datakilder.
Fest etiketter til dem.
Sender data til Loke.
For øyeblikket kan Promtail lese logger fra lokale filer og fra systemd journal. Den må installeres på hver maskin som tømmerstokkene samles inn fra.
Det er integrasjon med Kubernetes: Promtail finner automatisk ut statusen til klyngen gjennom Kubernetes REST API og samler inn logger fra en node, tjeneste eller pod, og legger umiddelbart ut etiketter basert på metadata fra Kubernetes (podnavn, filnavn, etc.).
Du kan også henge etiketter basert på data fra loggen ved å bruke Pipeline. Pipeline Promtail kan bestå av fire typer trinn. Flere detaljer - in offisiell dokumentasjon, vil jeg umiddelbart legge merke til noen av nyansene.
Parsing stadier. Dette er stadiet av RegEx og JSON. På dette stadiet trekker vi ut data fra loggene til det såkalte ekstraherte kartet. Du kan trekke ut fra JSON ved ganske enkelt å kopiere feltene vi trenger inn i det utpakkede kartet, eller gjennom regulære uttrykk (RegEx), der navngitte grupper "tilordnes" til det utpakkede kartet. Uttrukket kart er et nøkkelverdilager, der nøkkel er navnet på feltet, og verdi er verdien fra loggene.
Forvandle stadier. Dette stadiet har to alternativer: transformasjon, der vi setter transformasjonsreglene, og kilde - datakilden for transformasjonen fra det ekstraherte kartet. Hvis det ikke er et slikt felt i det utpakkede kartet, vil det bli opprettet. Dermed er det mulig å lage etiketter som ikke er basert på det utpakkede kartet. På dette stadiet kan vi manipulere dataene i det utpakkede kartet ved hjelp av en ganske kraftig golang mal. I tillegg må vi huske at det utpakkede kartet er fulllastet under parsing, noe som gjør det mulig for eksempel å sjekke verdien i det: «{{if .tag}tag value exists{end}}». Malen støtter betingelser, løkker og noen strengfunksjoner som Replace og Trim.
Handlingsstadier. På dette stadiet kan du gjøre noe med det ekstraherte:
Lag en etikett fra de utpakkede dataene, som vil bli indeksert av Loki.
Endre eller angi hendelsestid fra loggen.
Endre dataene (loggteksten) som skal gå til Loke.
Lag beregninger.
Filtreringsstadier. Kampstadiet, hvor vi enten kan sende poster som vi ikke trenger til /dev/null, eller sende dem for videre behandling.
Ved å bruke eksemplet med å behandle vanlige nginx-logger, vil jeg vise hvordan du kan analysere logger ved å bruke Promtail.
For testen, la oss ta et modifisert nginx jwilder/nginx-proxy:alpine-bilde og en liten demon som kan spørre seg selv via HTTP som nginx-proxy. Daemonen har flere endepunkter, som den kan gi svar av forskjellige størrelser, med forskjellige HTTP-statuser og med forskjellige forsinkelser.
Vi vil samle logger fra docker-containere, som kan finnes langs stien /var/lib/docker/containers/ / -json.log
I docker-compose.yml setter vi opp Promtail og spesifiserer banen til konfigurasjonen:
Legg til banen til loggene til promtail.yml (det er et "docker"-alternativ i konfigurasjonen som gjør det samme på én linje, men det ville ikke være så åpenbart):
scrape_configs:
- job_name: containers
static_configs:
labels:
job: containerlogs
__path__: /var/lib/docker/containers/*/*log # for linux only
Når denne konfigurasjonen er aktivert, vil Loki motta logger fra alle containere. For å unngå dette endrer vi innstillingene til testen nginx i docker-compose.yml - legg til logging i tag-feltet:
For alle logger hvis image_name er lik nginx.promtail.test, trekker vi ut loggfeltet fra kildeloggen og legger det i det utpakkede kartet med radtasten.
Parse request_url. Ved hjelp av regexp bestemmer vi formålet med forespørselen: til statikk, til bilder, til API og setter den tilsvarende nøkkelen i det utpakkede kartet.
- template:
source: request_type
template: "{{if .photo}}photo{{else if .static_type}}static{{else if .api_request}}api{{else}}other{{end}}"
Ved å bruke betingede operatører i malen sjekker vi de installerte feltene i det utpakkede kartet og angir de nødvendige verdiene for request_type-feltet: foto, statisk, API. Tilordne andre hvis det mislyktes. Nå inneholder request_type forespørselstypen.
Vi setter etikettene api_request, virtual_host, request_type og status (HTTP-status) basert på hva vi klarte å legge inn i det utpakkede kartet.
- output:
source: nginx_log_row
Endre utgang. Nå går den rensede nginx-loggen fra det utpakkede kartet til Loki.
Etter å ha kjørt konfigurasjonen ovenfor, kan du se at hver oppføring er merket basert på data fra loggen.
Husk at å trekke ut etiketter med et stort antall verdier (kardinalitet) kan redusere Loki betydelig. Det vil si at du ikke skal legge inn for eksempel bruker_id i indeksen. Les mer om dette i artikkelenHvordan etiketter i Loki kan gjøre loggforespørsler raskere og enklere". Men dette betyr ikke at du ikke kan søke etter user_id uten indekser. Det er nødvendig å bruke filtre når du søker ("grab" i henhold til dataene), og indeksen fungerer her som en strømidentifikator.
Loggvisualisering
Loki kan fungere som en datakilde for Grafana-diagrammer ved hjelp av LogQL. Følgende funksjoner støttes:
rate - antall poster per sekund;
telle over tid - antall poster i det gitte området.
Det er også aggregeringsfunksjoner Sum, Avg og andre. Du kan bygge ganske komplekse grafer, for eksempel en graf over antall HTTP-feil:
Lokis standarddatakilde er litt mindre funksjonell enn Prometheus-datakilden (du kan for eksempel ikke endre forklaringen), men Loki kan kobles til som en Prometheus-typekilde. Jeg er ikke sikker på om dette er dokumentert oppførsel, men å dømme etter responsen fra utviklerne "Hvordan konfigurere Loki som Prometheus-datakilde? · Utgave #1222 · grafana/loki”, for eksempel, det er helt lovlig og Loki er fullt kompatibel med PromQL.
Legg til Loki som datakilde med typen Prometheus og legg til URL /loki:
Og du kan lage grafer, som om vi jobbet med beregninger fra Prometheus:
Jeg tror at avviket i funksjonalitet er midlertidig og utviklerne vil fikse det i fremtiden.
Beregninger
Loki gir muligheten til å trekke ut numeriske beregninger fra logger og sende dem til Prometheus. For eksempel inneholder nginx-loggen antall byte per svar, og også, med en viss modifikasjon av standard loggformat, tiden i sekunder det tok å svare. Disse dataene kan trekkes ut og sendes til Prometheus.
Alternativet lar deg definere og oppdatere beregninger basert på data fra det utpakkede kartet. Disse beregningene sendes ikke til Loki - de vises i Promtail /metrics-endepunktet. Prometheus må konfigureres til å motta data fra dette stadiet. I eksemplet ovenfor, for request_type="api" samler vi inn en histogramberegning. Med denne typen beregninger er det praktisk å få persentiler. For statikk og bilder samler vi inn summen av byte og antall rader der vi mottok byte for å beregne gjennomsnittet.
På denne måten kan du for eksempel finne ut de fire tregeste spørringene. Du kan også konfigurere overvåking for disse beregningene.
skalering
Loki kan være i både singel binær modus og sharded (horisontalt skalerbar modus). I det andre tilfellet kan den lagre data til skyen, og bitene og indeksen lagres separat. I versjon 1.5 er muligheten til å lagre på ett sted implementert, men det anbefales ennå ikke å bruke det i produksjon.
Chunks kan lagres i S3-kompatibel lagring, for lagring av indekser, bruk horisontalt skalerbare databaser: Cassandra, BigTable eller DynamoDB. Andre deler av Loki - Distributører (for skriving) og Querier (for spørringer) - er statsløse og skaleres også horisontalt.
På DevOpsDays Vancouver 2019-konferansen kunngjorde en av deltakerne Callum Styan at prosjektet hans med Loki har petabyte med logger med en indeks på mindre enn 1% av den totale størrelsen: "Hvordan Loki korrelerer beregninger og logger - og sparer penger".
Sammenligning av Loki og ELK
Indeksstørrelse
For å teste den resulterende indeksstørrelsen tok jeg logger fra nginx-beholderen som Pipeline ovenfor var konfigurert for. Loggfilen inneholdt 406 624 linjer med et totalt volum på 109 MB. Logger ble generert i løpet av en time, omtrent 100 poster per sekund.
Et eksempel på to linjer fra loggen:
Ved indeksering av ELK ga dette en indeksstørrelse på 30,3 MB:
I Lokis tilfelle ga dette omtrent 128 KB indeks og omtrent 3,8 MB data i biter. Det er verdt å merke seg at loggen ble kunstig generert og ikke inneholdt et bredt utvalg av data. En enkel gzip på den originale Docker JSON-loggen med data ga en komprimering på 95,4 %, og gitt at kun den rensede nginx-loggen ble sendt til Loki selv, er komprimeringen til 4 MB forståelig. Det totale antallet unike verdier for Loki-etiketter var 35, noe som forklarer den lille størrelsen på indeksen. For ELK ble loggen også ryddet. Dermed komprimerte Loki de originale dataene med 96 %, og ELK med 70 %.
Minneforbruk
Hvis vi sammenligner hele stabelen med Prometheus og ELK, så "spiser" Loke flere ganger mindre. Det er klart at Go-tjenesten bruker mindre enn Java-tjenesten, og å sammenligne størrelsen på Heap Elasticsearch JVM og det tildelte minnet for Loki er feil, men likevel er det verdt å merke seg at Loki bruker mye mindre minne. CPU-fordelen er ikke så åpenbar, men den er også tilstede.
Fart
Loke «sluker» logger raskere. Hastigheten avhenger av mange faktorer - hva slags logger, hvor sofistikert vi analyserer dem, nettverk, disk osv. - men den er definitivt høyere enn for ELK (i min test - omtrent to ganger). Dette forklares av det faktum at Loki legger mye mindre data inn i indeksen og bruker derfor mindre tid på indeksering. I dette tilfellet er situasjonen snudd med søkehastigheten: Loki bremser merkbart ned på data større enn noen få gigabyte, mens for ELK er søkehastigheten ikke avhengig av datastørrelsen.
Loggsøk
Loki er betydelig dårligere enn ELK når det gjelder loggsøkemuligheter. Grep med regulære uttrykk er en sterk ting, men det er dårligere enn en voksendatabase. Mangelen på rekkeviddespørringer, aggregering kun av etiketter, manglende evne til å søke uten etiketter - alt dette begrenser oss i å søke etter informasjon av interesse i Loki. Dette betyr ikke at ingenting kan bli funnet ved å bruke Loki, men det definerer flyten av arbeid med logger, når du først finner et problem på Prometheus-diagrammene, og deretter ser etter hva som skjedde i loggene ved å bruke disse etikettene.
grensesnitt
For det første er det vakkert (beklager, kunne ikke motstå). Grafana har et pent grensesnitt, men Kibana er mye mer funksjonelt.
Loki fordeler og ulemper
Av plussene kan det bemerkes at Loki integreres med henholdsvis Prometheus, vi får metrikk og varsling ut av boksen. Den er praktisk for å samle logger og lagre dem med Kubernetes Pods, siden den har en tjenesteoppdagelse som er arvet fra Prometheus og automatisk fester etiketter.
Av minusene - dårlig dokumentasjon. Noen ting, for eksempel funksjonene og egenskapene til Promtail, oppdaget jeg bare i prosessen med å studere koden, fordelen med åpen kildekode. En annen ulempe er de svake analysemulighetene. Loke kan for eksempel ikke analysere logger med flere linjer. Ulempene inkluderer også det faktum at Loki er en relativt ung teknologi (utgivelse 1.0 var i november 2019).
Konklusjon
Loki er en 100 % interessant teknologi som er egnet for små og mellomstore prosjekter, som lar deg løse mange problemer med loggaggregering, loggsøk, overvåking og analyse av logger.
Vi bruker ikke Loki på Badoo, fordi vi har en ELK-stack som passer oss og som har blitt bevokst med ulike tilpassede løsninger gjennom årene. For oss er snublesteinen søket i loggene. Med nesten 100 GB logger per dag er det viktig for oss å kunne finne alt og litt til og gjøre det raskt. For kartlegging og overvåking bruker vi andre løsninger som er tilpasset våre behov og integrert med hverandre. Loki-stakken har konkrete fordeler, men den vil ikke gi oss mer enn det vi har, og fordelene vil ikke akkurat oppveie kostnadene ved å migrere.
Og selv om det etter forskning ble klart at vi ikke kan bruke Loki, håper vi at dette innlegget vil hjelpe deg med å velge.
Depotet med koden brukt i artikkelen er lokalisert her.