Fluentd: Perchè hè impurtante di cunfigurà u buffer di output
Oghje, hè impussibile imaginà un prughjettu basatu in Kubernetes senza a pila ELK, chì salva logs di l'applicazioni è di i cumpunenti di u sistema di u cluster. In a nostra pratica, usemu a pila EFK cù Fluentd invece di Logstash.
Fluentd hè un collettore di log universale mudernu chì guadagna sempre più pupularità è s'hè unitu à a Cloud Native Computing Foundation, per quessa chì u so vettore di sviluppu hè focu annantu à l'usu in cunjunzione cù Kubernetes.
U fattu di utilizà Fluentd invece di Logstash ùn cambia micca l'essenza generale di u pacchettu di software, in ogni modu, Fluentd hè carattarizatu da e so sfumature specifiche chì risultanu da a so versatilità.
Per esempiu, quandu avemu cuminciatu à aduprà EFK in un prughjettu occupatu cù una alta intensità di logging, avemu statu affruntatu cù u fattu chì in Kibana certi missaghji sò stati mostrati ripetutamente parechje volte. In questu articulu vi diceremu perchè stu fenomenu si trova è cumu per risolve u prublema.
U prublema di duplicazione di documenti
In i nostri prughjetti, Fluentd hè implementatu cum'è DaemonSet (lanciatu automaticamente in una istanza nantu à ogni node di u cluster Kubernetes) è monitorizza i logs di u container stdout in /var/log/containers. Dopu a cullizzioni è a trasfurmazioni, i logs in forma di documenti JSON sò mandati à ElasticSearch, risuscitatu in cluster o forma standalone, secondu a scala di u prugettu è i requisiti per u rendiment è a tolleranza di difetti. Kibana hè utilizatu com'è interfaccia grafica.
Quandu aduprate Fluentd cù un plugin di buffering di output, avemu scontru una situazione induve certi documenti in ElasticSearch avianu esattamente u listessu cuntenutu è diffarendu solu in l'identificatore. Pudete verificà chì questu hè una ripetizione di missaghju utilizendu u log Nginx cum'è un esempiu. In u schedariu di logu, stu missaghju esiste in una sola copia:
Mentre risolve stu prublema in i logs Fluentd, pudete vede un gran numaru di avvisi cù u cuntenutu seguente:
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"
Questi avvirtimenti sò quandu ElasticSearch ùn pò micca rinvià una risposta à una dumanda in u tempu specificatu da u paràmetru request_timeout, chì hè per quessa chì u fragmentu di buffer trasmessu ùn pò esse sbulicatu. Dopu questu, Fluentd prova di mandà u frammentu di buffer à ElasticSearch di novu è dopu un numeru arbitrariu di tentativi, l'operazione si compie bè:
Tuttavia, ElasticSearch tratta ognuna di i frammenti di buffer trasferiti cum'è unicu è li assigna valori unichi di u campu _id durante l'indexazione. Questu hè cumu appare e copie di i missaghji.
In Kibana si vede cusì:
Solución di salvezza
Ci hè parechje scelte per risolve stu prublema. Unu di elli hè u mecanismu integratu in u plugin fluent-plugin-elasticsearch per generà un hash unicu per ogni documentu. Se aduprate stu mecanismu, ElasticSearch ricunnosce e ripetizioni in u stadiu di trasmissioni è impedisce i documenti duplicati. Ma ci vole à piglià in contu chì stu metudu di risolviri u prublema lotta cù l'inchiesta è ùn elimina micca l'errore cù una mancanza di timeout, cusì avemu abbandunatu u so usu.
Utilizemu un plugin di buffering nantu à l'output Fluentd per prevene a perdita di log in casu di prublemi di rete à cortu termine o intensità di logging aumentata. Se per una certa ragione ElasticSearch ùn pò micca scrive istantaneamente un documentu à l'indici, u documentu hè in fila è almacenatu nantu à u discu. Dunque, in u nostru casu, per eliminà a fonte di u prublema chì porta à l'errore descrittu sopra, hè necessariu di stabilisce i valori curretti per i paràmetri di buffering, à quale u buffer di output Fluentd serà abbastanza grande è à u listessu tempu riesce à esse sbulicatu in u tempu attribuitu.
Hè nutate chì i valori di i paràmetri discututi quì sottu sò individuali in ogni casu specificu di l'usu di buffering in plugins di output, postu chì dependenu di parechji fatturi: l'intensità di scrittura di messagi à u logu per servizii, u rendiment di u sistema di discu, a rete. a carica di u canali è a so larghezza di banda. Per quessa, per ottene paràmetri di buffer chì sò adattati per ogni casu individuale, ma micca redundante, evitendu ricerche longu à a cieca, pudete aduprà l'infurmazioni di debugging chì Fluentd scrive à u so log durante l'operazione è ottene relativamente rapidamente i valori curretti.
À u mumentu chì u prublema hè stata registrata, a cunfigurazione pareva cusì:
Quandu si risolve u prublema, i valori di i seguenti parametri sò stati selezziunati manualmente:
chunk_limit_size - a dimensione di i pezzi in quale i missaghji in u buffer sò spartuti.
flush_interval - intervallu di tempu dopu chì u buffer hè sbulicatu.
queue_limit_length - u numeru massimu di pezzi in a fila.
request_timeout hè u tempu per quale a cunnessione trà Fluentd è ElasticSearch hè stabilitu.
A dimensione di u buffer tutale pò esse calculata multiplicendu i paràmetri queue_limit_length è chunk_limit_size, chì ponu esse interpretati cum'è "u numeru massimu di pezzi in a fila, ognuna di quale hà una dimensione data". Se a dimensione di u buffer hè insufficiente, l'avvertimentu seguente appariscerà in i logs:
2020-01-21 10:22:57 +0000 [warn]: [test-prod] failed to write data into buffer by buffer overflow action=:block
Hè significatu chì u buffer ùn hà micca tempu per esse sbulicatu in u tempu attribuitu è i dati chì entra in u buffer sanu hè bluccatu, chì portarà à a perdita di parte di i logs.
Pudete aumentà u buffer in dui maneri: aumentendu o a dimensione di ogni pezzu in a fila, o u numeru di pezzi chì ponu esse in a fila.
Se stabilisce u chunk size chunk_limit_size à più di 32 megabytes, allora ElasticSeacrh ùn l'accetta, postu chì u pacchettu entrante serà troppu grande. Dunque, se avete bisognu di aumentà u buffer più, hè megliu aumentà a lunghezza massima di a fila queue_limit_length.
Quandu u buffer smette di overflowing è solu u timeout missaghju insufficiente resta, pudete cumincià à aumentà u paràmetru request_timeout. Tuttavia, se stabilisce u valore à più di 20 seconde, i seguenti avvisi cumincianu à apparisce in i logs 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"
Stu missaghju ùn affetta micca u funziunamentu di u sistema in ogni modu è significa chì u tempu di flush di u buffer pigliò più di quellu stabilitu da u paràmetru slow_flush_log_threshold. Questa hè infurmazione di debugging è l'utilicemu quandu sceglite u valore di u paràmetru request_timeout.
L'algoritmu di selezzione generalizata hè u seguitu:
Pone request_timeout à un valore garantitu per esse più grande di ciò chì hè necessariu (centinaie di seconde). Durante a cunfigurazione, u criteriu principale per l'impostazione curretta di stu paràmetru serà a sparizione di l'avvirtimenti per a mancanza di timeout.
Aspettate i missaghji chì anu superatu u limitu di slow_flush_log_threshold. U testu d'avvertimentu in u campu elapsed_time mostrarà u tempu reale chì u buffer hè statu sbulicatu.
Pone request_timeout à un valore più grande di u valore massimu elapsed_time ottenutu durante u periodu di osservazione. Calculemu u valore request_timeout cum'è elapsed_time + 50%.
Per sguassà l'avvirtimenti nantu à i flussi di buffer longu da u logu, pudete elevà u valore di slow_flush_log_threshold. Calculemu stu valore cum'è elapsed_time + 25%.
I valori finali di sti paràmetri, cum'è nutatu prima, sò ottenuti individualmente per ogni casu. Dopu à l'algoritmu di sopra, simu guarantiti per eliminà l'errore chì porta à i missaghji ripetuti.
A tabella sottu mostra cumu u numeru di errori per ghjornu, chì porta à a duplicazione di missaghji, cambia in u prucessu di selezzione di i valori di i paràmetri descritti sopra:
nodu-1
nodu-2
nodu-3
nodu-4
Prima dopu
Prima dopu
Prima dopu
Prima dopu
fiascatu à lavà u buffer
1749/2
694/2
47/0
1121/2
ripruvà successu
410/2
205/1
24/0
241/2
In più, vale a pena nutà chì i paràmetri resultanti ponu perde a so rilevanza mentre u prughjettu cresce è, per quessa, u numeru di logs aumenta. U signu primariu di timeout insufficiente hè u ritornu di missaghji nantu à un flussu di buffer longu à u logu Fluentd, vale à dì, sopra à u limitu slow_flush_log_threshold. Da questu puntu, ci hè sempre un picculu margine prima chì u paràmetru request_timeout hè superatu, cusì hè necessariu di risponde à sti messagi in una manera puntuale è ripetite u prucessu di selezziunà i paràmetri ottimali descritti sopra.
cunchiusioni
A fine-tuning di u buffer di output Fluentd hè una di e tappe principali di cunfigurà a pila EFK, determinendu a stabilità di u so funziunamentu è a piazza curretta di documenti in indici. Basatu annantu à l'algoritmu di cunfigurazione descrittu, pudete esse sicuru chì tutti i logs seranu scritti à l'indici ElasticSearch in l'ordine currettu, senza ripetizioni o pèrdite.
Leghjite ancu altri articuli nantu à u nostru blog: