Fluentd: Hvorfor det er viktig å konfigurere utgangsbufferen

Fluentd: Hvorfor det er viktig å konfigurere utgangsbufferen

I dag er det umulig å forestille seg et Kubernetes-basert prosjekt uten ELK-stakken, som lagrer logger av både applikasjoner og systemkomponenter i klyngen. I vår praksis bruker vi EFK-stakken med Fluentd i stedet for Logstash.

Fluentd er en moderne, universell loggsamler som blir mer og mer populær og har sluttet seg til Cloud Native Computing Foundation, som er grunnen til at utviklingsvektoren er fokusert på bruk sammen med Kubernetes.

Det faktum å bruke Fluentd i stedet for Logstash endrer ikke den generelle essensen av programvarepakken, men Fluentd er preget av sine egne spesifikke nyanser som følge av dens allsidighet.

For eksempel, da vi begynte å bruke EFK i et travelt prosjekt med høy loggintensitet, ble vi møtt med det faktum at i Kibana ble noen meldinger vist gjentatte ganger flere ganger. I denne artikkelen vil vi fortelle deg hvorfor dette fenomenet oppstår og hvordan du løser problemet.

Problemet med dokumentduplisering

I våre prosjekter er Fluentd distribuert som et DaemonSet (automatisk lansert i én instans på hver node i Kubernetes-klyngen) og overvåker stdout-beholderlogger i /var/log/containers. Etter innsamling og behandling sendes loggene i form av JSON-dokumenter til ElasticSearch, hevet i klynge eller frittstående form, avhengig av prosjektets omfang og kravene til ytelse og feiltoleranse. Kibana brukes som det grafiske grensesnittet.

Når vi brukte Fluentd med en utgangsbuffer-plugin, møtte vi en situasjon der noen dokumenter i ElasticSearch hadde nøyaktig det samme innholdet og bare skilte seg i identifikatoren. Du kan bekrefte at dette er en meldingsrepetisjon ved å bruke Nginx-loggen som eksempel. I loggfilen finnes denne meldingen i en enkelt kopi:

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

Det er imidlertid flere dokumenter i ElasticSearch som inneholder denne meldingen:

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

Dessuten kan det være mer enn to repetisjoner.

Mens du fikser dette problemet i Fluentd-loggene, kan du se et stort antall advarsler med følgende innhold:

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"

Disse advarslene oppstår når ElasticSearch ikke kan returnere et svar på en forespørsel innen tiden spesifisert av parameteren request_timeout, og det er grunnen til at det videresendte bufferfragmentet ikke kan slettes. Etter dette prøver Fluentd å sende bufferfragmentet til ElasticSearch igjen, og etter et vilkårlig antall forsøk fullføres operasjonen vellykket:

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"

Imidlertid behandler ElasticSearch hvert av de overførte bufferfragmentene som unike og tildeler dem unike _id-feltverdier under indeksering. Slik vises kopier av meldinger.

I Kibana ser det slik ut:

Fluentd: Hvorfor det er viktig å konfigurere utgangsbufferen

Løsningen

Det er flere alternativer for å løse dette problemet. En av dem er mekanismen innebygd i fluent-plugin-elasticsearch-pluginen for å generere en unik hash for hvert dokument. Hvis du bruker denne mekanismen, vil ElasticSearch gjenkjenne repetisjoner på videresendingsstadiet og forhindre dupliserte dokumenter. Men vi må ta hensyn til at denne metoden for å løse problemet sliter med etterforskningen og ikke eliminerer feilen med manglende tidsavbrudd, så vi forlot bruken.

Vi bruker en buffer-plugin på Fluentd-utgangen for å forhindre loggtap ved kortvarige nettverksproblemer eller økt loggingsintensitet. Hvis ElasticSearch av en eller annen grunn ikke er i stand til å umiddelbart skrive et dokument til indeksen, settes dokumentet i kø og lagres på disk. Derfor, i vårt tilfelle, for å eliminere kilden til problemet som fører til feilen beskrevet ovenfor, er det nødvendig å angi de riktige verdiene for bufferparameterne, der Fluentd-utgangsbufferen vil være av tilstrekkelig størrelse og samtidig klare å bli klarert i tildelt tid.

Det er verdt å merke seg at verdiene til parameterne diskutert nedenfor er individuelle i hvert enkelt tilfelle av bruk av bufring i utdataplugins, da de avhenger av mange faktorer: intensiteten av å skrive meldinger til loggen etter tjenester, disksystemytelse, nettverk kanalbelastning og dens båndbredde. For å oppnå bufferinnstillinger som er egnet for hvert enkelt tilfelle, men ikke overflødige, og unngå lange søk i blinde, kan du bruke feilsøkingsinformasjonen som Fluentd skriver til loggen sin under drift og relativt raskt få de riktige verdiene.

På det tidspunktet problemet ble registrert, så konfigurasjonen slik ut:

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

Når du løste problemet, ble verdiene til følgende parametere valgt manuelt:
chunk_limit_size — størrelsen på delene som meldinger i bufferen er delt inn i.

  • flush_interval — tidsintervall etter hvilket bufferen tømmes.
  • queue_limit_length — det maksimale antallet biter i køen.
  • request_timeout er tiden som forbindelsen mellom Fluentd og ElasticSearch er etablert.

Den totale bufferstørrelsen kan beregnes ved å multiplisere parameterne queue_limit_length og chunk_limit_size, som kan tolkes som "maksimalt antall biter i køen, som hver har en gitt størrelse." Hvis bufferstørrelsen er utilstrekkelig, vil følgende advarsel vises i loggene:

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

Det betyr at bufferen ikke rekker å tømmes i den tildelte tiden og dataene som kommer inn i hele bufferen blokkeres, noe som vil føre til tap av deler av loggene.

Du kan øke bufferen på to måter: ved å øke enten størrelsen på hver del i køen, eller antall biter som kan være i køen.

Hvis du setter chunk size chunk_limit_size til mer enn 32 megabyte, vil ikke ElasticSeacrh godta det, siden den innkommende pakken vil være for stor. Derfor, hvis du trenger å øke bufferen ytterligere, er det bedre å øke den maksimale kølengden queue_limit_length.

Når bufferen slutter å renne over og bare meldingen om utilstrekkelig tidsavbrudd gjenstår, kan du begynne å øke parameteren request_timeout. Men hvis du setter verdien til mer enn 20 sekunder, vil følgende advarsler begynne å vises i Fluentd-loggene:

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" 

Denne meldingen påvirker ikke driften av systemet på noen måte og betyr at bufferspylingstiden tok lengre tid enn satt av parameteren slow_flush_log_threshold. Dette er feilsøkingsinformasjon, og vi bruker den når vi velger verdien av parameteren request_timeout.

Den generaliserte utvalgsalgoritmen er som følger:

  1. Sett request_timeout til en verdi som garantert er større enn nødvendig (hundrevis av sekunder). Under oppsettet vil hovedkriteriet for riktig innstilling av denne parameteren være at advarsler forsvinner på grunn av manglende tidsavbrudd.
  2. Vent på meldinger om overskridelse av slow_flush_log_threshold-terskelen. Advarselsteksten i elapsed_time-feltet vil vise sanntiden bufferen ble tømt.
  3. Sett request_timeout til en verdi som er større enn den maksimale elapsed_time-verdien som ble oppnådd i løpet av observasjonsperioden. Vi beregner request_timeout-verdien som elapsed_time + 50 %.
  4. For å fjerne advarsler om lange bufferspylinger fra loggen, kan du øke verdien av slow_flush_log_threshold. Vi beregner denne verdien som medgått_tid + 25 %.

De endelige verdiene for disse parameterne, som nevnt tidligere, oppnås individuelt for hvert tilfelle. Ved å følge algoritmen ovenfor, er vi garantert å eliminere feilen som fører til gjentatte meldinger.

Tabellen nedenfor viser hvordan antall feil per dag, som fører til duplisering av meldinger, endringer i prosessen med å velge verdiene til parameterne beskrevet ovenfor:

node-1
node-2
node-3
node-4

Før etter
Før etter
Før etter
Før etter

klarte ikke å tømme bufferen
1749/2
694/2
47/0
1121/2

nytt forsøk lyktes
410/2
205/1
24/0
241/2

Det er i tillegg verdt å merke seg at de resulterende innstillingene kan miste sin relevans etter hvert som prosjektet vokser, og følgelig øker antallet logger. Det primære tegnet på utilstrekkelig tidsavbrudd er retur av meldinger om en lang bufferflush til Fluentd-loggen, det vil si overskridelse av slow_flush_log_threshold-terskelen. Fra dette tidspunktet er det fortsatt en liten margin før parameteren request_timeout overskrides, så det er nødvendig å svare på disse meldingene i tide og gjenta prosessen med å velge de optimale innstillingene beskrevet ovenfor.

Konklusjon

Finjustering av Fluentd-utgangsbufferen er et av hovedstadiene for å konfigurere EFK-stakken, bestemme stabiliteten til driften og riktig plassering av dokumenter i indekser. Basert på den beskrevne konfigurasjonsalgoritmen kan du være sikker på at alle logger blir skrevet til ElasticSearch-indeksen i riktig rekkefølge, uten repetisjoner eller tap.

Les også andre artikler på bloggen vår:

Kilde: www.habr.com

Legg til en kommentar