Fluentd: Zašto je važno konfigurirati izlazni međuspremnik

Fluentd: Zašto je važno konfigurirati izlazni međuspremnik

U današnje vrijeme nemoguće je zamisliti projekt temeljen na Kubernetesu bez ELK stoga koji sprema zapise i aplikacija i sistemskih komponenti klastera. U našoj praksi koristimo EFK stog s Fluentdom umjesto Logstasha.

Fluentd je moderan, univerzalni log collector koji dobiva sve veću popularnost te se pridružio Cloud Native Computing Foundation, zbog čega je njegov razvojni vektor usmjeren na korištenje u kombinaciji s Kubernetesom.

Činjenica korištenja Fluentd-a umjesto Logstasha ne mijenja opću bit softverskog paketa, međutim, Fluentd karakteriziraju svoje specifične nijanse koje proizlaze iz njegove svestranosti.

Na primjer, kada smo počeli koristiti EFK u prometnom projektu s velikim intenzitetom zapisivanja, 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 implementiran kao DaemonSet (automatski se pokreće u jednoj instanci na svakom čvoru Kubernetes klastera) i nadzire zapisnike spremnika stdout u /var/log/containers. Nakon prikupljanja i obrade, zapisnici u obliku JSON dokumenata šalju se ElasticSearchu, podignuti u obliku klastera ili samostalnom obliku, ovisno o veličini projekta i zahtjevima za performansama i tolerancijom na greške. Kibana se koristi kao grafičko sučelje.

Kada smo koristili Fluentd s dodatkom za međuspremnik izlaza, naišli smo na situaciju u kojoj su neki dokumenti u ElasticSearchu imali potpuno isti sadržaj i razlikovali su se samo u identifikatoru. Možete potvrditi da se radi o ponavljanju poruke koristeći Nginx zapisnik kao primjer. U log datoteci 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 ElasticSearchu 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"
  }
}

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

Dok rješavate ovaj problem u Fluentd zapisima, 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 pojavljuju 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 ponovno pokušava 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 međuspremnika kao jedinstven i dodjeljuje im jedinstvene vrijednosti polja _id tijekom indeksiranja. Ovako se pojavljuju kopije poruka.

U Kibani to izgleda ovako:

Fluentd: Zašto je važno konfigurirati izlazni međuspremnik

Rješenje

Postoji nekoliko opcija za rješavanje ovog problema. Jedan od njih je mehanizam ugrađen u dodatak fluent-plugin-elasticsearch za generiranje jedinstvenog hasha za svaki dokument. Ako koristite ovaj mehanizam, ElasticSearch će prepoznati ponavljanja u fazi prosljeđivanja i spriječiti dvostruke dokumente. Ali moramo uzeti u obzir da se ova metoda rješavanja problema bori s istragom i ne uklanja pogrešku s nedostatkom vremena pa smo odustali od njezine upotrebe.

Koristimo dodatak za međuspremnik na Fluentd izlazu kako bismo spriječili gubitak zapisa u slučaju kratkoročnih problema s mrežom ili povećanog intenziteta zapisivanja. Ako iz nekog razloga ElasticSearch ne može odmah napisati dokument u indeks, dokument se stavlja u red čekanja i pohranjuje na disk. Stoga, u našem slučaju, kako bi se eliminirao izvor problema koji dovodi do gore opisane pogreške, potrebno je postaviti ispravne vrijednosti za parametre međuspremnika, pri kojima će Fluentd izlazni međuspremnik biti dovoljne veličine i u isto vrijeme uspjeti biti očišćeni u zadanom vremenu.

Vrijedno je napomenuti da su vrijednosti parametara koji se razmatraju u nastavku individualne u svakom konkretnom slučaju korištenja međuspremnika u izlaznim dodacima, jer ovise o mnogim čimbenicima: intenzitetu pisanja poruka u dnevnik po uslugama, performansama diskovnog sustava, mreži opterećenje kanala i njegovu propusnost. Stoga, kako biste dobili postavke međuspremnika koje su prikladne za svaki pojedinačni slučaj, ali ne i suvišne, izbjegavajući dugotrajna pretraživanja naslijepo, možete koristiti informacije o ispravljanju pogrešaka koje Fluentd zapisuje u svoj dnevnik tijekom rada i relativno brzo dobiti ispravne vrijednosti.

U trenutku 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 dijelova u koje su podijeljene poruke u međuspremniku.

  • flush_interval — vremenski interval nakon kojeg se međuspremnik čisti.
  • queue_limit_length — maksimalni broj dijelova u redu čekanja.
  • request_timeout je vrijeme za koje se uspostavlja veza između Fluentd i ElasticSearch.

Ukupna veličina međuspremnika može se izračunati množenjem parametara queue_limit_length i chunk_limit_size, koji se mogu protumačiti kao "maksimalni broj dijelova u redu čekanja, od kojih svaki ima zadanu veličinu." Ako je veličina međuspremnika nedovoljna, u zapisnicima ć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 međuspremnik nema vremena za brisanje u dodijeljenom vremenu i podaci koji ulaze u puni međuspremnik su blokirani, što će dovesti do gubitka dijela zapisa.

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

Ako postavite veličinu bloka chunk_limit_size na više od 32 megabajta, ElasticSeacrh ga neće prihvatiti jer će dolazni paket biti prevelik. Stoga, ako trebate dodatno povećati međuspremnik, bolje je povećati maksimalnu duljinu reda čekanja queue_limit_length.

Kada se međuspremnik prestane prelijevati 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 će se upozorenja početi pojavljivati ​​u zapisima Fluentd:

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 sustava i znači da je vrijeme ispiranja međuspremnika trajalo duže nego što je postavljeno parametrom slow_flush_log_threshold. Ovo su informacije o otklanjanju pogrešaka i koristimo ih pri odabiru vrijednosti parametra request_timeout.

Generalizirani algoritam odabira je sljedeći:

  1. Postavite request_timeout na vrijednost koja će zajamčeno biti veća od potrebne (stotine sekundi). Tijekom postavljanja, glavni kriterij za ispravnu postavku ovog parametra bit će nestanak upozorenja o nedostatku vremenskog ograničenja.
  2. Pričekajte poruke o prekoračenju praga slow_flush_log_threshold. Tekst upozorenja u polju elapsed_time prikazat će stvarno vrijeme kada je međuspremnik očišćen.
  3. Postavite request_timeout na vrijednost veću od maksimalne vrijednosti elapsed_time dobivene tijekom razdoblja promatranja. Vrijednost request_timeout izračunavamo kao elapsed_time + 50%.
  4. Da biste uklonili upozorenja o dugim ispiranjima međuspremnika iz dnevnika, možete povećati vrijednost slow_flush_log_threshold. Tu 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. Slijedeći gore navedeni algoritam, zajamčeno je da ćemo eliminirati pogrešku koja dovodi do ponovljenih poruka.

Donja tablica pokazuje kako se broj pogrešaka po danu, 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 međuspremnik
1749/2
694/2
47/0
1121/2

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

Vrijedno je dodatno napomenuti da dobivene postavke mogu izgubiti na važnosti kako projekt raste i, sukladno tome, povećava se broj dnevnika. Primarni znak nedovoljnog vremenskog ograničenja vraćanje je poruka o dugom ispiranju međuspremnika u dnevnik Fluentd, odnosno prekoračenje praga slow_flush_log_threshold. Od ovog trenutka postoji još mala margina prije prekoračenja parametra request_timeout, stoga je potrebno pravovremeno odgovoriti na ove poruke i ponoviti gore opisani postupak odabira optimalnih postavki.

Zaključak

Fino podešavanje izlaznog međuspremnika Fluentd jedna je od glavnih faza konfiguriranja EFK stoga, utvrđivanje stabilnosti njegovog rada i ispravnog postavljanja dokumenata u indekse. Na temelju opisanog konfiguracijskog algoritma, možete biti sigurni da će svi dnevnici biti zapisani u ElasticSearch indeks ispravnim redoslijedom, bez ponavljanja ili gubitaka.

Također pročitajte ostale članke na našem blogu:

Izvor: www.habr.com

Dodajte komentar