Fluentd: Zašto je važno konfigurirati izlazni bafer

Fluentd: Zašto je važno konfigurirati izlazni bafer

Danas je nemoguće zamisliti projekat zasnovan na Kubernetesu bez ELK steka, koji čuva dnevnike aplikacija i sistemskih komponenti klastera. U našoj praksi koristimo EFK stack sa Fluentdom umjesto Logstash-om.

Fluentd je moderan, univerzalni sakupljač dnevnika koji dobija sve veću popularnost i pridružio se Cloud Native Computing Foundation, zbog čega je njegov vektor razvoja fokusiran na korištenje u sprezi sa Kubernetesom.

Činjenica da se Fluentd koristi umjesto Logstash-a ne mijenja opću suštinu softverskog paketa, međutim, Fluentd karakteriziraju svoje specifične nijanse koje proizlaze iz njegove svestranosti.

Na primjer, kada smo počeli koristiti EFK u zauzetom projektu s velikim intenzitetom logovanja, suočili smo se s činjenicom da su se u Kibani neke poruke prikazivale više puta. U ovom članku ćemo vam reći zašto se ovaj fenomen pojavljuje i kako riješiti problem.

Problem umnožavanja dokumenata

U našim projektima, Fluentd je raspoređen kao DaemonSet (automatski se pokreće u jednoj instanci na svakom čvoru Kubernetes klastera) i prati evidencije stdout kontejnera u /var/log/containers. Nakon prikupljanja i obrade, dnevnici u obliku JSON dokumenata se šalju ElasticSearch-u, podižu se u klaster ili samostalno, u zavisnosti od obima projekta i zahtjeva za performansama i tolerancijom grešaka. Kibana se koristi kao grafički interfejs.

Kada smo koristili Fluentd sa dodatkom za baferovanje izlaza, naišli smo na situaciju da neki dokumenti u ElasticSearch-u imaju potpuno isti sadržaj i razlikuju se samo po identifikatoru. Možete provjeriti je li ovo ponavljanje poruke koristeći Nginx dnevnik kao primjer. U log fajlu ova poruka postoji u jednoj kopiji:

127.0.0.1 192.168.0.1 - [28/Feb/2013:12:00:00 +0900] "GET / HTTP/1.1" 200 777 "-" "Opera/12.0" -

Međutim, postoji nekoliko dokumenata u ElasticSearch-u koji sadrže ovu poruku:

{
  "_index": "test-custom-prod-example-2020.01.02",
  "_type": "_doc",
  "_id": "HgGl_nIBR8C-2_33RlQV",
  "_version": 1,
  "_score": 0,
  "_source": {
    "service": "test-custom-prod-example",
    "container_name": "nginx",
    "namespace": "test-prod",
    "@timestamp": "2020-01-14T05:29:47.599052886 00:00",
    "log": "127.0.0.1 192.168.0.1 - [28/Feb/2013:12:00:00  0900] "GET / HTTP/1.1" 200 777 "-" "Opera/12.0" -",
    "tag": "custom-log"
  }
}

{
  "_index": "test-custom-prod-example-2020.01.02",
  "_type": "_doc",
  "_id": "IgGm_nIBR8C-2_33e2ST",
  "_version": 1,
  "_score": 0,
  "_source": {
    "service": "test-custom-prod-example",
    "container_name": "nginx",
    "namespace": "test-prod",
    "@timestamp": "2020-01-14T05:29:47.599052886 00:00",
    "log": "127.0.0.1 192.168.0.1 - [28/Feb/2013:12:00:00  0900] "GET / HTTP/1.1" 200 777 "-" "Opera/12.0" -",
    "tag": "custom-log"
  }
}

Štaviše, može biti više od dva ponavljanja.

Dok rješavate ovaj problem u Fluentd logovima, možete vidjeti veliki broj upozorenja sa sljedećim sadržajem:

2020-01-16 01:46:46 +0000 [warn]: [test-prod] failed to flush the buffer. retry_time=4 next_retry_seconds=2020-01-16 01:46:53 +0000 chunk="59c37fc3fb320608692c352802b973ce" error_class=Fluent::Plugin::ElasticsearchOutput::RecoverableRequestFailure error="could not push logs to Elasticsearch cluster ({:host=>"elasticsearch", :port=>9200, :scheme=>"http", :user=>"elastic", :password=>"obfuscated"}): read timeout reached"

Ova upozorenja se javljaju kada ElasticSearch ne može vratiti odgovor na zahtjev unutar vremena određenog parametrom request_timeout, zbog čega se proslijeđeni fragment međuspremnika ne može obrisati. Nakon toga, Fluentd pokušava ponovo poslati fragment međuspremnika u ElasticSearch i nakon proizvoljnog broja pokušaja, operacija se uspješno završava:

2020-01-16 01:47:05 +0000 [warn]: [test-prod] retry succeeded. chunk_id="59c37fc3fb320608692c352802b973ce" 
2020-01-16 01:47:05 +0000 [warn]: [test-prod] retry succeeded. chunk_id="59c37fad241ab300518b936e27200747" 
2020-01-16 01:47:05 +0000 [warn]: [test-dev] retry succeeded. chunk_id="59c37fc11f7ab707ca5de72a88321cc2" 
2020-01-16 01:47:05 +0000 [warn]: [test-dev] retry succeeded. chunk_id="59c37fb5adb70c06e649d8c108318c9b" 
2020-01-16 01:47:15 +0000 [warn]: [kube-system] retry succeeded. chunk_id="59c37f63a9046e6dff7e9987729be66f"

Međutim, ElasticSearch tretira svaki od prenesenih fragmenata bafera kao jedinstven i dodjeljuje im jedinstvene vrijednosti polja _id tokom indeksiranja. Ovako se pojavljuju kopije poruka.

U Kibani to izgleda ovako:

Fluentd: Zašto je važno konfigurirati izlazni bafer

Rešavanje problema

Postoji nekoliko opcija za rješavanje ovog problema. Jedan od njih je mehanizam ugrađen u dodatak fluent-plugin-elasticsearch za generisanje jedinstvenog hasha za svaki dokument. Ako koristite ovaj mehanizam, ElasticSearch će prepoznati ponavljanja u fazi prosljeđivanja i spriječiti dupliranje dokumenata. Ali moramo uzeti u obzir da se ovaj način rješavanja problema bori sa istraživanjem i ne otklanja grešku nedostatkom timeouta, pa smo odustali od njegove upotrebe.

Koristimo dodatak za međuspremnik na Fluentd izlazu kako bismo spriječili gubitak dnevnika u slučaju kratkoročnih problema s mrežom ili povećanog intenziteta evidentiranja. Ako iz nekog razloga ElasticSearch nije u mogućnosti trenutno upisati dokument u indeks, dokument se stavlja u red čekanja i pohranjuje na disk. Stoga je u našem slučaju, kako bi se otklonio izvor problema koji dovodi do gore opisane greške, potrebno postaviti ispravne vrijednosti za parametre baferiranja, pri čemu će izlazni bafer Fluentd biti dovoljne veličine i u isto vrijeme uspjeti da se očisti u zadanom vremenu.

Vrijedi napomenuti da su vrijednosti parametara o kojima se govori u nastavku individualne u svakom konkretnom slučaju korištenja međuspremnika u izlaznim dodacima, jer zavise od mnogih faktora: intenziteta pisanja poruka u dnevnik od strane usluga, performansi diskovnog sistema, mreže opterećenje kanala i njegov propusni opseg. Stoga, da biste dobili postavke bafera koje su prikladne za svaki pojedinačni slučaj, ali nisu redundantne, izbjegavajući naslijepo dugotrajno pretraživanje, možete koristiti informacije za otklanjanje grešaka koje Fluentd upisuje u svoj dnevnik tokom rada i relativno brzo dobiti ispravne vrijednosti.

U vrijeme kada je problem zabilježen, konfiguracija je izgledala ovako:

 <buffer>
        @type file
        path /var/log/fluentd-buffers/kubernetes.test.buffer
        flush_mode interval
        retry_type exponential_backoff
        flush_thread_count 2
        flush_interval 5s
        retry_forever
        retry_max_interval 30
        chunk_limit_size 8M
        queue_limit_length 8
        overflow_action block
      </buffer>

Prilikom rješavanja problema ručno su odabrane vrijednosti sljedećih parametara:
chunk_limit_size — veličina komada na koje su poruke u baferu podijeljene.

  • flush_interval — vremenski interval nakon kojeg se bafer briše.
  • queue_limit_length — maksimalni broj komada u redu čekanja.
  • request_timeout je vrijeme za koje se uspostavlja veza između Fluentd-a i ElasticSearch-a.

Ukupna veličina bafera može se izračunati množenjem parametara queue_limit_length i chunk_limit_size, što se može protumačiti kao „maksimalni broj komada u redu, od kojih svaki ima zadanu veličinu“. Ako veličina međuspremnika nije dovoljna, u evidenciji će se pojaviti sljedeće upozorenje:

2020-01-21 10:22:57 +0000 [warn]: [test-prod] failed to write data into buffer by buffer overflow action=:block

To znači da bafer nema vremena da se obriše u zadanom vremenu i da su podaci koji ulaze u puni bafer blokirani, što će dovesti do gubitka dijela dnevnika.

Međuspremnik možete povećati na dva načina: povećanjem veličine svakog dijela u redu ili broja dijelova koji mogu biti u redu.

Ako postavite veličinu komada chunk_limit_size na više od 32 megabajta, ElasticSeacrh to neće prihvatiti jer će dolazni paket biti prevelik. Stoga, ako trebate dodatno povećati bafer, bolje je povećati maksimalnu dužinu reda čekanja queue_limit_length.

Kada bafer prestane da se prelije i ostane samo poruka o nedostatku vremena čekanja, možete početi povećavati parametar request_timeout. Međutim, ako postavite vrijednost na više od 20 sekundi, sljedeća upozorenja će se početi pojavljivati ​​u Fluentd evidencijama:

2020-01-21 09:55:33 +0000 [warn]: [test-dev] buffer flush took longer time than slow_flush_log_threshold: elapsed_time=20.85753920301795 slow_flush_log_threshold=20.0 plugin_id="postgresql-dev" 

Ova poruka ni na koji način ne utječe na rad sistema i znači da je vrijeme ispiranja bafera trajalo duže nego što je postavljeno parametrom slow_flush_log_threshold. Ovo su informacije za otklanjanje grešaka i koristimo ih kada biramo vrijednost parametra request_timeout.

Generalizirani algoritam odabira je sljedeći:

  1. Postavite request_timeout na vrijednost za koju je zajamčeno da je veća od potrebne (stotine sekundi). Tokom podešavanja, glavni kriterijum za ispravno podešavanje ovog parametra biće nestanak upozorenja o nedostatku vremenskog ograničenja.
  2. Sačekajte poruke o prekoračenju praga slow_flush_log_threshold. Tekst upozorenja u polju elapsed_time će pokazati stvarno vrijeme kada je bafer obrisan.
  3. Postavite request_timeout na vrijednost veću od maksimalne vrijednosti elapsed_time dobivene tokom perioda promatranja. Vrijednost request_timeout izračunavamo kao elapsed_time + 50%.
  4. Da biste uklonili upozorenja o dugim ispuštanjima bafera iz dnevnika, možete podići vrijednost slow_flush_log_threshold. Ovu vrijednost izračunavamo kao proteklo_vrijeme + 25%.

Konačne vrijednosti ovih parametara, kao što je ranije navedeno, dobivaju se pojedinačno za svaki slučaj. Praćenjem gore navedenog algoritma garantovano ćemo eliminisati grešku koja dovodi do ponovljenih poruka.

Donja tabela pokazuje kako se broj grešaka dnevno, koje dovode do dupliciranja poruka, mijenja u procesu odabira vrijednosti gore opisanih parametara:

čvor-1
čvor-2
čvor-3
čvor-4

Prije poslije
Prije poslije
Prije poslije
Prije poslije

nije uspio isprati bafer
1749/2
694/2
47/0
1121/2

ponovni pokušaj je uspio
410/2
205/1
24/0
241/2

Vrijedi dodatno napomenuti da rezultirajuće postavke mogu izgubiti svoju relevantnost kako projekt raste i, shodno tome, povećava se broj dnevnika. Primarni znak nedovoljnog vremenskog ograničenja je vraćanje poruka o dugom pražnjenju bafera u Fluentd dnevnik, to jest, prekoračenje praga slow_flush_log_threshold. Od ovog trenutka ostaje još mala margina prije prekoračenja parametra request_timeout, pa je potrebno pravovremeno odgovoriti na ove poruke i ponoviti gore opisani postupak odabira optimalnih postavki.

zaključak

Fino podešavanje Fluentd izlaznog bafera je jedna od glavnih faza konfigurisanja EFK steka, određivanje stabilnosti njegovog rada i ispravnog postavljanja dokumenata u indekse. Na osnovu opisanog konfiguracionog algoritma, možete biti sigurni da će svi zapisi biti upisani u ElasticSearch indeks ispravnim redoslijedom, bez ponavljanja ili gubitaka.

Pročitajte i druge članke na našem blogu:

izvor: www.habr.com

Dodajte komentar