Fluentd: Çıkış arabelleğini yapılandırmak neden önemlidir?

Fluentd: Çıkış arabelleğini yapılandırmak neden önemlidir?

Günümüzde kümenin hem uygulamalarının hem de sistem bileşenlerinin günlüklerini kaydeden ELK yığını olmadan Kubernetes tabanlı bir proje hayal etmek imkansızdır. Uygulamamızda Logstash yerine Fluentd ile EFK yığınını kullanıyoruz.

Fluentd, giderek daha fazla popülerlik kazanan ve Cloud Native Computing Foundation'a katılan modern, evrensel bir günlük toplayıcıdır; bu nedenle geliştirme vektörü Kubernetes ile birlikte kullanıma odaklanmıştır.

Logstash yerine Fluentd kullanılması, yazılım paketinin genel özünü değiştirmez ancak Fluentd, çok yönlülüğünden kaynaklanan kendine özgü nüanslarla karakterize edilir.

Örneğin loglama yoğunluğu yüksek olan yoğun bir projede EFK'yi kullanmaya başladığımızda Kibana'da bazı mesajların defalarca defalarca görüntülenmesiyle karşı karşıya kaldık. Bu yazıda size bu olgunun neden oluştuğunu ve sorunun nasıl çözüleceğini anlatacağız.

Belge çoğaltma sorunu

Projelerimizde Fluentd, DaemonSet olarak dağıtılır (Kubernetes kümesinin her düğümünde tek bir örnekte otomatik olarak başlatılır) ve /var/log/containers dosyasındaki stdout konteyner günlüklerini izler. Toplandıktan ve işlendikten sonra, JSON belgeleri biçimindeki günlükler, projenin ölçeğine ve performans ve hata toleransı gereksinimlerine bağlı olarak küme halinde veya bağımsız biçimde yükseltilerek ElasticSearch'e gönderilir. Grafiksel arayüz olarak Kibana kullanılmaktadır.

Fluentd'yi bir çıktı tamponlama eklentisi ile kullanırken, ElasticSearch'teki bazı belgelerin tamamen aynı içeriğe sahip olduğu ve yalnızca tanımlayıcının farklı olduğu bir durumla karşılaştık. Örnek olarak Nginx günlüğünü kullanarak bunun bir mesaj tekrarı olduğunu doğrulayabilirsiniz. Günlük dosyasında bu mesaj tek bir kopya halinde bulunmaktadır:

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

Ancak ElasticSearch'te bu mesajı içeren birkaç belge var:

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

Üstelik ikiden fazla tekrar olabilir.

Fluentd loglarında bu sorunu düzeltirken aşağıdaki içeriklere sahip çok sayıda uyarı görebilirsiniz:

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"

Bu uyarılar, ElasticSearch'ün request_timeout parametresi tarafından belirtilen süre içinde bir isteğe yanıt döndüremediği ve bu nedenle iletilen arabellek parçasının temizlenemediği durumlarda ortaya çıkar. Bundan sonra Fluentd arabellek parçasını tekrar ElasticSearch'e göndermeye çalışır ve isteğe bağlı sayıda denemeden sonra işlem başarıyla tamamlanır:

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"

Ancak ElasticSearch, aktarılan arabellek parçalarının her birini benzersiz olarak ele alır ve indeksleme sırasında onlara benzersiz _id alanı değerleri atar. Mesajların kopyaları bu şekilde görünür.

Kibana'da şöyle görünür:

Fluentd: Çıkış arabelleğini yapılandırmak neden önemlidir?

Çözelti

Bu sorunu çözmek için birkaç seçenek var. Bunlardan biri, her belge için benzersiz bir karma oluşturmak için akıcı eklenti-elasticsearch eklentisinde yerleşik mekanizmadır. Bu mekanizmayı kullanırsanız, ElasticSearch iletme aşamasında tekrarları tanıyacak ve mükerrer belgeleri önleyecektir. Ancak sorunu çözmenin bu yönteminin soruşturmayı zorlaştırdığını ve zaman aşımı eksikliği ile hatayı ortadan kaldırmadığını dikkate almalıyız, bu nedenle kullanımından vazgeçtik.

Kısa süreli ağ sorunları veya artan günlük yoğunluğu durumunda günlük kaybını önlemek için Fluentd çıkışında bir tamponlama eklentisi kullanıyoruz. Herhangi bir nedenden ötürü ElasticSearch bir belgeyi anında dizine yazamazsa, belge sıraya alınır ve diskte saklanır. Bu nedenle bizim durumumuzda yukarıda açıklanan hataya yol açan sorunun kaynağını ortadan kaldırmak için Fluentd çıkış tamponunun yeterli boyutta olacağı tamponlama parametreleri için doğru değerlerin ayarlanması gerekir ve aynı zamanda ayrılan sürede temizlenmeyi başarır.

Aşağıda tartışılan parametrelerin değerlerinin, çıktı eklentilerinde arabelleğe almanın her özel durumunda bireysel olduğunu belirtmekte fayda var, çünkü bunlar birçok faktöre bağlıdır: servislere göre günlüğe mesaj yazma yoğunluğu, disk sistemi performansı, ağ Kanal yükü ve bant genişliği. Bu nedenle, her bir duruma uygun, ancak gereksiz olmayan, körü körüne uzun aramalardan kaçınarak tampon ayarlarını elde etmek için, Fluentd'in çalışma sırasında günlüğüne yazdığı hata ayıklama bilgilerini kullanabilir ve doğru değerleri nispeten hızlı bir şekilde elde edebilirsiniz.

Sorun kaydedildiğinde yapılandırma şu şekilde görünüyordu:

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

Sorunu çözerken aşağıdaki parametrelerin değerleri manuel olarak seçildi:
chunk_limit_size — arabellekteki mesajların bölündüğü parçaların boyutu.

  • flush_interval — arabelleğin temizlendiği zaman aralığı.
  • kuyruk_limit_uzunluğu — kuyruktaki maksimum parça sayısı.
  • request_timeout, Fluentd ile ElasticSearch arasındaki bağlantının kurulduğu süredir.

Toplam arabellek boyutu, kuyruk_limit_uzunluğu ve yığın_limit_size parametrelerinin çarpılmasıyla hesaplanabilir; bu parametreler, "her biri belirli bir boyuta sahip olan kuyruktaki maksimum parça sayısı" olarak yorumlanabilir. Arabellek boyutu yetersizse günlüklerde aşağıdaki uyarı görünecektir:

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

Bu, arabelleğin ayrılan sürede temizlenmesi için zamanın olmadığı ve tam arabelleğe giren verilerin engellendiği anlamına gelir, bu da günlüklerin bir kısmının kaybolmasına yol açacaktır.

Arabelleği iki şekilde artırabilirsiniz: kuyruktaki her bir parçanın boyutunu veya kuyrukta bulunabilecek parça sayısını artırarak.

Chunck_limit_size yığın boyutunu 32 megabaytın üzerine ayarlarsanız, gelen paket çok büyük olacağından ElasticSeacrh bunu kabul etmeyecektir. Bu nedenle, arabelleği daha da artırmanız gerekiyorsa, maksimum kuyruk uzunluğunun kuyruk_limit_uzunluğunu artırmak daha iyidir.

Arabellek taşması durduğunda ve yalnızca zaman aşımı yetersiz mesajı kaldığında request_timeout parametresini artırmaya başlayabilirsiniz. Ancak değeri 20 saniyeden fazla ayarlarsanız Fluentd loglarında aşağıdaki uyarılar görünmeye başlayacaktır:

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" 

Bu mesaj sistemin çalışmasını hiçbir şekilde etkilemez ve arabellek temizleme süresinin, Slow_flush_log_threshold parametresi tarafından ayarlanandan daha uzun sürdüğü anlamına gelir. Bu hata ayıklama bilgisidir ve bunu request_timeout parametresinin değerini seçerken kullanırız.

Genelleştirilmiş seçim algoritması aşağıdaki gibidir:

  1. request_timeout değerini gerekenden daha büyük olması garanti edilen bir değere (yüzlerce saniye) ayarlayın. Kurulum sırasında bu parametrenin doğru ayarlanması için ana kriter, zaman aşımı eksikliğine ilişkin uyarıların ortadan kalkması olacaktır.
  2. Slow_flush_log_threshold eşiğinin aşılmasına ilişkin mesajları bekleyin. Elapsed_time alanındaki uyarı metni arabelleğin temizlendiği gerçek zamanı gösterecektir.
  3. request_timeout'u gözlem süresi boyunca elde edilen maksimum geçen_zaman değerinden daha büyük bir değere ayarlayın. request_timeout değerini geçen_time + %50 olarak hesaplıyoruz.
  4. Uzun arabellek temizleme işlemleriyle ilgili uyarıları günlükten kaldırmak için, Slow_flush_log_threshold değerini artırabilirsiniz. Bu değeri geçen_zaman + %25 olarak hesaplıyoruz.

Bu parametrelerin nihai değerleri, daha önce de belirtildiği gibi, her durum için ayrı ayrı elde edilir. Yukarıdaki algoritmayı takip ederek mesajların tekrarlanmasına yol açan hatayı ortadan kaldırmamız garanti edilir.

Aşağıdaki tablo, mesajların kopyalanmasına yol açan günlük hata sayısının, yukarıda açıklanan parametrelerin değerlerinin seçilmesi sürecinde nasıl değiştiğini göstermektedir:

düğüm-1
düğüm-2
düğüm-3
düğüm-4

Önce sonra
Önce sonra
Önce sonra
Önce sonra

arabellek temizlenemedi
1749/2
694/2
47/0
1121/2

yeniden deneme başarılı oldu
410/2
205/1
24/0
241/2

Ayrıca, proje büyüdükçe ve buna bağlı olarak günlük sayısı arttıkça ortaya çıkan ayarların geçerliliğini kaybedebileceğini belirtmekte fayda var. Yetersiz zaman aşımının birincil işareti, Fluentd günlüğüne uzun bir arabellek temizlemeyle ilgili mesajların döndürülmesi, yani yavaş_flush_log_threshold eşiğinin aşılmasıdır. Bu noktadan sonra request_timeout parametresinin aşılmasına hala küçük bir marj kalıyor, bu nedenle bu mesajlara zamanında yanıt vermek ve yukarıda açıklanan en uygun ayarları seçme işlemini tekrarlamak gerekiyor.

Sonuç

Fluentd çıkış arabelleğinin ince ayarının yapılması, EFK yığınını yapılandırmanın, işleminin kararlılığını belirlemenin ve belgelerin dizinlere doğru yerleştirilmesinin ana aşamalarından biridir. Açıklanan yapılandırma algoritmasına dayanarak, tüm günlüklerin ElasticSearch dizinine tekrarlar veya kayıplar olmadan doğru sırayla yazılacağından emin olabilirsiniz.

Ayrıca blogumuzdaki diğer makaleleri de okuyun:

Kaynak: habr.com

Yorum ekle