Fluentd: varför det Àr viktigt att stÀlla in utmatningsbufferten

Fluentd: varför det Àr viktigt att stÀlla in utmatningsbufferten

I dagens lÀge Àr det omöjligt att förestÀlla sig ett projekt baserat pÄ Kubernetes utan ELK-stacken, som anvÀnds för att spara loggar frÄn bÄde applikationer och systemkomponenter i klustret. I vÄr praktik anvÀnder vi EFK-stacken med Fluentd istÀllet för Logstash.

Fluentd Àr en modern och mÄngsidig loggkollektor som vinner allt mer popularitet och har anslutit sig till Cloud Native Computing Foundation, vilket innebÀr att dess utvecklingsinriktning Àr fokuserad pÄ anvÀndning tillsammans med Kubernetes.

Faktum Àr att anvÀndningen av Fluentd istÀllet för Logstash inte förÀndrar den övergripande funktionen av programvarusystemet, men Fluentd har sina specifika nyanser, vilket beror pÄ dess mÄngfunktionalitet.

Till exempel, nÀr vi började anvÀnda EFK i ett intensivt projekt med hög loggskrivning, stötte vi pÄ att vissa meddelanden i Kibana visas flera gÄnger. I denna artikel kommer vi att berÀtta orsaken till detta fenomen och hur man löser problemet.

Problemet med dubblering av dokument

I vÄra projekt Àr Fluentd implementerat som en DaemonSet (startar automatiskt i en instans pÄ varje nod i Kubernetes-klustret) och övervakar stdout-loggar frÄn containrarna i /var/log/containers. Efter insamling och behandling skickas loggarna i form av JSON-dokument till ElasticSearch, antingen i kluster- eller fristÄende version, beroende pÄ projektets storlek och krav pÄ prestanda och tillförlitlighet. För det grafiska grÀnssnittet anvÀnds Kibana.

Vid anvÀndning av Fluentd med en buffrande plugin vid utgÄngen stötte vi pÄ en situation dÀr vissa dokument i ElasticSearch har helt identiskt innehÄll och bara skiljer sig Ät i identifieraren. Att sÀkerstÀlla att detta verkligen Àr ett meddelande som upprepas kan illustreras med ett exempel frÄn Nginx-loggen. I loggfilen finns detta meddelande en gÄng:

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

Men i ElasticSearch finns flera dokument som innehÄller detta meddelande:

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

Dessutom kan det finnas fler Àn tvÄ upprepningar.

Under registreringen av detta problem kan man observera ett stort antal varningar i Fluentd-loggarna med följande innehÄll:

2020-01-16 01:46:46 +0000 [warn]: [test-prod] misslyckades med att tömma bufferten. retry_time=4 next_retry_seconds=2020-01-16 01:46:53 +0000 chunk="59c37fc3fb320608692c352802b973ce" error_class=Fluent::Plugin::ElasticsearchOutput::RecoverableRequestFailure error="kunde inte skicka loggar till Elasticsearch-klustret ({:host=>"elasticsearch", :port=>9200, :scheme=>"http", :user=>"elastic", :password=>"obfuscated"}): tid för lÀsning överskreds"

Dessa varningar uppstÄr nÀr ElasticSearch inte kan returnera ett svar inom den tid som anges i request_timeout, vilket gör att den skickade bufferdelen inte kan rensas. Efter det försöker Fluentd att skicka bufferdelen till ElasticSearch igen och efter ett antal försök lyckas operationen:

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

Dock uppfattar ElasticSearch varje skickad bufferdel som unik och tilldelar dem unika vÀrden i fÀlten _id vid indexering. PÄ sÄ sÀtt uppstÄr kopior av meddelanden.

I Kibana ser det ut sÄ hÀr:

Fluentd: varför det Àr viktigt att stÀlla in utmatningsbufferten

Lös problemet

Det finns flera alternativ för att lösa detta problem. Ett av dem Àr den inneboende mekanismen för generering av unika hash-vÀrden för varje dokument som finns i pluginet fluent-plugin-elasticsearch. Om denna mekanism anvÀnds kommer ElasticSearch att kÀnna igen dubbletter under överföringsstadiet och förhindra duplicering av dokument. Men man mÄste ocksÄ ta hÀnsyn till att denna metod för att lösa problemet bekÀmpar konsekvenserna och inte eliminerar felet med bristen pÄ timeout, varför vi valde att inte anvÀnda den.

Vi anvÀnder en buffrande plugin i Fluentd utgÄngen för att förhindra förlust av loggar vid kortvariga nÀtverksproblem eller ökad loggskrivning. Om ElasticSearch av nÄgon anledning inte omedelbart kan skriva ett dokument till indexet, hamnar dokumentet i en kö som lagras pÄ disken. DÀrför, för att eliminera kÀllan till problemet som orsakar det ovan beskrivna felet, mÄste korrekta vÀrden för buffertparametrarna stÀllas in, sÄ att Fluentds utgÄngsbuffert har tillrÀcklig kapacitet och kan rensas inom angiven tid.

Det Àr vÀrt att notera att vÀrdena för de parametrar som kommer att diskuteras nedan Àr individuella för varje specifikt fall av buffring i utgÄngsplugins, eftersom de beror pÄ mÄnga faktorer: intensiteten av loggmeddelanden som skrivs av tjÀnster, prestanda för lagringssystemet, belastning pÄ nÀtverkskanalen och dess kapacitet. För att fÄ lÀmpliga men inte överdrivna instÀllningar för varje specifikt fall, och undvika lÄngvarig blind avkÀnning, kan man anvÀnda den felsökningsinformation som Fluentd skriver till sin logg under drift och relativt snabbt fÄ korrekta vÀrden.

Vid tidpunkten för problemet sÄg konfigurationen ut pÄ följande sÀtt:

 @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

Under lösningen av problemet justerades följande parameter vÀrden manuellt:
chunk_limit_size — storleken pĂ„ chunkar som meddelanden bryts ned i i bufferten.

  • flush_interval — tidsintervallet för nĂ€r bufferten rensas.
  • queue_limit_length — det maximala antalet chunkar i kön.
  • request_timeout — den tid som anslutningen mellan Fluentd och ElasticSearch stĂ€lls in pĂ„.

Den totala storleken pÄ bufferten kan berÀknas genom att multiplicera parametrarna queue_limit_length och chunk_limit_size, vilket kan tolkas som "det maximala antalet chunkar i kön, dÀr varje har en angiven storlek". Om bufferten Àr för liten, kommer följande varning att visas i loggarna:

2020-01-21 10:22:57 +0000 [warn]: [test-prod] misslyckades med att skriva data i bufferten pÄ grund av buffertöversvÀmning action=:block

Det betyder att bufferten inte hinner rensa sig inom angiven tid och data som kommer in i den fulla bufferten blockeras, vilket leder till förlust av en del loggar.

Bufferten kan ökas pÄ tvÄ sÀtt: genom att antingen öka storleken pÄ varje chunk i kön eller antalet chunkar som kan vara i kön.

Om storleken pÄ chunk_limit_size sÀtts till mer Àn 32 megabyte, kommer ElasticSearch inte att acceptera den, eftersom det inkommande paketet blir för stort. DÀrför, om bufferten behöver ökas ytterligare, Àr det bÀst att öka den maximala kö-lÀngden queue_limit_length.

NÀr bufferten slutar översvÀmmas och endast meddelandet om timeout-överskridning kvarstÄr, kan du börja öka parametern request_timeout. Men om vÀrdet sÀtts högre Àn 20 sekunder, kommer följande varningar att visas i Fluentds loggar:

2020-01-21 09:55:33 +0000 [warn]: [test-dev] buffertflush tog lÀngre tid Àn slow_flush_log_threshold: elapsed_time=20.85753920301795 slow_flush_log_threshold=20.0 plugin_id="postgresql-dev" 

Detta meddelande pÄverkar inte systemets funktion och innebÀr att tiden för att rensa bufferten tog lÀngre tid Àn angivet i slow_flush_log_threshold. Detta Àr felsökningsinformation och vi anvÀnder den nÀr vi stÀller in vÀrdet pÄ parametern request_timeout.

Den allmÀnna algoritmen för justering ser ut pÄ följande sÀtt:

  1. SÀtt vÀrdet pÄ request_timeout betydligt högre Àn nödvÀndigt (hundratals sekunder). Under instÀllningsperioden kommer det huvudsakliga kriteriet för att korrekt stÀlla in denna parameter vara att varningarna om timeout-överskridning försvinner.
  2. VÀnta pÄ meddelanden om överskridande av slow_flush_log_threshold. I texten av varningen kommer det verkliga tiden för att rensa bufferten att anges i fÀltet elapsed_time.
  3. StÀll in vÀrdet för request_timeout högre Àn det maximala vÀrdet för elapsed_time som fÄtts under observationsperioden. Vi berÀknar vÀrdet pÄ request_timeout som elapsed_time + 50%.
  4. För att ta bort varningar om lÄngsam buffertrensning frÄn loggen kan man höja vÀrdet pÄ slow_flush_log_threshold. Vi berÀknar detta vÀrde som elapsed_time + 25%.

De slutgiltiga vÀrdena för dessa parametrar, som tidigare nÀmnts, Àr individuella för varje fall. Genom att följa den ovan angivna algoritmen garanterar vi att vi eliminerar felet som leder till dubbletter av meddelanden.

I tabellen nedan visas hur antalet fel per dag som leder till dublika meddelanden förÀndras under processen att justera vÀrdena för de ovan beskrivna parametrarna:

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

Före/Efter
Före/Efter
Före/Efter
Före/Efter

misslyckades med att rensa bufferten
1749/2
694/2
47/0
1121/2

Äterförsök lyckades
410/2
205/1
24/0
241/2

Det Àr vÀrt att notera att de instÀllningar som erhÄllits kan förlora sin relevans i takt med att projektet vÀxer och, dÀrmed, antalet loggar ökar. Det primÀra tecknet pÄ otillrÀcklig instÀlld tidsgrÀns Àr att loggarna i Fluentd visar meddelanden om lÄngsam buffertrensning, det vill sÀga överskridande av tröskeln slow_flush_log_threshold. FrÄn och med detta ögonblick finns det en liten marginal kvar innan parameter request_timeout överskrids, sÄ det Àr viktigt att reagera snabbt pÄ dessa meddelanden och upprepa processen för att justera de optimala instÀllningarna, som beskrivits ovan.

Slutsats

Finjusteringen av utdata bufferten i Fluentd Àr ett av de viktigaste stegen i konfigurationen av EFK-stacken, som bestÀmmer stabiliteten i dess arbete och korrekt placering av dokumenten i indexen. Med hjÀlp av den beskrivna konfigurationsalgoritmen kan man vara sÀker pÄ att alla loggar kommer att skrivas till ElasticSearch-indexet i rÀtt ordning, utan dubbletter och förluster.

LÀs Àven andra artiklar i vÄr blogg:

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster