Sbírání logů od Lokiho

Sbírání logů od Lokiho

My v Badoo neustále sledujeme nové technologie a vyhodnocujeme, zda je v našem systému použijeme či nikoli. O jednu z těchto studií se chceme podělit s komunitou. Je věnován Lokimu, systému agregace protokolů.

Loki je řešení pro ukládání a prohlížení protokolů a tento zásobník také poskytuje flexibilní systém pro jejich analýzu a odesílání dat společnosti Prometheus. V květnu vyšla další aktualizace, kterou tvůrci aktivně propagují. Zajímalo nás, co Loki umí, jaké funkce poskytuje a do jaké míry může fungovat jako alternativa k ELK, zásobníku, který nyní používáme.

Co je Loki

Grafana Loki je sada komponent pro kompletní logovací systém. Na rozdíl od jiných podobných systémů je Loki založen na myšlence indexování pouze metadat protokolů - štítků (stejně jako v Prometheus) a komprimování samotných protokolů vedle sebe do samostatných částí.

Domovská stránka, GitHub

Než se pustím do toho, co můžete dělat s Lokim, chci objasnit, co je míněno „myšlenkou indexování pouze metadat“. Porovnejme přístup Loki a přístup indexování v tradičních řešeních, jako je Elasticsearch, na příkladu řádku z protokolu nginx:

172.19.0.4 - - [01/Jun/2020:12:05:03 +0000] "GET /purchase?user_id=75146478&item_id=34234 HTTP/1.1" 500 8102 "-" "Stub_Bot/3.0" "0.001"

Tradiční systémy analyzují celý řádek, včetně polí s mnoha jedinečnými hodnotami user_id a item_id, a vše ukládají do velkých indexů. Výhodou tohoto přístupu je, že můžete rychle spouštět složité dotazy, protože téměř všechna data jsou v indexu. Ale musíte za to zaplatit, protože index se zvětší, což se promítá do požadavků na paměť. Díky tomu je fulltextový index protokolů co do velikosti srovnatelný se samotnými protokoly. Aby bylo možné v něm rychle prohledávat, musí být index načten do paměti. A čím více protokolů, tím rychleji se index zvyšuje a tím více paměti spotřebuje.

Přístup Loki vyžaduje, aby z řetězce byla extrahována pouze nezbytná data, jejichž počet hodnot je malý. Tímto způsobem získáme malý index a můžeme prohledávat data filtrováním podle času a indexovaných polí a poté skenovat zbytek pomocí regulárních výrazů nebo hledání podřetězců. Proces se nezdá nejrychlejší, ale Loki rozdělí požadavek na několik částí a provede je paralelně, přičemž zpracuje velké množství dat v krátkém čase. Počet fragmentů a paralelních požadavků v nich je konfigurovatelný; tedy množství dat, které lze zpracovat za jednotku času, závisí lineárně na množství poskytnutých zdrojů.

Tento kompromis mezi velkým rychlým indexem a malým paralelním indexem hrubé síly umožňuje Lokimu kontrolovat náklady na systém. Lze jej flexibilně konfigurovat a rozšiřovat podle vašich potřeb.

Zásobník Loki se skládá ze tří složek: Promtail, Loki, Grafana. Promtail shromažďuje protokoly, zpracovává je a posílá je Lokimu. Loki je drží. A Grafana si může vyžádat data od Lokiho a ukázat je. Obecně lze Lokiho využít nejen pro ukládání logů a jejich prohledávání. Celý zásobník poskytuje skvělé příležitosti pro zpracování a analýzu příchozích dat způsobem Prometheus.
Popis procesu instalace naleznete zde.

Hledání protokolu

V protokolech můžete vyhledávat ve speciálním rozhraní Grafana — Explorer. Dotazy používají jazyk LogQL, který je velmi podobný jazyku PromQL, který používá Prometheus. V zásadě si to lze představit jako distribuovaný grep.

Vyhledávací rozhraní vypadá takto:

Sbírání logů od Lokiho

Samotný dotaz se skládá ze dvou částí: selektoru a filtru. Selektor je vyhledávání podle indexovaných metadat (štítek), které jsou přiřazeny k protokolům, a filtr je vyhledávací řetězec nebo regulární výraz, který filtruje záznamy definované selektorem. V uvedeném příkladu: Ve složených závorkách - selektor, vše za - filtr.

{image_name="nginx.promtail.test"} |= "index"

Vzhledem k tomu, jak Loki funguje, nemůžete zadávat požadavky bez selektoru, ale štítky mohou být libovolně obecné.

Selektor je pár klíč–hodnota hodnoty ve složených závorkách. Pomocí operátorů =, != nebo regulárních výrazů můžete kombinovat selektory a zadat různé podmínky vyhledávání:

{instance=~"kafka-[23]",name!="kafka-dev"} 
// Найдёт логи с лейблом instance, имеющие значение kafka-2, kafka-3, и исключит dev 

Filtr je text nebo regulární výraz, který odfiltruje všechna data přijatá selektorem.

V režimu metrik je možné získat ad-hoc grafy na základě přijatých dat. Můžete například zjistit četnost výskytu v protokolech nginx položky obsahující řetězec indexu:

Sbírání logů od Lokiho

Úplný popis funkcí naleznete v dokumentaci LogQL.

Analýza protokolu

Existuje několik způsobů, jak sbírat protokoly:

  • S pomocí Promtailu, standardní součásti zásobníku pro sběr kmenů.
  • Přímo z kontejneru docker pomocí Ovladač protokolování Loki Docker.
  • Použijte Fluentd nebo Fluent Bit, které mohou odesílat data Lokimu. Na rozdíl od Promtailu mají hotové parsery pro téměř jakýkoli typ log a zvládnou i víceřádkové logy.

Promtail se obvykle používá pro analýzu. Dělá to tři věci:

  • Vyhledá zdroje dat.
  • Připojte k nim štítky.
  • Odešle data Lokimu.

V současné době může Promtail číst protokoly z místních souborů a ze systemd journalu. Musí být nainstalován na každém počítači, ze kterého se shromažďují protokoly.

Existuje integrace s Kubernetes: Promtail automaticky zjišťuje stav clusteru prostřednictvím Kubernetes REST API a shromažďuje protokoly z uzlu, služby nebo podu, okamžitě zveřejňuje štítky na základě metadat z Kubernetes (název podu, název souboru atd.).

Můžete také zavěsit štítky na základě dat z protokolu pomocí Pipeline. Pipeline Promtail se může skládat ze čtyř typů stupňů. Více podrobností - v oficiální dokumentace, okamžitě si všimnu některých nuancí.

  1. Fáze analýzy. Toto je fáze RegEx a JSON. V této fázi extrahujeme data z logů do tzv. extrahované mapy. Z JSON můžete extrahovat jednoduchým zkopírováním polí, která potřebujeme, do extrahované mapy, nebo prostřednictvím regulárních výrazů (RegEx), kde jsou pojmenované skupiny „mapovány“ do extrahované mapy. Extrahovaná mapa je úložiště párů klíč–hodnota, kde klíč je název pole a hodnota je jeho hodnota z protokolů.
  2. Fáze transformace. Tato fáze má dvě možnosti: transformace, kde nastavujeme pravidla transformace, a zdroj - zdroj dat pro transformaci z extrahované mapy. Pokud v extrahované mapě žádné takové pole není, bude vytvořeno. Je tedy možné vytvářet štítky, které nejsou založeny na extrahované mapě. V této fázi můžeme manipulovat s daty v extrahované mapě pomocí poměrně výkonného šablona golang. Kromě toho musíme pamatovat na to, že extrahovaná mapa se při analýze plně načte, což umožňuje například zkontrolovat hodnotu v ní: „{{if .tag}hodnota značky existuje{end}}“. Šablona podporuje podmínky, smyčky a některé funkce řetězce, jako je Nahradit a Oříznout.
  3. Akční fáze. V této fázi můžete s extrahovaným něco udělat:
    • Vytvořte štítek z extrahovaných dat, který bude indexovat Loki.
    • Změňte nebo nastavte čas události z protokolu.
    • Změňte data (text protokolu), která půjdou Lokimu.
    • Vytvářejte metriky.
  4. Fáze filtrování. Fáze zápasu, kdy můžeme záznamy, které nepotřebujeme, poslat do /dev/null, nebo je poslat k dalšímu zpracování.

Na příkladu zpracování běžných protokolů nginx ukážu, jak můžete protokoly analyzovat pomocí Promtail.

Pro test si vezměme upravený obrázek nginx jwilder/nginx-proxy:alpine a malého démona, který se umí dotazovat přes HTTP jako nginx-proxy. Démon má několik koncových bodů, kterým může dávat odpovědi různé velikosti, s různými stavy HTTP a s různým zpožděním.

Budeme sbírat protokoly z docker kontejnerů, které najdete na cestě /var/lib/docker/containers/ / -json.log

V docker-compose.yml nastavíme Promtail a určíme cestu ke konfiguraci:

promtail:
  image: grafana/promtail:1.4.1
 // ...
 volumes:
   - /var/lib/docker/containers:/var/lib/docker/containers:ro
   - promtail-data:/var/lib/promtail/positions
   - ${PWD}/promtail/docker.yml:/etc/promtail/promtail.yml
 command:
   - '-config.file=/etc/promtail/promtail.yml'
 // ...

Přidejte cestu k protokolům do promtail.yml (v konfiguraci je možnost „docker“, která dělá totéž na jednom řádku, ale nebylo by to tak zřejmé):

scrape_configs:
 - job_name: containers

   static_configs:
       labels:
         job: containerlogs
         __path__: /var/lib/docker/containers/*/*log  # for linux only

Když je tato konfigurace povolena, Loki bude přijímat protokoly ze všech kontejnerů. Abychom tomu zabránili, změníme nastavení testovacího nginx v docker-compose.yml - do pole tagu přidejte protokolování:

proxy:
 image: nginx.test.v3
//…
 logging:
   driver: "json-file"
   options:
     tag: "{{.ImageName}}|{{.Name}}"

Upravte promtail.yml a nastavte Pipeline. Protokoly jsou následující:

{"log":"u001b[0;33;1mnginx.1    | u001b[0mnginx.test 172.28.0.3 - - [13/Jun/2020:23:25:50 +0000] "GET /api/index HTTP/1.1" 200 0 "-" "Stub_Bot/0.1" "0.096"n","stream":"stdout","attrs":{"tag":"nginx.promtail.test|proxy.prober"},"time":"2020-06-13T23:25:50.66740443Z"}
{"log":"u001b[0;33;1mnginx.1    | u001b[0mnginx.test 172.28.0.3 - - [13/Jun/2020:23:25:50 +0000] "GET /200 HTTP/1.1" 200 0 "-" "Stub_Bot/0.1" "0.000"n","stream":"stdout","attrs":{"tag":"nginx.promtail.test|proxy.prober"},"time":"2020-06-13T23:25:50.702925272Z"}

fáze potrubí:

 - json:
     expressions:
       stream: stream
       attrs: attrs
       tag: attrs.tag

Extrahujeme pole stream, attrs, attrs.tag (pokud existují) z příchozího JSON a vložíme je do extrahované mapy.

 - regex:
     expression: ^(?P<image_name>([^|]+))|(?P<container_name>([^|]+))$
     source: "tag"

Pokud bylo možné vložit pole značky do extrahované mapy, pak pomocí regulárního výrazu extrahujeme názvy obrázku a kontejneru.

 - labels:
     image_name:
     container_name:

Přidělujeme štítky. Pokud jsou v extrahovaných datech nalezeny klíče image_name a container_name, pak budou jejich hodnoty přiřazeny k příslušným štítkům.

 - match:
     selector: '{job="docker",container_name="",image_name=""}'
     action: drop

Zahodíme všechny protokoly, které nemají nastavené štítky image_name a container_name.

  - match:
     selector: '{image_name="nginx.promtail.test"}'
     stages:
       - json:
           expressions:
             row: log

Pro všechny protokoly, jejichž image_name se rovná nginx.promtail.test, extrahujte pole protokolu ze zdrojového protokolu a vložte jej do extrahované mapy pomocí klíče řádku.

  - regex:
         # suppress forego colors
         expression: .+nginx.+|.+[0m(?P<virtual_host>[a-z_.-]+) +(?P<nginxlog>.+)
         source: logrow

Vymažeme vstupní řetězec regulárními výrazy a vytáhneme virtuálního hostitele nginx a řádek protokolu nginx.

     - regex:
         source: nginxlog
         expression: ^(?P<ip>[w.]+) - (?P<user>[^ ]*) [(?P<timestamp>[^ ]+).*] "(?P<method>[^ ]*) (?P<request_url>[^ ]*) (?P<request_http_protocol>[^ ]*)" (?P<status>[d]+) (?P<bytes_out>[d]+) "(?P<http_referer>[^"]*)" "(?P<user_agent>[^"]*)"( "(?P<response_time>[d.]+)")?

Analyzujte protokol nginx s regulárními výrazy.

    - regex:
           source: request_url
           expression: ^.+.(?P<static_type>jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|html|htm)$
     - regex:
           source: request_url
           expression: ^/photo/(?P<photo>[^/?.]+).*$
       - regex:
           source: request_url
           expression: ^/api/(?P<api_request>[^/?.]+).*$

Analyzujte request_url. Pomocí regexpu určíme účel požadavku: na statiku, na fotky, na API a nastavíme odpovídající klíč v extrahované mapě.

       - template:
           source: request_type
           template: "{{if .photo}}photo{{else if .static_type}}static{{else if .api_request}}api{{else}}other{{end}}"

Pomocí podmíněných operátorů v Template zkontrolujeme nainstalovaná pole v extrahované mapě a nastavíme požadované hodnoty pro pole request_type: photo, static, API. Pokud selže, přiřaďte jiné. Nyní request_type obsahuje typ požadavku.

       - labels:
           api_request:
           virtual_host:
           request_type:
           status:

Nastavili jsme štítky api_request, virtual_host, request_type a status (HTTP status) podle toho, co se nám podařilo vložit do extrahované mapy.

       - output:
           source: nginx_log_row

Změňte výstup. Nyní vyčištěný log nginx z extrahované mapy jde k Lokimu.

Sbírání logů od Lokiho

Po spuštění výše uvedené konfigurace můžete vidět, že každá položka je označena na základě dat z protokolu.

Mějte na paměti, že extrahování štítků s velkým počtem hodnot (kardinalita) může Lokiho výrazně zpomalit. To znamená, že byste do indexu neměli vkládat například user_id. Přečtěte si o tom více v článkuJak mohou štítky v Loki zrychlit a zjednodušit dotazy na protokol". To však neznamená, že nemůžete vyhledávat podle user_id bez indexů. Při vyhledávání je nutné používat filtry („chytit“ podle dat) a index zde funguje jako identifikátor proudu.

Vizualizace logu

Sbírání logů od Lokiho

Loki může fungovat jako zdroj dat pro grafy Grafana pomocí LogQL. Podporovány jsou následující funkce:

  • rychlost - počet záznamů za sekundu;
  • počítat v čase - počet záznamů v daném rozsahu.

Nechybí ani agregační funkce Sum, Avg a další. Můžete vytvořit poměrně složité grafy, například graf počtu chyb HTTP:

Sbírání logů od Lokiho

Výchozí zdroj dat Loki je o něco méně funkční než zdroj dat Prometheus (například nemůžete změnit legendu), ale Loki lze připojit jako zdroj typu Prometheus. Nejsem si jistý, jestli je to zdokumentované chování, ale soudě podle reakce od vývojářů “Jak nakonfigurovat Loki jako zdroj dat Prometheus? · Vydání #1222 · grafana/loki“, například je to naprosto legální a Loki je plně kompatibilní s PromQL.

Přidejte Loki jako zdroj dat s typem Prometheus a připojte URL /loki:

Sbírání logů od Lokiho

A můžete vytvářet grafy, jako bychom pracovali s metrikami od společnosti Prometheus:

Sbírání logů od Lokiho

Myslím, že rozpor ve funkčnosti je dočasný a vývojáři to v budoucnu opraví.

Sbírání logů od Lokiho

Metriky

Loki poskytuje možnost extrahovat numerické metriky z protokolů a odesílat je společnosti Prometheus. Například protokol nginx obsahuje počet bajtů na odpověď a také, s určitou úpravou standardního formátu protokolu, čas v sekundách, který trvala odpověď. Tato data lze extrahovat a odeslat společnosti Prometheus.

Přidejte další sekci do promtail.yml:

- match:
   selector: '{request_type="api"}'
   stages:
     - metrics:
         http_nginx_response_time:
           type: Histogram
           description: "response time ms"
           source: response_time
           config:
             buckets: [0.010,0.050,0.100,0.200,0.500,1.0]
- match:
   selector: '{request_type=~"static|photo"}'
   stages:
     - metrics:
         http_nginx_response_bytes_sum:
           type: Counter
           description: "response bytes sum"
           source: bytes_out
           config:
             action: add
         http_nginx_response_bytes_count:
           type: Counter
           description: "response bytes count"
           source: bytes_out
           config:
             action: inc

Tato možnost umožňuje definovat a aktualizovat metriky na základě dat z extrahované mapy. Tyto metriky se neodesílají Loki – zobrazují se v koncovém bodu Promtail /metrics. Prometheus musí být nakonfigurován pro příjem dat z této fáze. Ve výše uvedeném příkladu pro request_type="api" shromažďujeme metriku histogramu. S tímto typem metrik je vhodné získat percentily. U statiky a fotek sbíráme součet bajtů a počet řádků, ve kterých jsme bajty dostali, abychom vypočítali průměr.

Přečtěte si více o metrikách zde.

Otevřete port na Promtail:

promtail:
     image: grafana/promtail:1.4.1
     container_name: monitoring.promtail
     expose:
       - 9080
     ports:
       - "9080:9080"

Dbáme na to, aby se zobrazily metriky s předponou promtail_custom:

Sbírání logů od Lokiho

Nastavení Promethea. Přidat pracovní nabídku:

- job_name: 'promtail'
 scrape_interval: 10s
 static_configs:
   - targets: ['promtail:9080']

A nakreslete graf:

Sbírání logů od Lokiho

Můžete tak zjistit například čtyři nejpomalejší požadavky. Můžete také nakonfigurovat sledování těchto metrik.

Měřítko

Loki může být v samostatném binárním režimu i ve sharded (horizontálně škálovatelný režim). Ve druhém případě může ukládat data do cloudu a části a index jsou uloženy samostatně. Ve verzi 1.5 je implementována možnost ukládání na jedno místo, ale zatím se nedoporučuje používat ji v produkci.

Sbírání logů od Lokiho

Bloky lze ukládat do úložiště kompatibilního s S3 a k ukládání indexů lze použít horizontálně škálovatelné databáze: Cassandra, BigTable nebo DynamoDB. Ostatní části Loki - Distributoři (pro psaní) a Querier (pro dotazy) - jsou bezstavové a také horizontálně škálovatelné.

Na konferenci DevOpsDays Vancouver 2019 jeden z účastníků Callum Styan oznámil, že s Lokim má jeho projekt petabajty protokolů s indexem menším než 1 % celkové velikosti: „Jak Loki koreluje metriky a protokoly — a šetří vám peníze".

Srovnání Lokiho a ELKa

Velikost indexu

Abych otestoval výslednou velikost indexu, vzal jsem protokoly z kontejneru nginx, pro který byl nakonfigurován Pipeline výše. Soubor protokolu obsahoval 406 624 řádků o celkovém objemu 109 MB. Protokoly byly generovány během jedné hodiny, přibližně 100 záznamů za sekundu.

Příklad dvou řádků z protokolu:

Sbírání logů od Lokiho

Při indexování ELK to poskytlo velikost indexu 30,3 MB:

Sbírání logů od Lokiho

V případě Lokiho to dalo asi 128 KB indexu a asi 3,8 MB dat v blocích. Stojí za zmínku, že protokol byl uměle vytvořen a neobsahoval širokou škálu dat. Jednoduchý gzip na původním protokolu Docker JSON s daty dal kompresi 95,4 % a vzhledem k tomu, že samotnému Lokimu byl odeslán pouze vyčištěný protokol nginx, je komprimace na 4 MB pochopitelná. Celkový počet jedinečných hodnot pro štítky Loki byl 35, což vysvětluje malou velikost indexu. U ELK byl protokol také vyčištěn. Loki tedy zkomprimoval původní data o 96 % a ELK o 70 %.

Spotřeba paměti

Sbírání logů od Lokiho

Pokud porovnáme celý stack Prometheus a ELK, pak Loki "žere" několikrát méně. Je jasné, že služba Go spotřebovává méně než služba Java a srovnání velikosti Heap Elasticsearch JVM a přidělené paměti pro Lokiho je nesprávné, ale přesto stojí za zmínku, že Loki používá mnohem méně paměti. Jeho výhoda CPU není tak zřejmá, ale je také přítomna.

Rychlost

Loki „hltá“ logy rychleji. Rychlost závisí na mnoha faktorech - jaké protokoly, jak sofistikovaně je analyzujeme, síť, disk atd. - ale rozhodně je vyšší než u ELK (v mém testu asi dvakrát). To je vysvětleno skutečností, že Loki vkládá do indexu mnohem méně dat, a proto tráví méně času indexováním. V tomto případě je situace s rychlostí vyhledávání obrácená: Loki znatelně zpomaluje na datech větších než pár gigabajtů, zatímco u ELK rychlost vyhledávání nezávisí na velikosti dat.

Hledání protokolu

Loki je výrazně horší než ELK, pokud jde o možnosti vyhledávání protokolů. Grep s regulárními výrazy je silná věc, ale je horší než databáze pro dospělé. Nedostatek dotazů na rozsah, agregace pouze podle štítků, nemožnost vyhledávání bez štítků - to vše nás omezuje při hledání informací, které nás zajímají v Loki. To neznamená, že pomocí Loki nelze nic najít, ale definuje tok práce s protokoly, kdy nejprve najdete problém v grafech Prometheus a poté pomocí těchto štítků hledáte, co se v protokolech stalo.

rozhraní

Za prvé, je to krásné (omlouvám se, nemohl jsem odolat). Grafana má pěkně vypadající rozhraní, ale Kibana je mnohem funkčnější.

Loki pro a proti

Z plusů lze poznamenat, že Loki se integruje s Prometheem, respektive dostáváme metriky a upozornění ihned po vybalení. Je vhodný pro shromažďování protokolů a jejich ukládání pomocí Kubernetes Pods, protože má zjišťování služby zděděné z Prometheus a automaticky připojuje štítky.

Z mínusů - špatná dokumentace. Některé věci, jako jsou funkce a možnosti Promtailu, jsem objevil až v procesu studia kódu, výhoda open-source. Další nevýhodou jsou slabé možnosti analýzy. Loki například nemůže analyzovat víceřádkové protokoly. Mezi nevýhody patří také skutečnost, že Loki je relativně mladá technologie (vydání 1.0 bylo v listopadu 2019).

Závěr

Loki je 100% zajímavá technologie, která je vhodná pro malé a střední projekty a umožňuje vám řešit mnoho problémů s agregací protokolů, vyhledáváním protokolů, monitorováním a analýzou protokolů.

Lokiho na Badoo nepoužíváme, protože máme ELK stack, který nám vyhovuje a který za ta léta zarostl různými zakázkovými řešeními. U nás je kamenem úrazu hledání v logech. S téměř 100 GB logů za den je pro nás důležité, abychom dokázali najít vše a ještě něco navíc a udělat to rychle. Pro vytváření grafů a monitorování používáme jiná řešení, která jsou přizpůsobena našim potřebám a vzájemně integrována. Loki stack má hmatatelné výhody, ale nedá nám víc, než co máme, a jeho výhody nebudou přesně převyšovat náklady na migraci.

A i když po průzkumu vyšlo najevo, že Lokiho použít nemůžeme, doufáme, že vám tento příspěvek pomůže při výběru.

Úložiště s kódem použitým v článku se nachází zde.

Zdroj: www.habr.com

Přidat komentář