Fluentd: Kodėl svarbu sukonfigūruoti išvesties buferį

Fluentd: Kodėl svarbu sukonfigūruoti išvesties buferį

Šiais laikais neįmanoma įsivaizduoti „Kubernetes“ pagrįsto projekto be ELK krūvos, kuri išsaugo tiek programų, tiek klasterio sistemos komponentų žurnalus. Savo praktikoje mes naudojame EFK steką su Fluentd, o ne Logstash.

Fluentd yra modernus, universalus rąstų rinktuvas, kuris vis labiau populiarėja ir prisijungė prie Cloud Native Computing Foundation, todėl jo kūrimo vektorius yra orientuotas į naudojimą kartu su Kubernetes.

„Fluentd“ naudojimas vietoje „Logstash“ nekeičia bendros programinės įrangos paketo esmės, tačiau „Fluentd“ pasižymi specifiniais niuansais, atsirandančiais dėl jo universalumo.

Pavyzdžiui, kai pradėjome naudoti EFK intensyviame projekte su dideliu medienos ruošos intensyvumu, susidūrėme su tuo, kad Kibanoje kai kurie pranešimai buvo rodomi kelis kartus. Šiame straipsnyje mes jums pasakysime, kodėl šis reiškinys atsiranda ir kaip išspręsti problemą.

Dokumentų dubliavimo problema

Mūsų projektuose „Fluentd“ yra įdiegtas kaip „DaemonSet“ (automatiškai paleidžiamas vienu atveju kiekviename „Kubernetes“ klasterio mazge) ir stebi standartinių konteinerių žurnalus aplanke /var/log/containers. Po surinkimo ir apdorojimo žurnalai JSON dokumentų pavidalu siunčiami į ElasticSearch, iškeliami į grupę arba atskirą formą, atsižvelgiant į projekto mastą ir našumo bei gedimų tolerancijos reikalavimus. Kibana naudojama kaip grafinė sąsaja.

Naudodami Fluentd su išvesties buferio papildiniu, susidūrėme su situacija, kai kai kurie ElasticSearch dokumentai turėjo lygiai tokį patį turinį ir skyrėsi tik identifikatoriumi. Galite patikrinti, ar tai yra pranešimo kartojimas, naudodami Nginx žurnalą kaip pavyzdį. Žurnalo faile šis pranešimas yra vienoje kopijoje:

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

Tačiau ElasticSearch yra keli dokumentai, kuriuose yra šis pranešimas:

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

Be to, gali būti daugiau nei du pakartojimai.

Išspręsdami šią problemą „Fluentd“ žurnaluose, galite matyti daugybę įspėjimų su tokiu turiniu:

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"

Šie įspėjimai atsiranda, kai ElasticSearch negali atsakyti į užklausą per parametro request_timeout nurodytą laiką, todėl persiųsto buferio fragmento negalima išvalyti. Po to Fluentd vėl bando nusiųsti buferio fragmentą į ElasticSearch ir po tam tikro skaičiaus bandymų operacija sėkmingai baigiama:

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"

Tačiau „ElasticSearch“ kiekvieną perkeltą buferio fragmentą traktuoja kaip unikalų ir indeksavimo metu priskiria jiems unikalias _id lauko reikšmes. Taip atsiranda pranešimų kopijos.

Kibanoje tai atrodo taip:

Fluentd: Kodėl svarbu sukonfigūruoti išvesties buferį

Sprendimas

Yra keletas variantų, kaip išspręsti šią problemą. Vienas iš jų yra įskiepyje „fluent-plugin-elasticsearch“ įtaisytas mechanizmas, skirtas kiekvienam dokumentui generuoti unikalią maišą. Jei naudosite šį mechanizmą, ElasticSearch atpažins pasikartojimus persiuntimo etape ir užkirs kelią dokumentų pasikartojimui. Tačiau turime atsižvelgti į tai, kad šis problemos sprendimo būdas kovoja su tyrimu ir nepašalina klaidos, kai trūksta laiko, todėl atsisakėme jo naudojimo.

Fluentd išvestyje naudojame buferio papildinį, kad išvengtume žurnalo praradimo trumpalaikių tinklo problemų arba padidėjus registravimo intensyvumui. Jei dėl kokių nors priežasčių ElasticSearch negali akimirksniu įrašyti dokumento į rodyklę, dokumentas įtraukiamas į eilę ir saugomas diske. Todėl mūsų atveju, norint pašalinti problemos šaltinį, dėl kurio atsiranda aukščiau aprašyta klaida, būtina nustatyti teisingas buferio parametrų reikšmes, kurioms esant Fluentd išvesties buferis bus pakankamo dydžio ir tuo pačiu pavyksta išvalyti per skirtą laiką.

Verta paminėti, kad žemiau aptartų parametrų reikšmės yra individualios kiekvienu konkrečiu buferio naudojimo išvesties papildiniuose atveju, nes priklauso nuo daugelio veiksnių: pranešimų rašymo į žurnalą intensyvumo pagal paslaugas, disko sistemos našumo, tinklo. kanalo apkrova ir jos pralaidumas. Todėl norėdami gauti kiekvienam konkrečiam atvejui tinkamus, bet ne perteklinius buferio nustatymus, aklai išvengdami ilgų paieškų, galite naudoti derinimo informaciją, kurią Fluentd įrašo į savo žurnalą veikimo metu ir gana greitai gauti teisingas reikšmes.

Tuo metu, kai problema buvo įrašyta, konfigūracija atrodė taip:

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

Sprendžiant problemą rankiniu būdu buvo pasirinktos šių parametrų reikšmės:
chunk_limit_size – gabalų, į kuriuos padalyti pranešimai buferyje, dydis.

  • flush_interval – laiko intervalas, po kurio išvalomas buferis.
  • queue_limit_length – maksimalus gabalų skaičius eilėje.
  • request_timeout yra laikas, per kurį užmezgamas ryšys tarp Fluentd ir ElasticSearch.

Bendrą buferio dydį galima apskaičiuoti padauginus parametrus queue_limit_length ir chunk_limit_size, kurie gali būti interpretuojami kaip „maksimalus eilėje esančių dalių skaičius, kurių kiekvienas turi tam tikrą dydį“. Jei buferio dydis yra nepakankamas, žurnaluose pasirodys šis įspėjimas:

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

Tai reiškia, kad buferis nespėja išvalyti per numatytą laiką, o duomenys, patenkantys į visą buferį, yra blokuojami, o tai lems dalies žurnalų praradimą.

Buferį galite padidinti dviem būdais: padidindami kiekvienos eilės dalies dydį arba eilėje galinčių būti dalių skaičių.

Jei chunk_limit_size gabalo dydį nustatote daugiau nei 32 megabaitus, ElasticSeacrh jo nepriims, nes gaunamas paketas bus per didelis. Todėl, jei reikia dar padidinti buferį, geriau padidinti maksimalų eilės ilgį queue_limit_length.

Kai buferis nustoja perpildyti ir lieka tik pranešimas apie laiko pabaigos nepakanka, galite pradėti didinti užklausos_laiko pabaigos parametrą. Tačiau jei nustatysite reikšmę ilgesnę nei 20 sekundžių, Fluentd žurnaluose bus rodomi šie įspėjimai:

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" 

Šis pranešimas niekaip neįtakoja sistemos veikimo ir reiškia, kad buferio praplovimo laikas užtruko ilgiau, nei nustatytas parametru slow_flush_log_threshold. Tai yra derinimo informacija, kurią naudojame pasirinkdami parametro request_timeout reikšmę.

Apibendrintas atrankos algoritmas yra toks:

  1. Nustatykite užklausos_laiką į vertę, kuri garantuotai bus didesnė nei būtina (šimtai sekundžių). Sąrankos metu pagrindinis teisingo šio parametro nustatymo kriterijus bus įspėjimų apie skirtojo laiko trūkumą išnykimas.
  2. Palaukite pranešimų apie slow_flush_log_threshold slenksčio viršijimą. Įspėjamasis tekstas lauke „elapsed_time“ parodys tikrąjį buferio išvalymo laiką.
  3. Nustatykite užklausos_laiką vertę, didesnę nei didžiausia praėjusio laiko reikšmė, gauta per stebėjimo laikotarpį. Apskaičiuojame užklausos_laiko pabaigos reikšmę kaip praėjęs_laikas + 50%.
  4. Norėdami pašalinti įspėjimus apie ilgus buferio praplovimus iš žurnalo, galite padidinti slow_flush_log_threshold reikšmę. Šią reikšmę apskaičiuojame kaip praėjęs laikas + 25%.

Galutinės šių parametrų vertės, kaip minėta anksčiau, kiekvienu atveju gaunamos atskirai. Laikydamiesi aukščiau pateikto algoritmo, garantuojame, kad pašalinsime klaidą, dėl kurios pasikartojantys pranešimai.

Žemiau esančioje lentelėje parodyta, kaip keičiasi klaidų per dieną, dėl kurių dubliuojami pranešimai, skaičius pasirenkant aukščiau aprašytų parametrų reikšmes:

mazgas-1
mazgas-2
mazgas-3
mazgas-4

Prieš po
Prieš po
Prieš po
Prieš po

nepavyko nuplauti buferio
1749/2
694/2
47/0
1121/2

bandyti pakartoti pavyko
410/2
205/1
24/0
241/2

Verta papildomai pažymėti, kad gauti nustatymai gali prarasti savo aktualumą, kai projektas auga ir atitinkamai didėja žurnalų skaičius. Pagrindinis nepakankamo skirtojo laiko požymis yra pranešimų apie ilgą buferio praplovimą grįžimas į Fluentd žurnalą, tai yra, viršijantis slow_flush_log_threshold slenkstį. Nuo šio momento iki request_timeout parametro viršijimo vis dar yra nedidelė marža, todėl būtina laiku atsakyti į šiuos pranešimus ir pakartoti aukščiau aprašytą optimalių nustatymų parinkimo procesą.

išvada

Tikslus Fluentd išvesties buferio derinimas yra vienas iš pagrindinių EFK kamino konfigūravimo etapų, nustatantis jo veikimo stabilumą ir teisingą dokumentų išdėstymą indeksuose. Remiantis aprašytu konfigūravimo algoritmu, galite būti tikri, kad visi žurnalai bus įrašyti į ElasticSearch indeksą teisinga tvarka, be pasikartojimų ir nuostolių.

Taip pat skaitykite kitus mūsų tinklaraščio straipsnius:

Šaltinis: www.habr.com

Добавить комментарий