ناقلات السجلات
ناقلات السجلات
ناقل السجلات هو العميل البرمجي الذي يجسر الفجوة بين مخرجات السجلات الخام — الملفات على القرص، وإخراج الحاويات عبر stdout، وسجلات systemd، ومقابس syslog — وخلفية التسجيل المركزية. إتقان هذه الطبقة أمر لا يقبل التفاوض: فناقل مُعد تهيئةً خاطئة يسقط الأحداث بصمت تحت الحمل، أو يُدخل ارتفاعات في الكمون بمقدار ثوانٍ متعددة، أو يستهلك من وحدة المعالجة المركزية ما يجعله المستهلك الرئيسي للموارد على عقدة الإنتاج. تقارن هذه الدرس الأدوات الثلاث الأكثر انتشاراً في الفرق الهندسية الحقيقية اليوم: Filebeat وFluent Bit وVector.
آلية متابعة الملفات (Tailing)
تعتمد هذه الأدوات الثلاث جميعها على نفس استدعاء النواة: inotify في Linux وkqueue في macOS/BSD. وتحتفظ كلٌّ منها بـسجل موضع (registry) — ملف حالة صغير يخزّن رقم inode والإزاحة البايتية لكل ملف تتابعه. عند إعادة التشغيل، ينتقل الناقل مباشرةً إلى آخر إزاحة مؤكدة كي لا تُعاد معالجة أي سطر ولا يُفقد أي منه. هذا السجل هو أول ما يجب عليك حمايته: فقدانه — كأن تمحو حاوية مؤقتة المسار /var/lib/filebeat — يضطر الناقل إلى البدء من طرف الملف الحالي، وتضيع الأحداث التي وصلت خلال الفجوة إلى الأبد.
logrotate ملفاً دون استخدام copytruncate، يُلغى ربط inode القديم وينشأ inode جديد. إن كان ناقلك يراقب الملف بالاسم فقط، فإنه سيقرأ لحظياً من الملف الجديد الفارغ، مفوِّتاً آخر بايتات الملف القديم. احرص دائماً على ضبط الناقل كي يتابع inode القديم حتى نهايته قبل التحوّل — يسمى هذا الخيار close_inactive في Filebeat، وRotate_Wait في Fluent Bit.
Filebeat
Filebeat هو الناقل الأصيل في منظومة Elastic، مكتوب بلغة Go. تتمحور مهمته الرئيسية حول التسليم الموثوق إلى Elasticsearch أو Logstash. يتألق في البيئات التي تُشغّل ELK أصلاً، حيث تقلّص تلميحات الاكتشاف التلقائي (autodiscover) ومكتبة الوحدات الجاهزة (nginx وPostgreSQL وAWS وغيرها) والدعم المدمج لأنابيب Ingest Node من الكود المكرر. بصمته على وحدة المعالجة المركزية منخفضة، وعلى الذاكرة معتدلة لأنه يُخزّن طابور أحداث داخلياً قبل الإقرار بها.
Fluent Bit
Fluent Bit هو النسخة الخفيفة من Fluentd، مكتوبة بلغة C. بحجم ثنائي لا يتجاوز 650 كيلوبايت واستخدام RSS أقل من 10 ميغابايت في حالة الخمول، فإنه الناقل الافتراضي في DaemonSet لكل توزيعة Kubernetes مُدارة تقريباً (EKS وGKE وAKS جميعها تُشحن به). يعتمد نموذج الأنابيب الصريح والقابل للتكوين: Input → Parser → Filter → Buffer → Output. يمتلك مُدخِل tail محللاً متعدد الأسطر مخصصاً يعالج stack traces بشكل صحيح، وهو أمر بالغ الأهمية لخدمات Java وPython.
tail عن القراءة. يحمي ذلك الناقل من الإيقاف بسبب نفاد الذاكرة (OOM) خلال انفجارات السجلات. اقرن هذا الإعداد بالتخزين على نظام الملفات (storage.path) حتى تتسرب الأجزاء التي تتجاوز حد الذاكرة إلى القرص بدلاً من إسقاطها.
Vector
Vector، من إنتاج Datadog (مفتوح المصدر)، هو الأحدث بين الثلاثة والأكثر طموحاً. يُنمذج كل شيء — العملاء والمجمّعات والمحوّلات — كثنائي موحد ذي رسم بياني طوبولوجي. لغة remap الخاصة به (VRL — Vector Remap Language) هي لغة تعبيرية مخصصة وآمنة لتحويل السجلات، أكثر قدرةً بكثير من معالجات Filebeat أو مرشّحات Lua في Fluent Bit. كما ينشر Vector مقاييس مراقبة ذاتية داخلية تتيح لك التنبيه على إنتاجية الناقل ومعدلات الأخطاء.
التحليل والإثراء
سطور السجلات الخام عديمة الجدوى للاستعلام على النطاق الواسع — تحتاج إلى حقول منظمة. أبرز أنماط التحليل:
- JSON مباشر: إن كانت خدمتك تُصدر JSON أصلاً (وينبغي أن تفعل — راجع الدرس 2)، فالناقل يحتاج فقط إلى تحليل السلسلة الخارجية. استخدم مفاتيح
json.*في Filebeat، أو محللjsonفي Fluent Bit، أوparse_json!()في Vector. - Grok/Regex: للسجلات النصية القديمة كسجلات وصول nginx وApache. يدعم Filebeat وFluent Bit كلاهما Grok. Grok بطيء — إن كنت تملك الخدمة، انتقل إلى التسجيل المنظم بدلاً منه.
- تجميع متعدد الأسطر: تمتد stack traces عبر أسطر عديدة. تدعم الأدوات الثلاث التجميع المعتمد على regex. اضبط المهلة الزمنية بحذر (2–5 ثوانٍ) — القصيرة جداً تقسّم التتبعات، والطويلة جداً تُضيف كموناً لكل حدث.
يُضيف الإثراء بيانات وصفية غير موجودة في السجل الأصلي: اسم المضيف، وتسميات حاويات Kubernetes، ومنطقة السحابة، وبيئة النشر. افعل ذلك على مستوى الناقل لا المُفهرس — فأنت تدفع مقابل التخزين على كل حقل مثرى، وإثراء الحدث مرةً واحدة عند الحافة أرخص بكثير من إضافة خطوة أنبوب في مسار استيعاب Elasticsearch أو Loki الساخن.
الضغط العكسي والتخزين المؤقت
الضغط العكسي هو ما يمنع ناقلك من أن يصبح تسرباً للذاكرة غير محدود حين تكون الخلفية (Elasticsearch أو Loki أو Kafka) بطيئة أو غير متاحة. تتعامل كل أداة مع ذلك بطريقة مختلفة:
- Filebeat: يستخدم طابور في الذاكرة (حجم قابل للضبط) مع خيار تخزين على القرص. حين يمتلئ الطابور، يتوقف الحاصد (قارئ الملفات) عن القراءة. مع الطابور الافتراضي في الذاكرة، يضيع تعطّل Filebeat ما فيه من أحداث غير مُقرَّة. للتوظيفات عالية الموثوقية، انتقل إلى طابور القرص (
queue.diskفي إصدارات Filebeat الحديثة). - Fluent Bit: تنجو الأجزاء المدعومة بنظام الملفات (
storage.type filesystem) من عمليات إعادة التشغيل. يُطلق حدMem_Buf_Limitعلى كل مُدخِل سلوك التوقف عند الامتلاء. تتحكمstorage.max_chunks_upفي عدد الأجزاء التي يمكن وجودها في الذاكرة في وقت واحد. بدون تخزين على نظام الملفات، يضيع كل ما هو مُخزَّن عند إعادة تشغيل العقدة. - Vector: مخازن مؤقتة صريحة لكل حوض — إما
memory(سريع، يضيع بالتعطل) أوdisk(متين، بتكلفة I/O). تتيح سياسةwhen_fullالاختيار بينblock(تطبيق الضغط العكسي مع خطر التباطؤ) وdrop_newest(قبول الخسارة لحماية الإنتاجية). اخترblockلسجلات الأخطاء، وdrop_newestللتدفقات debug عالية الحجم.
دليل اختيار الأداة
أكثر أوضاع الإخفاق شيوعاً في الإنتاج
- تلف سجل الموضع (Registry): إن حُذف ملف السجل أو اقتُطع — كما يحدث مع وحدة تخزين EmptyDir في Kubernetes — يُعيد الناقل الإرسال من بداية الملف. فيضان الأحداث المكررة يجتاح Elasticsearch ويُطلق عواصف من التنبيهات. الحل: استخدم وحدة تخزين
hostPathللسجل، لا وحدة تخزين مؤقتة للحاوية. - تسرب الحاصدات (Harvester leak): يفتح Filebeat مقبض ملف لكل ملف يحصده. في البيئات ذات آلاف الملفات المُدارة دورياً، يستنزف ذلك حد الملفات المفتوحة للعملية (
ulimit -n). اضبطclose_inactiveبحزم وارفع حد نظام التشغيل في وحدة systemd أو فيsecurityContextالـ DaemonSet. - تتالي مهل الإخراج: حين تكون الخلفية بطيئة، يُحجب الإخراج فيمتلئ الطابور الداخلي فيتوقف الحاصد. وخلال ذلك يستمر الملف في الكتابة. إن دارت دورة السجل خلال فترة التوقف، تضيع البيانات غير المقروءة بعد الدورة. استخدم مخزناً مؤقتاً دائماً على القرص كي يتمكن الناقل من التفريغ بشكل غير متزامن.
- انحراف الساعة والأحداث غير المرتبة: تنحرف ساعات الحاويات وساعات المضيف. أثرِ دائماً بطابع زمني من جانب الخادم في الناقل، واحتفظ بطابع التطبيق كحقل منفصل (
app_timestamp). لا تستخدم وقت الاستيعاب طابعاً زمنياً وحيداً أبداً.
/api/v1/metrics على المنفذ 2020؛ Vector: نقطة Prometheus على المنفذ 9598) وأنشئ تنبيهاً على output_events_dropped_total > 0. الإسقاط الصامت للأحداث هو أصعب إخفاقات التسجيل في الكشف عنه بعد وقوعه.