Fluentd: зошто е важно да го подесите излезниот бафер

Fluentd: зошто е важно да го подесите излезниот бафер

Во денешно време, невозможно е да се замисли проект заснован на Kubernetes без стек ELK, со помош на кој се зачувуваат логовите и на апликациите и на системските компоненти на кластерот. Во нашата пракса, го користиме стекот EFK со Fluentd наместо Logstash.

Fluentd е модерен колекционер на дневници за општа намена кој добива сè поголема популарност и се приклучи на Cloud Native Computing Foundation, поради што неговиот развоен вектор е фокусиран на употреба во врска со Kubernetes.

Фактот на користење на Fluentd наместо Logstash не ја менува општата суштина на софтверскиот пакет, сепак, Fluentd има свои специфични нијанси кои произлегуваат од неговата разновидност.

На пример, кога почнавме да користиме EFK во зафатен проект со висок интензитет на логирање, се соочивме со фактот дека во Kibana некои пораки се прикажуваат постојано неколку пати. Во оваа статија ќе ви кажеме зошто се појавува овој феномен и како да го решите проблемот.

Проблемот со дуплирање на документи

Во нашите проекти, Fluentd е распореден како DaemonSet (автоматски работи во еден пример на секој јазол од кластерот Kubernetes) и ги следи логовите на контејнери stdout во /var/log/containers. По собирањето и обработката, дневниците во форма на JSON документи се испраќаат до ElasticSearch, подигнати во групирани или самостојни форми, во зависност од обемот на проектот и барањата за перформанси и толеранција на грешки. Kibana се користи како графички интерфејс.

При користење на Fluentd со приклучок за баферирање на излез, наидовме на ситуација кога некои документи во ElasticSearch имаат потполно иста содржина и се разликуваат само по ID. Можете да бидете сигурни дека ова е повторување на пораката користејќи го примерот на дневникот Nginx. Во датотеката за евиденција, оваа порака постои во еден пример:

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

Сепак, постојат неколку документи во ElasticSearch кои ја содржат оваа порака:

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

Покрај тоа, може да има повеќе од две повторувања.

За време на решавањето на овој проблем, може да се забележат голем број предупредувања во дневниците на Fluentd со следната содржина:

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"

Овие предупредувања се појавуваат кога ElasticSearch не може да врати одговор на барање во времето поставено од параметарот request_timeout, поради што препратениот фрагмент од тампон не може да се исчисти. После тоа, Fluentd повторно се обидува да го испрати фрагментот на тампон до ElasticSearch и по произволен број повторувања, операцијата успева:

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"

Сепак, ElasticSearch го третира секој од препратените фрагменти на тампон како единствен и им доделува уникатни вредности на полето _id при индексирање. Така, се појавуваат копии од пораки.

Во Кибана изгледа вака:

Fluentd: зошто е важно да го подесите излезниот бафер

Решението

Постојат неколку решенија за овој проблем. Еден од нив е механизмот вграден во додатокот fluent-plugin-elasticsearch за генерирање уникатен хаш за секој документ. Ако го користите овој механизам, ElasticSearch ќе препознае дупликати во фазата на препраќање и ќе спречи дупликат документи. Но, не може да се игнорира дека овој метод на решавање на проблемот се бори со истрагата и не ја елиминира грешката со недостаток на тајмаут, па затоа ја напуштивме неговата употреба.

Ние користиме приклучок за баферирање на излезот Fluentd за да спречиме губење на дневници во случај на кратки прекини на мрежата или зголемено евидентирање. Ако, поради некоја причина, ElasticSearch не може веднаш да го запише документот на индексот, документот се става во редица што е зачувана на дискот. Затоа, во нашиот случај, за да се елиминира изворот на проблемот што доведува до грешката опишана погоре, неопходно е да се постават точните вредности на параметрите на баферот, во кои излезниот бафер Fluentd ќе биде доволен. големина и во исто време имаат време да се расчисти во даденото време.

Треба да се напомене дека вредностите на параметрите, за кои ќе се дискутира подолу, се индивидуални во секој конкретен случај на користење на баферирање во излезните приклучоци, бидејќи тие зависат од многу фактори: интензитетот на евиденција на пораки од услугите, перформансите на системот на дискот, оптоварувањето на мрежниот канал и неговиот пропусен опсег. Затоа, за да добиете соодветни за секој поединечен случај, но не и вишок поставки на баферот, избегнувајќи долго слепо пребарување, можете да ги користите информациите за отстранување грешки што Fluentd ги пишува во својот дневник за време на работата и релативно брзо да ги добиете точните вредности.

Во моментот на решавање на проблемот, конфигурацијата изгледаше вака:

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

Во текот на решавањето на проблемот, вредностите на следните параметри беа рачно избрани:
chunk_limit_size - големината на деловите во кои се прекршени пораките во баферот.

  • flush_interval - временскиот интервал после кој тампонот се брише.
  • queue_limit_length - максималниот број на парчиња во редот.
  • request_timeout е времето за кое се воспоставува врска помеѓу Fluentd и ElasticSearch.

Вкупната големина на баферот може да се пресмета со множење на параметрите queue_limit_length и chunk_limit_size, кои може да се толкуваат како „максимален број делови во редот, од кои секоја има одредена големина“. Ако големината на баферот е недоволна, следното предупредување ќе се појави во дневниците:

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

Тоа значи дека баферот нема време да се исчисти во даденото време и податоците што влегуваат во целосниот бафер се блокирани, што ќе доведе до губење на дел од дневниците.

Можете да го зголемите тампонот на два начина: или со зголемување на големината на секое парче во редот или со зголемување на бројот на делови што можат да бидат во редот.

Ако ја поставите големината на chunk_limit_size на повеќе од 32 мегабајти, тогаш ElasticSeacrh нема да ја прифати, бидејќи дојдовниот пакет ќе биде премногу голем. Затоа, ако треба дополнително да го зголемите баферот, подобро е да ја зголемите максималната должина на queue_limit_length.

Кога тампонот ќе престане да се прелева и ќе остане само пораката за недостаток на истек на време, можете да почнете да го зголемувате параметарот request_timeout. Сепак, поставувањето на повеќе од 20 секунди ќе предизвика следните предупредувања да се појават во дневниците на 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" 

Оваа порака не влијае на системот на кој било начин и значи дека времето за испирање на баферот траело подолго отколку што е поставено со параметарот slow_flush_log_threshold. Ова е информација за отстранување грешки и ги користиме кога ја избираме вредноста на параметарот request_timeout.

Генерализираниот алгоритам за избор е како што следува:

  1. Поставете ја вредноста на request_timeout да се гарантира да биде поголема од потребното (стотици секунди). Во моментот на поставување, главниот критериум за правилно поставување на овој параметар ќе биде исчезнувањето на предупредувањата за недостаток на тајмаут.
  2. Почекајте пораки за надминување на прагот на slow_flush_log_threshold. Во текстот на предупредувањето, полето elapsed_time ќе го содржи вистинското време на бришење на баферот.
  3. Поставете ја вредноста на request_timeout да биде поголема од максималната вредност на elapsed_time добиена за време на периодот на следење. Вредноста на request_timeout ја пресметуваме како изминат_време + 50%.
  4. За да ги отстраните предупредувањата за долготрајно испирање на баферот од дневникот, може да ја подигнете вредноста slow_flush_log_threshold. Оваа вредност ја пресметуваме како изминат_време + 25%.

Конечните вредности на овие параметри, како што беше наведено претходно, се добиваат поединечно за секој случај. Следејќи го горенаведениот алгоритам, гарантирано ни е да ја елиминираме грешката што доведува до повторување на пораките.

Табелата подолу покажува како бројот на грешки дневно, што доведува до дупликат пораки, се менува во процесот на избирање на вредностите на параметрите опишани погоре:

јазол-1
јазол-2
јазол-3
јазол-4

Пред потоа
Пред потоа
Пред потоа
Пред потоа

не успеа да го испушти тампонот
1749/2
694/2
47/0
1121/2

обидот повторно успеа
410/2
205/1
24/0
241/2

Треба дополнително да се забележи дека примените поставки може да ја изгубат својата важност во процесот на раст на проектот и, соодветно, зголемување на бројот на дневници. Примарниот показател дека не се поставува истек на време е враќањето на долгите пораки за рамна тампон во дневникот на Fluentd, односно прагот на slow_flush_log_threshold е надминат. Од овој момент, сè уште има мала маргина пред да се надмине параметарот request_timeout, па затоа е неопходно навремено да се одговори на овие пораки и да се повтори процесот на избирање на оптималните поставки опишани погоре.

Заклучок

Дотерувањето на излезниот бафер на Fluentd е еден од главните чекори во подесувањето на стекот EFK, одредувајќи ја стабилноста на неговото работење и правилното поставување на документите во индексите. Фокусирајќи се на опишаниот алгоритам за конфигурација, можете да бидете сигурни дека сите дневници ќе бидат запишани во индексот ElasticSearch во правилен редослед, без повторување и губење.

Прочитајте и други написи на нашиот блог:

Извор: www.habr.com

Додадете коментар