Elasticsearch للمشغّلين
Elasticsearch للمشغّلين
تشغيل Elasticsearch في بيئة الإنتاج يختلف تمامًا عن تشغيله في بيئة تجريبية. في بيئات الحجم الكبير، الفرق بين كلاستر يصمد أمام ذروة استيعاب بيانات تبلغ 200 غيغابايت يوميًا وآخر ينهار يعود إلى أربعة أمور يجب أن تتحكم فيها بوصفك مشغّلًا: تصميم الـ Index، واستراتيجية الـ Shard، والالتزام بالـ Mapping، وإدارة دورة حياة الـ Index (ILM). هذا الدرس هو دليلك الميداني لكل هذه المحاور، إضافةً إلى إشارات صحة الكلاستر التي تنبّهك مبكرًا قبل وقوع الكارثة.
الـ Indices وما هي في الواقع
الـ Index في Elasticsearch هو الفضاء المنطقي الذي يجمع مجموعة من مستندات JSON المترابطة. تحت الغطاء، كل Index هو مجموعة من إندكسات Apache Lucene الفعلية. كل عملية كتابة تذهب إلى الـ Primary Shard ثم تُنسخ إلى الـ Replica Shards. القراءة يمكن أن تُخدَّم من أي منها — وبهذا يحقق Elasticsearch المتانة وقابلية التوسع في القراءة من نفس الكلاستر.
في حالة السجلات، نادرًا ما تُنشئ Index واحدًا ضخمًا. بدلًا من ذلك، تستخدم Data Stream، وهو سلسلة من الـ Indices المدعومة بطابع زمني وتُدار تلقائيًا. كل عملية كتابة على Data Stream تذهب دائمًا إلى الـ Index الحالي للكتابة (يُسمى "write backing index"). الـ Indices القديمة تصبح للقراءة فقط ويتولى ILM تدوير حذفها وفق السياسة المعرّفة.
@timestamp الذي تعتمد عليه استعلامات السجلات.
الـ Shards: وحدة التوسع ومصدر معظم مشكلات الإنتاج
الـ Shard هو إندكس Lucene مفرد. لكل Index عدد ثابت من الـ Primary Shards يُحدَّد عند الإنشاء — لا يمكن تغييره بدون إعادة فهرسة. لكل Shard عدد قابل للتهيئة من الـ Replica Shards. القواعد العملية المستخدمة في نشرات Elasticsearch الكبيرة هي:
- استهدف 20–50 غيغابايت لكل Shard. الـ Shards خارج هذا النطاق مشكلة: إذا كانت صغيرة جدًا، فإن عبء تنسيق آلاف الـ Shards يُدهور كمون الاستعلام؛ وإذا كانت كبيرة جدًا، تتعثر عمليات دمج القطاعات، ويطول التعافي بعد فشل العقدة، ويرتفع ضغط الذاكرة.
- Replica واحد على الأقل في الإنتاج. وجود صفر Replicas يعني أن أي فشل لعقدة يُسبب فقدانًا للبيانات وحالة احمرار للكلاستر.
- إجمالي عدد الـ Shards يُحدد استخدام الـ Heap. Elasticsearch يحتفظ ببيانات وصفية لكل Shard في الـ Heap. في بيئات الحجم الكبير، كل Shard يستهلك بضعة كيلوبايتات في كل عقدة. كلاستر يحوي 100,000 Shard سيُصاب بنفاد الذاكرة حتى على عقد بـ 64 غيغابايت.
لفحص توزيع الـ Shards الآن:
الـ Mappings: مخطط البيانات عند الكتابة
يُوصف Elasticsearch أحيانًا بأنه "بدون مخطط"، لكن هذا مضلل. ما يفعله فعليًا هو الـ Dynamic Mapping — أول مستند يصل يُحدد أنواع الحقول لكل المستندات اللاحقة. هذا خطير في خطوط معالجة السجلات. حقل يصل كـ long في سجلات خدمة واحدة ولكن كـ keyword في خدمة أخرى سيُولّد تعارضًا في الـ Mapping، مما يتسبب في رفض أحد المستندين بخطأ 400 وفقده بصمت اعتمادًا على إعداد الاستيعاب.
النمط المعتمد في الإنتاج هو تعريف Index Template صريح مع Component Templates تُثبّت الحقول المعروفة وتُهيّئ افتراضات منطقية للباقي. استخدم dynamic: strict للحقول التي تريد فيها تطبيقًا صارمًا، أو dynamic: true مع كتلة dynamic_templates تستقبل الحقول غير المتوقعة وتُعيّنها كـ keyword بدلًا من السماح لـ Elasticsearch باكتشاف نوع رقمي أو تاريخ قد يتعارض لاحقًا.
norms: false على حقل message. الـ Norms تخزّن بيانات تطبيع طول المستند لكل حقل لأغراض ترتيب مدى الصلة — لا فائدة منها في استعلامات السجلات حيث يهمك المطابقة الدقيقة لا ترتيب BM25. تعطيلها يوفر نحو بايت واحد لكل مستند لكل حقل، وهو ما يتراكم ليصل إلى غيغابايتات في الكلاسترات ذات الحجم الكبير.
إدارة دورة حياة الـ Index (ILM)
ILM هو محرك السياسات الذي ينقل الـ Indices عبر مراحل محددة — hot → warm → cold → frozen → delete — كلما تقدم عمرها. في كلاسترات السجلات هذا ليس خيارًا: بدون ILM، تمتلئ الأقراص وستجد نفسك تحذف الـ Indices يدويًا في الثالثة صباحًا.
المحركات الرئيسية للانتقال هي شروط التدوير (Rollover Conditions) في المرحلة الساخنة: عندما يصل Index إلى حد أقصى للعمر أو الحجم أو عدد المستندات، يُنشئ ILM Index جديدًا للكتابة ويصبح القديم للقراءة فقط ويبدأ انتقاله نحو الدفء. الحدود النموذجية في شركة متوسطة الحجم: تدوير عند max_age: 1d أو max_size: 40gb، انتقال للـ Warm بعد يومين (دمج قسري إلى قطعة واحدة + تقليص الـ Shards)، انتقال للـ Cold بعد 7 أيام (تحميل كـ Searchable Snapshot على التخزين السحابي)، حذف بعد 30–90 يومًا (نافذة الامتثال التنظيمي).
قراءة صحة الكلاستر
يعرض Elasticsearch صحة الكلاستر كـ أخضر / أصفر / أحمر. الأحمر يعني أن Shard أساسيًا واحدًا على الأقل غير موزّع — بعض البيانات غير متاحة والكتابات على ذلك الـ Shard مرفوضة. الأصفر يعني أن جميع الـ Primary Shards موزّعة لكن Replica Shard واحدًا على الأقل غير موزّع — الكلاستر يعمل بشكل كامل لكنه بدون تكرار لتلك الـ Shards. الأخضر يعني أن كل شيء موزّع وبصحة جيدة.
في كلاستر سجلات الإنتاج، حالة صفراء مستمرة خلال إعادة تشغيل متدرجة متوقعة ومقبولة. الأحمر هو دائمًا حادثة. أسرع مسار للفرز هو:
- تحقق من
GET /_cluster/health?pretty— انظر إلىunassigned_shardsوactive_shards_percent_as_number. - نفّذ
GET /_cluster/allocation/explain— سيخبرك Elasticsearch بالضبط لماذا الـ Shard غير موزّع (حد القرص، لا عقد مؤهلة، إلخ). - إذا كانت حدود القرص هي السبب، الحدود الافتراضية هي 85% (منخفض — إيقاف توزيع الـ Replicas)، 90% (مرتفع — نقل الـ Shards بعيدًا)، 95% (مرحلة الفيضان — جميع الـ Indices تصبح للقراءة فقط). تحقق بـ
GET /_cat/nodes?v&h=name,diskUsed,diskAvail,diskTotal,diskPercent.
jvm.mem.heap_used_percent على كل عقدة. فوق 85% استخدام للـ Heap، يبدأ مجمع القمامة (GC) في الـ JVM بالتسبب في توقفات لعدة ثوانٍ. هذا هو السبب الثاني الأكثر شيوعًا لحوادث Elasticsearch في الإنتاج بعد تكاثر الـ Shards. اضبط تنبيهًا عند 75% Heap، وتنبيهًا حرجًا عند 85%.
عادات المشغّل الاحترافي
- اختبر دائمًا سياسة ILM جديدة على Data Stream غير إنتاجي قبل تطبيقها على Indices الإنتاج — إجراء
shrinkمدمّر ولا يمكن التراجع عنه. - حدد أولوية Index Template الخاص بك (استخدم قيمًا مثل 200) حتى لا تتجاوزها القوالب المدمجة في Elastic ذات الأولوية 100 بشكل غير متوقع.
- استخدم
GET /_data_stream/logs-app-*لرؤية أي Backing Indices موجودة وأيها هو Index الكتابة الحالي — هذا أول ما تتحقق منه عند توقف وصول السجلات. - تجنب
_forcemergeعلى الـ Indices الساخنة. إنها عملية كثيفة الاستخدام للـ I/O وتتنافس مع الفهرسة النشطة ويمكن أن تزعزع استقرار العقدة تحت الحمل.