Grafana Loki
Grafana Loki
يقوم Elasticsearch بفهرسة كل رمز في كل سطر سجل. هذا النهج القوي لكنه مكلف: بيئة سجلات بحجم 1 تيرابايت يومياً تحتاج عادةً إلى 3-5 أضعاف ذلك في تخزين Elasticsearch (الفهارس والنسخ الاحتياطية وعمليات دمج الأجزاء) وكلستر يكلف آلاف الدولارات شهرياً. صُمم Grafana Loki من قِبل فريق Grafana Labs للإجابة على سؤال مختلف: ماذا لو خزّنّا السجلات بنفس الطريقة التي يخزّن بها Prometheus المقاييس؟ نفهرس التصنيفات فقط، نضغط النص الخام، ونستعلم بشكل كسول عند وقت القراءة. النتيجة تكلفة أقل بكثير مع مقايضة في سرعة الاستعلام الخام التي نادراً ما تكون عنق الزجاجة في التحقيق الفعلي من الحوادث.
يأخذك هذا الدرس في عمق معمارية Loki ولغة استعلامه LogQL والمواقف التشغيلية التي يتفوق فيها Loki، حتى تتمكن من اختيار الأداة المناسبة وتشغيلها بشكل صحيح في الإنتاج.
الفهرسة القائمة على التصنيفات مقابل الفهرسة النصية الكاملة
في Elasticsearch، يُحلَّل كل سطر سجل عند الاستيعاب: كل كلمة وكل رقم وكل حقل يصبح إدخالاً في فهرس مقلوب. هذا يجعل البحث النصي الكامل العشوائي فورياً، لكنه يعني أيضاً أن الفهرس يمكن أن يكون أكبر من البيانات الخام بسهولة. يحترق المعالج عند الاستيعاب لتحليل الرموز ودمج الأجزاء؛ وتحترق الذاكرة عند الاستعلام لتحميل قوائم النشر.
يتبع Loki النهج المعاكس. عند الاستيعاب، يستخرج فقط التصنيفات التي تعلنها — أزواج مفتاح-قيمة ثابتة يرفقها ناقل السجلات، مثل app="api-gateway" وenv="production" وnamespace="payments". هذه التصنيفات تعرّف تدفقاً. داخل كل تدفق، تُحزَم سطور السجلات في أجزاء مضغوطة (Snappy أو LZ4 افتراضياً) وتُكتب في التخزين الكائني (S3, GCS, Azure Blob). يعيش فهرس التصنيفات في مخزن صغير — كان Cassandra أو BoltDB في البداية، والآن فهرس TSDB المدمج الذي جاء في Loki 2.8. عند الاستعلام، يحدد Loki أولاً التدفقات المطابقة عبر التصنيفات، ثم يفك ضغط الأجزاء ذات الصلة فقط ويطبق أي تعبيرات تصفية على النص الخام في الذاكرة. فكر في الأمر على أنه grep على سجلات مضغوطة مع بوابة تصنيفية.
|= و|~ وخطوط أنابيب المحلل) مخصصة لإيجاد ماذا داخل تلك التدفقات. إذا لامس استعلامك عدداً كبيراً جداً من التدفقات، فسيكون بطيئاً. وإذا كان لدى تدفق ما عدد كبير جداً من السطور في الثانية، تكبر الأجزاء وتصبح عملية فك الضغط هي عنق الزجاجة — كلاهما مشكلة في تصميم التصنيفات.
معمارية Loki
يعمل نشر Loki الإنتاجي في وضع الخدمات المصغرة مع مكونات قابلة للتوسع بشكل مستقل:
- Distributor — يستقبل طلبات الدفع من Promtail/Alloy/Fluent Bit عبر نقطة نهاية HTTP
/loki/api/v1/push. يتحقق من صحة التصنيفات ويفرض حدود المعدل ويوزع على Ingesters عبر حلقة التجزئة المتسقة. - Ingester — يحتفظ بسجل الكتابة المسبقة (WAL) في الذاكرة والأجزاء المفتوحة. يُفرغ الأجزاء المختومة إلى التخزين الكائني ويكتب الفهرس إلى مخزن TSDB. وسّعه أفقياً؛ استخدم WAL على SSD محلي للمتانة.
- Querier — يتعامل مع طلبات
/loki/api/v1/query_range. يجلب البيانات من Ingesters في الذاكرة (البيانات الحديثة) ومن التخزين الكائني (البيانات القديمة)، يدمج النتائج ويطبق خطوط أنابيب LogQL. - Query Frontend — يشظّي الاستعلامات ذات النطاق الزمني الطويل، يخزّن النتائج مؤقتاً، ويضع طلبات في قوائم الانتظار للعدالة. انشر هذا دائماً أمام Queriers على نطاق واسع.
- Ruler — يقيّم قواعد LogQL من نوع المقياس (التنبيه والتسجيل) وفق جدول زمني، مطابق في المفهوم لقواعد Prometheus.
- Compactor — يدمج بشكل دوري أجزاء فهرس TSDB الصغيرة ويفرض الاحتفاظ عبر علامات الحذف في التخزين الكائني.
LogQL — لغة استعلام Loki
صُممت LogQL عن قصد على غرار PromQL. يبدأ كل استعلام بـمحدد تدفق السجل — مجموعة من مطابقات التصنيفات في أقواس متعرجة — يتبعها مراحل خط الأنابيب الاختيارية التي تصفي وتحوّل سطور السجل.
المراحل الرئيسية في خط الأنابيب هي:
| json/| logfmt/| pattern/| regexp— تحليل السطر الخام إلى حقول|= "string"/!= "string"/|~ "regex"/!~ "regex"— مرشحات السطر (سريعة؛ تُطبق قبل فك الضغط في إصدارات Loki الأحدث)| field_name = "value"— مرشحات التصنيف على الحقول المستخرجة| line_format "template"— إعادة تشكيل سطر الإخراج باستخدام صياغة قالب Go| unwrap field_name— استخراج حقل رقمي لتجميع المقاييس (rate, avg_over_time, quantile_over_time)
{app="checkout", env="production"} يمسح أجزاء أقل بكثير مقارنة بـ{env="production"} وحده. الاستعلام الذي يلمس أكثر من ~200 تدفق سيكون بطيئاً بغض النظر عن كفاءة خط أنابيب التصفية.
تصميم التصنيفات: القرار التشغيلي الأهم
تتصرف التصنيفات في Loki بشكل مطابق للتصنيفات في Prometheus: كل مجموعة فريدة من قيم التصنيفات تنشئ تدفقاً جديداً. الكثير من التدفقات — الأساسية العالية — يدمر ميزة التكلفة في Loki لأن فهرس TSDB ينفجر وتصبح ملفات الأجزاء صغيرة جداً (نسبة ضغط منخفضة). الأنماط المضادة الكلاسيكية هي:
- استخدام
user_idأوrequest_idأوtrace_idكتصنيف. هذه تنتمي داخل سطر السجل، وتُستخرج عند وقت الاستعلام بخط أنابيب المحلل. - استخدام اسم الـ pod أو تجزئة النشر كتصنيف في Kubernetes — استخدم
podباعتدال وفضّلapp/component. - ترميز مستوى الخطورة كتصنيف (مثل
level="error") عندما يكون الحقل موجوداً بالفعل داخل حمولة JSON — حلّله باستخدام| json | level="error"عند وقت الاستعلام بدلاً من ذلك.
مجموعة آمنة للبداية في بيئة Kubernetes هي: cluster وnamespace وapp وenv. كل شيء آخر — اسم المضيف واسم الـ pod ومستوى السجل ومعرف التتبع — يعيش داخل سطر السجل ويُستخرج عبر خطوط أنابيب المحلل.
نشر Loki مع Promtail على Kubernetes
متى يفوز Loki (ومتى لا يفوز)
يفوز Loki عندما:
- تشغّل بالفعل Grafana وPrometheus وتريد حزمة مراقبة موحدة دون فريق Elasticsearch منفصل.
- حجم السجلات مرتفع (مئات الجيجابايت يومياً) والتكلفة قيد — تخزين S3 أرخص بـ10-30 مرة من أقراص Elasticsearch EBS لكل جيجابايت.
- تتبع الاستعلامات نمطاً معروفاً: "أرني سجلات من هذه الخدمة في هذا النطاق الزمني خلال نافذة الحادثة." الاسترجاع القائم على التصنيفات سريع لهذا العبء.
- تحتاج إلى ربط السجلات بالمقاييس والتتبعات في لوحة Grafana واحدة — تربط طريقة عرض Loki's Explore مباشرة بتتبعات Tempo عبر حقول
traceID.
يواجه Loki صعوبات عندما:
- تحتاج إلى بحث نصي كامل عشوائي شبه فوري عبر جميع السجلات في آن واحد (أدوات الامتثال، التحقيق الجنائي في الأنماط غير المعروفة). Elasticsearch أسرع هنا.
- سير عمل فريقك مبني حول واجهة مستخدم Kibana — LogQL لها منحنى تعلم وـ Grafana Explore ليست بديلاً مباشراً.
- لديك سجلات غير منظمة وبتنسيقات غير متسقة من أنظمة قديمة حيث التحليل غير موثوق — الفهرس النصي الكامل لـ Elasticsearch أكثر تسامحاً.
retention_enabled: true في إعدادات Compactor وكان مكون Compactor يعمل فعلاً. يكتشف كثير من الفرق بعد 90 يوماً أن حاوية S3 الخاصة بهم قد نمت دون حدود. تحقق دائماً باستخدام aws s3 ls s3://my-loki-chunks --recursive --summarize | tail -2 بعد أسبوع من التشغيل.
التنبيه مع Loki Ruler
يقيّم Loki Ruler تعبيرات المقاييس في LogQL وفق جدول زمني ويطلق تنبيهات متوافقة مع Prometheus. عرّف القواعد بنفس تنسيق YAML كـ Prometheus:
تُحمَّل القواعد عبر Ruler API أو تُخزَّن في التخزين الكائني (بادئة S3). تمر التنبيهات عبر Alertmanager بشكل مطابق لـ Prometheus. يتيح لك هذا الحفاظ على شجرة توجيه تنبيهات واحدة لكل من التنبيهات القائمة على المقاييس والسجلات.