Fluentd: Zakaj je pomembno konfigurirati izhodni medpomnilnik

Fluentd: Zakaj je pomembno konfigurirati izhodni medpomnilnik

Dandanes si je nemogoče predstavljati Kubernetes temelječ projekt brez sklada ELK, ki shranjuje dnevnike tako aplikacij kot sistemskih komponent gruče. V naši praksi uporabljamo sklad EFK s Fluentd namesto Logstash.

Fluentd je sodoben univerzalni zbiralnik dnevnikov, ki postaja vedno bolj priljubljen in se je pridružil Cloud Native Computing Foundation, zato je njegov razvojni vektor usmerjen v uporabo v povezavi s Kubernetesom.

Dejstvo, da uporabljamo Fluentd namesto Logstash, ne spremeni splošnega bistva programskega paketa, kljub temu pa so za Fluentd značilne lastne specifične nianse, ki izhajajo iz njegove vsestranskosti.

Na primer, ko smo začeli uporabljati EFK v napornem projektu z visoko intenzivnostjo beleženja, smo se soočili z dejstvom, da so bila v Kibani nekatera sporočila prikazana večkrat. V tem članku vam bomo povedali, zakaj se ta pojav pojavi in ​​kako rešiti težavo.

Problem podvajanja dokumentov

V naših projektih je Fluentd razporejen kot DaemonSet (samodejno zagnan v enem primeru na vsakem vozlišču gruče Kubernetes) in spremlja dnevnike vsebnika stdout v /var/log/containers. Po zbiranju in obdelavi se dnevniki v obliki dokumentov JSON pošljejo v ElasticSearch, dvignjeni v obliki gruče ali samostojni obliki, odvisno od obsega projekta in zahtev glede zmogljivosti in tolerance napak. Kibana se uporablja kot grafični vmesnik.

Pri uporabi Fluentd z vtičnikom za medpomnilnik izhoda smo naleteli na situacijo, ko so imeli nekateri dokumenti v ElasticSearch popolnoma enako vsebino in so se razlikovali samo v identifikatorju. Na primeru dnevnika Nginx lahko preverite, ali gre za ponavljanje sporočila. V dnevniški datoteki je to sporočilo v eni sami 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" -

Vendar obstaja več dokumentov v ElasticSearch, ki vsebujejo to sporočilo:

{
  "_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"
  }
}

Poleg tega sta lahko več kot dve ponovitvi.

Med odpravljanjem te težave v dnevnikih Fluentd lahko vidite veliko število opozoril z naslednjo vsebino:

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"

Ta opozorila se pojavijo, ko ElasticSearch ne more vrniti odgovora na zahtevo v času, določenem s parametrom request_timeout, zaradi česar posredovanega fragmenta medpomnilnika ni mogoče počistiti. Po tem poskusi Fluentd ponovno poslati fragment vmesnega pomnilnika v ElasticSearch in po poljubnem številu poskusov se operacija uspešno zaključi:

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"

Vendar pa ElasticSearch vsakega od prenesenih fragmentov vmesnega pomnilnika obravnava kot edinstvenega in mu med indeksiranjem dodeli edinstvene vrednosti polja _id. Tako se prikažejo kopije sporočil.

V Kibani je videti takole:

Fluentd: Zakaj je pomembno konfigurirati izhodni medpomnilnik

Rešitev

Obstaja več možnosti za rešitev te težave. Eden od njih je mehanizem, vgrajen v vtičnik fluent-plugin-elasticsearch za generiranje edinstvene zgoščene vrednosti za vsak dokument. Če uporabite ta mehanizem, bo ElasticSearch prepoznal ponavljanja v fazi posredovanja in preprečil podvojene dokumente. Upoštevati pa moramo, da se ta način reševanja problema spopada s preiskavo in ne odpravi napake s pomanjkanjem časovne omejitve, zato smo njegovo uporabo opustili.

Na izhodu Fluentd uporabljamo vtičnik za medpomnjenje, da preprečimo izgubo dnevnika v primeru kratkotrajnih težav z omrežjem ali povečane intenzivnosti beleženja. Če iz nekega razloga ElasticSearch ne more takoj zapisati dokumenta v indeks, se dokument postavi v čakalno vrsto in shrani na disk. Zato je v našem primeru za odpravo vira težave, ki vodi do zgoraj opisane napake, potrebno nastaviti pravilne vrednosti za parametre medpomnilnika, pri katerih bo izhodni medpomnilnik Fluentd zadostne velikosti in hkrati uspejo biti očiščeni v dodeljenem času.

Omeniti velja, da so vrednosti spodaj obravnavanih parametrov individualne v vsakem posameznem primeru uporabe medpomnilnika v izhodnih vtičnikih, saj so odvisne od številnih dejavnikov: intenzivnosti pisanja sporočil v dnevnik po storitvah, zmogljivosti diskovnega sistema, omrežja obremenitev kanala in njegovo pasovno širino. Če želite torej pridobiti nastavitve vmesnega pomnilnika, ki so primerne za vsak posamezen primer, vendar ne odvečne, s čimer se slepo izognete dolgotrajnemu iskanju, lahko uporabite informacije o odpravljanju napak, ki jih Fluentd zapiše v svoj dnevnik med delovanjem, in razmeroma hitro pridobite pravilne vrednosti.

V času, ko je bila težava zabeležena, je konfiguracija izgledala takole:

 <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>

Pri reševanju problema so bile ročno izbrane vrednosti naslednjih parametrov:
chunk_limit_size — velikost kosov, na katere so razdeljena sporočila v medpomnilniku.

  • flush_interval — časovni interval, po katerem se vmesni pomnilnik počisti.
  • queue_limit_length — največje število kosov v čakalni vrsti.
  • request_timeout je čas, za katerega je vzpostavljena povezava med Fluentd in ElasticSearch.

Skupno velikost vmesnega pomnilnika je mogoče izračunati z množenjem parametrov queue_limit_length in chunk_limit_size, ki ju je mogoče interpretirati kot "največje število kosov v čakalni vrsti, od katerih ima vsak določeno velikost." Če velikost vmesnega pomnilnika ni zadostna, se bo v dnevnikih pojavilo naslednje opozorilo:

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

To pomeni, da medpomnilnik nima časa za čiščenje v dodeljenem času in da so podatki, ki vstopijo v polni medpomnilnik, blokirani, kar bo povzročilo izgubo dela dnevnikov.

Medpomnilnik lahko povečate na dva načina: s povečanjem velikosti vsakega kosa v čakalni vrsti ali števila kosov, ki so lahko v čakalni vrsti.

Če nastavite velikost kosa chunk_limit_size na več kot 32 megabajtov, je ElasticSeacrh ne bo sprejel, ker bo dohodni paket prevelik. Če morate torej medpomnilnik še povečati, je bolje povečati največjo dolžino čakalne vrste queue_limit_length.

Ko se vmesni pomnilnik preneha prepolnjevati in ostane samo sporočilo o prenizki časovni omejitvi, lahko začnete povečevati parameter request_timeout. Če pa vrednost nastavite na več kot 20 sekund, se bodo v dnevnikih Fluentd začela pojavljati naslednja opozorila:

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" 

To sporočilo na noben način ne vpliva na delovanje sistema in pomeni, da je čas izpiranja medpomnilnika trajal dlje, kot je nastavljeno s parametrom slow_flush_log_threshold. To so informacije za odpravljanje napak in jih uporabljamo, ko izbiramo vrednost parametra request_timeout.

Splošni izbirni algoritem je naslednji:

  1. Nastavite request_timeout na vrednost, ki bo zajamčeno večja od potrebne (stotine sekund). Med nastavitvijo bo glavno merilo za pravilno nastavitev tega parametra izginotje opozoril o pomanjkanju časovne omejitve.
  2. Počakajte na sporočila o prekoračitvi praga slow_flush_log_threshold. Besedilo opozorila v polju elapsed_time bo prikazalo realni čas, ko je bil medpomnilnik počiščen.
  3. Nastavite request_timeout na vrednost, ki je večja od največje vrednosti elapsed_time, pridobljene med obdobjem opazovanja. Vrednost request_timeout izračunamo kot elapsed_time + 50 %.
  4. Če želite iz dnevnika odstraniti opozorila o dolgih splakovanjih medpomnilnika, lahko zvišate vrednost slow_flush_log_threshold. To vrednost izračunamo kot elapsed_time + 25 %.

Končne vrednosti teh parametrov, kot smo že omenili, se pridobijo za vsak primer posebej. Z upoštevanjem zgornjega algoritma bomo zagotovo odpravili napako, ki vodi do ponavljajočih se sporočil.

Spodnja tabela prikazuje, kako se število napak na dan, ki vodijo do podvajanja sporočil, spreminja v procesu izbire vrednosti zgoraj opisanih parametrov:

vozlišče-1
vozlišče-2
vozlišče-3
vozlišče-4

Prej potem
Prej potem
Prej potem
Prej potem

ni uspelo izprazniti medpomnilnika
1749/2
694/2
47/0
1121/2

ponovni poskus uspel
410/2
205/1
24/0
241/2

Dodatno je treba opozoriti, da lahko nastale nastavitve izgubijo svojo pomembnost, ko projekt raste in posledično se poveča število dnevnikov. Primarni znak nezadostne časovne omejitve je vračanje sporočil o dolgem praznjenju medpomnilnika v dnevnik Fluentd, to je preseganje praga slow_flush_log_threshold. Od te točke naprej je še vedno majhna rezerva do preseženega parametra request_timeout, zato je potrebno na ta sporočila pravočasno odgovoriti in ponoviti zgoraj opisani postopek izbire optimalnih nastavitev.

Zaključek

Natančna nastavitev izhodnega medpomnilnika Fluentd je ena glavnih stopenj konfiguracije sklada EFK, ki določa stabilnost njegovega delovanja in pravilno postavitev dokumentov v indekse. Na podlagi opisanega konfiguracijskega algoritma ste lahko prepričani, da bodo vsi dnevniki zapisani v indeks ElasticSearch v pravilnem vrstnem redu, brez ponovitev ali izgub.

Preberite tudi druge članke na našem blogu:

Vir: www.habr.com

Dodaj komentar