Fluentd: لماذا من المهم ضبط المخزن المؤقت للإخراج

Fluentd: لماذا من المهم ضبط المخزن المؤقت للإخراج

في الوقت الحاضر ، من المستحيل تخيل مشروع يعتمد على Kubernetes بدون مكدس ELK ، بمساعدة سجلات كل من التطبيقات ومكونات النظام في المجموعة. في ممارستنا ، نستخدم مكدس EFK مع Fluentd بدلاً من Logstash.

Fluentd هو مجمع سجلات حديث متعدد الأغراض يكتسب المزيد والمزيد من الشعبية وقد انضم إلى Cloud Native Computing Foundation ، ولهذا السبب يركز متجه التطوير على الاستخدام مع Kubernetes.

حقيقة استخدام Fluentd بدلاً من Logstash لا يغير الجوهر العام لحزمة البرنامج ، ومع ذلك ، فإن Fluentd له الفروق الدقيقة الخاصة به الناتجة عن تعدد استخداماته.

على سبيل المثال ، عندما بدأنا في استخدام EFK في مشروع مزدحم بكثافة تسجيل عالية ، واجهنا حقيقة أنه في Kibana يتم عرض بعض الرسائل بشكل متكرر عدة مرات. سنخبرك في هذا المقال عن سبب حدوث هذه الظاهرة وكيفية حلها.

مشكلة نسخ المستندات

في مشاريعنا ، يتم نشر Fluentd باعتباره DaemonSet (يتم تشغيله تلقائيًا في مثيل واحد على كل عقدة من مجموعة Kubernetes) ويراقب سجلات stdout الحاوية في / var / log / container. بعد التجميع والمعالجة ، يتم إرسال السجلات في شكل مستندات JSON إلى ElasticSearch ، ويتم رفعها في شكل مجمع أو مستقل ، اعتمادًا على حجم المشروع ومتطلبات الأداء والتسامح مع الخطأ. يتم استخدام كيبانا كواجهة رسومية.

عند استخدام Fluentd مع مكون إضافي للتخزين المؤقت للإخراج ، واجهنا موقفًا حيث تحتوي بعض المستندات في ElasticSearch على نفس المحتوى تمامًا وتختلف فقط في المعرف. يمكنك التأكد من أن هذا تكرار للرسالة باستخدام مثال سجل 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 يتعامل مع كل جزء من أجزاء المخزن المؤقت المعاد توجيهه على أنه فريد ويعين لهم قيم حقل معرف فريد عند الفهرسة. وهكذا تظهر نسخ من الرسائل.

في Kibana يبدو كالتالي:

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. في نص التحذير ، سيحتوي حقل الوقت المنقضي على وقت مسح المخزن المؤقت الفعلي.
  3. قم بتعيين قيمة request_timeout لتكون أكبر من الحد الأقصى لقيمة الوقت المنقضي التي تم تلقيها أثناء فترة المراقبة. نحسب قيمة request_timeout على أنها elapsed_time + 50٪.
  4. لإزالة التحذيرات حول تدفق المخزن المؤقت الطويل من السجل ، يمكنك رفع قيمة slow_flush_log_threshold. نحسب هذه القيمة على أنها elapsed_time + 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

إضافة تعليق