السجلات على نطاق واسع: ELK وLoki

مكدس ELK

18 دقيقة الدرس 3 من 28

مكدس ELK

مكدس ELK — الذي يضم Elasticsearch وLogstash وKibana — هو الحل مفتوح المصدر الأكثر انتشاراً لتركيز السجلات في القطاع. تُشغّل شركات كبرى مثل Netflix وLinkedIn وUber وGoldman Sachs هذا المكدس على نطاق يُقدَّر بالبيتابايت. فهم بنيته التحتية هو الأساس لكل عمل تشغيلي على السجلات بمعايير الشركات التقنية الكبرى.

بنية المكوّنات الثلاثة

لكل مكوّن وظيفة واحدة، والفصل بينها مقصود. كسر هذا الحد هو أحد أكثر أسباب حوادث ELK الإنتاجية شيوعاً.

  • Elasticsearch — محرك بحث وتحليلات موزّع يعتمد الفهرس المقلوب. يخزّن السجلات ويفهرس كل حقل، وينفّذ الاستعلامات عبر تيرابايتات في أجزاء من الثانية. تُكتب السجلات في فهارس مختومة بالتاريخ مثل logs-app-2025.06.11. يُقسَّم كل فهرس إلى أجزاء (shards) موزّعة على العقد وتُنسخ لضمان التوافر.
  • Logstash (أو عقد Elastic Ingest) — طبقة الاستيعاب والتحويل. تستقبل بثوث السجلات الخام وتحوّلها إلى JSON منظّم باستخدام مرشحات Grok وDissect وCSV، وتثري الحقول بمعلومات GeoIP وعميل المستخدم، ثم تُعيد توجيهها إلى Elasticsearch. تعمل أيضاً كمخزن مؤقت عند حدوث ضغط خلفي.
  • Kibana — واجهة التصوير والاستعلام. يستخدم المهندسون تبويب Discover لإجراء بحث بـ KQL (لغة استعلام Kibana)، وبناء لوحات المعلومات بمخططات التجميع، وإعداد قواعد التنبيه. في الإنتاج، تُعدّ أيضاً نقطة الدخول لـ APM وإدارة Fleet.
ELK Stack Architecture App Logs System Logs K8s Events Beats / Agents Filebeat Metricbeat Fluentd / Fluent Bit OpenTelemetry Logstash Input plugins Filter (Grok/Dissect) Enrich (GeoIP) Output plugins Elasticsearch Cluster (3+ nodes) Node 1 Node 2 Node 3 Node 4 Shards + Replicas Kibana Log Sources Ship & Buffer Parse & Enrich Store & Visualise
مكدس ELK: تتدفق السجلات من المصادر عبر وكلاء خفيفي الوزن إلى Logstash للتحليل والإثراء، ثم إلى مجموعة Elasticsearch التي يستعلم عنها Kibana.

Elasticsearch: ما يجب أن يعرفه المشغّل

يستخدم Elasticsearch فهرساً مقلوباً — يُفهرَس كل رمز في كل حقل عند الكتابة. هذا هو السبب في أن البحث النصي الكامل عبر مليارات سطور السجلات يستغرق أجزاء من الثانية، لكنه يعني أيضاً أن معدل الكتابة واستخدام القرص يبلغان 3 إلى 5 أضعاف حجم السجلات الخام. يُقسَّم كل فهرس إلى أجزاء أساسية (primary shards) كأهداف كتابة، وأجزاء نسخية (replica shards) لتوسعة القراءة والتوافر العالي. الأجزاء الخاطئة هي السبب الأكثر شيوعاً لتراجع أداء مجموعات Elasticsearch في الإنتاج.

الإفراط في التجزيء يُدمّر المجموعات. توصية فريق Elastic نفسه هي جزء واحد لكل 30 إلى 50 غيغابايت من البيانات. الآلاف من الأجزاء الصغيرة — وهو خطأ شائع عند إنشاء فهارس يومية بالإعدادات الافتراضية — تُثقل عقد الماستر بالبيانات الوصفية، مما يُسبّب بطء البحث وفي نهاية المطاف أعطالاً بسبب نفاد الذاكرة. استخدم ILM (إدارة دورة حياة الفهرس) وحدّد number_of_shards صراحةً في قالب الفهرس.

Logstash: خط أنابيب الاستيعاب

يتكوّن خط أنابيب Logstash من ثلاثة أقسام: input (مصدر السجلات) وfilter (كيفية تحليلها وإثرائها) وoutput (وجهتها). أهم مرشح هو Grok، الذي يطابق سطور السجل النصي الحر مع أنماط regex مسمّاة.

# /etc/logstash/conf.d/nginx.conf input { beats { port => 5044 } } filter { if [fields][log_type] == "nginx_access" { grok { match => { "message" => '%{IPORHOST:client_ip} - %{USER:ident} \[%{HTTPDATE:timestamp}\] "%{WORD:method} %{DATA:request} HTTP/%{NUMBER:http_version}" %{NUMBER:status:int} %{NUMBER:bytes:int} "%{DATA:referrer}" "%{DATA:user_agent}"' } } date { match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"] target => "@timestamp" } geoip { source => "client_ip" target => "geoip" } mutate { remove_field => ["message", "timestamp", "agent"] } } if "_grokparsefailure" in [tags] { drop {} } } output { elasticsearch { hosts => ["https://es-node-1:9200", "https://es-node-2:9200"] index => "nginx-access-%{+YYYY.MM.dd}" user => "logstash_writer" password => "${LOGSTASH_ES_PASSWORD}" ssl_certificate_authorities => ["/etc/logstash/certs/ca.crt"] } }
فضّل Elastic Ingest Pipelines للتحليل البسيط. Logstash عملية JVM ثقيلة تحتاج من 1 إلى 4 غيغابايت من الكومة وضبطاً دقيقاً. لاستخراج الحقول والإثراء البسيط، تُلغي خطوط أنابيب Ingest Node المدمجة في Elasticsearch (تعمل على جانب الخادم وتُعرَّف عبر الـ API) رحلة Logstash بالكامل وتقلّل التعقيد التشغيلي. احتفظ بـ Logstash لمنطق التوجيه المعقد، أو الوجهات المتعددة، أو أعباء التحويل الثقيلة.

Kibana: الاستعلام ولوحات المعلومات

تتصل Kibana بـ Elasticsearch عبر REST API وتوفّر عرض Discover للتحقيقات الآنية ومحرّر Dashboard للتصورات الدائمة. لغة الاستعلام هي KQL (لغة استعلام Kibana)، وهي صياغة مبسّطة فوق Elasticsearch DSL.

# أمثلة KQL في Kibana Discover # البحث عن جميع أخطاء 5xx من خدمة الدفع status >= 500 and service.name : "checkout-api" # أخطاء من pod محدد في آخر 15 دقيقة (الوقت النسبي في منتقي الوقت) kubernetes.pod.name : "checkout-api-*" and log.level : "error" # طلبات بطيئة (زمن الاستجابة > 2000 مللي ثانية) لا تأتي من فحوصات الصحة الداخلية duration_ms > 2000 and NOT http.url : "/health" # المعادل بـ Elasticsearch DSL (ما تبنيه Kibana داخلياً) POST /nginx-access-*/_search { "query": { "bool": { "filter": [ { "range": { "status": { "gte": 500 } } }, { "term": { "service.name": "checkout-api" } } ] } }, "sort": [{ "@timestamp": "desc" }], "size": 200 }

أنماط الفشل في الإنتاج

ثلاثة أنماط فشل تُسبّب غالبية حوادث ELK الإنتاجية:

  1. ضغط الكومة وتوقفات جمع القمامة. عقد Elasticsearch عمليات JVM. عندما يتجاوز استخدام الكومة 75%، يبدأ جامع القمامة في التسبب في توقفات تمتد لثوانٍ، مما يُبطّئ الاستيعاب وزمن استجابة الاستعلامات. الحد الصارم هو 50% من الذاكرة المتاحة، بحد أقصى 31 غيغابايت (بسبب OOPs المضغوطة). راقب jvm.mem.heap_used_percent كمقياس Prometheus حرج.
  2. الانقسام الدماغي (Split-brain). في Elasticsearch 7 وما بعده، حُلّت هذه المشكلة إلى حدٍ بعيد بفضل تنسيق المجموعة المبني على Raft، لكنها قد تظهر إذا كان discovery.seed_hosts مُهيَّأ بشكل خاطئ أو حدثت انقسامات شبكية. دائماً شغّل عدداً فردياً من العقد المؤهلة لدور الماستر (3 أو 5) وحدّد cluster.initial_master_nodes بشكل صحيح عند التمهيد الأول فقط.
  3. توقف خط أنابيب Logstash. إذا تعرّض Elasticsearch لضغط خلفي (قرص ممتلئ، أو قاطع دائرة مفتوح)، تمتلئ قائمة انتظار Logstash الدائمة. بدون تفعيل قائمة الانتظار الدائمة (queue.type: persisted)، تُحذف سطور السجل بصمت. فعّل دائماً قائمة الانتظار الدائمة في الإنتاج وحجّمها لاستيعاب 30 دقيقة على الأقل من ذروة الاستيعاب.
بنية hot-warm-cold. على نطاق واسع، تشغيل جميع البيانات على عقد NVMe سريعة مكلف للغاية. يدعم Elasticsearch التخزين متعدد المستويات عبر سياسات ILM: تعيش السجلات على عقد ساخنة (SSD) لأول 7 أيام، ثم تنتقل إلى عقد دافئة (أقراص HDD أكبر، نسخ متماثلة مخفّضة) لمدة 30 يوماً، ثم تنتقل إلى باردة (للقراءة فقط، لقطات قابلة للبحث في S3) للاحتفاظ طويل الأمد. هذه هي البنية القياسية في أي منظمة تستوعب أكثر من 50 غيغابايت يومياً.

خط الأمان الأساسي

لا تشغّل ELK أبداً بدون تفعيل الأمان. أفضت إمكانية الوصول الافتراضية المفتوحة لـ Elasticsearch إلى آلاف قواعد البيانات المكشوفة للعموم. منذ Elasticsearch 8.0، الأمان (TLS + مصادقة أساسية) مفعّل افتراضياً. للعمليات الموجودة:

  • فعّل TLS على جميع اتصالات inter-node والاتصالات من العميل إلى العقدة (xpack.security.enabled: true، xpack.security.http.ssl.enabled: true).
  • استخدم حسابات خدمة مخصصة بأقل الامتيازات (logstash_writer role: الكتابة فقط في أنماط فهارس محددة؛ kibana_read_only لمستهلكي لوحات المعلومات).
  • لا تكشف أبداً منفذ HTTP الخاص بـ Elasticsearch (9200) للإنترنت — ضعه خلف مجموعة أمان VPC أو جدار حماية، ليكون متاحاً فقط من طبقة الاستيعاب وKibana.