موازنة التحميل
موازنة التحميل
لا يستطيع خادم واحد تحمّل عدد غير محدود من الاتصالات المتزامنة دون أن ترتفع التأخيرات وتنتهي مهل الطلبات. تحلّ موازنة التحميل هذه المشكلة بتوزيع حركة المرور الواردة على مجموعة من الخوادم الخلفية (تُعرف بـالمصادر العليا أو خوادم الأصل). على نطاق الشركات الكبرى، لا تُعدّ موازنات التحميل مجرد أدوات أداء — فهي الآلية الأساسية لـالنشر دون توقف، وعزل الأعطال، والتوسع الأفقي.
Service بين الاثنين: يحتفظ kube-proxy بقواعد iptables/IPVS التي توازن التحميل تلقائياً على حزم Pod الصحيحة.
L4 مقابل L7: أين يتخذ القرار في المكدس؟
الخيار التصميمي الأهم هو ما إذا كان موازن التحميل يعمل على مستوى الطبقة الرابعة (النقل) أو الطبقة السابعة (التطبيق).
موازنة تحميل الطبقة 4 تعمل على مستوى TCP/UDP. يُعيد الموازن توجيه تدفقات البايت دون فحص الحمولة. يرى عنوان IP الوجهة والمنفذ، يختار خادماً خلفياً، ويُنشئ اتصالَي TCP — أحدهما من العميل إلى الموازن ("الواجهة الأمامية")، والآخر من الموازن إلى الخادم الخلفي ("اتصال الخلفية") — ويربطهما معاً. وهو سريع للغاية ويعمل مع أي بروتوكول TCP/UDP.
موازنة تحميل الطبقة 7 تُنهي بروتوكول التطبيق (HTTP، gRPC، WebSocket). يُحلّل الموازن طلب HTTP بالكامل قبل توجيهه، مما يتيح اتخاذ قرارات بناءً على مسار URL، ورأس المضيف، والكوكيز، ومعاملات الاستعلام، أو جسم الطلب. تأتي هذه الإمكانية المتقدمة مع تأخير إضافي (~1-5 مللي ثانية لكل قفزة عند التحميل العالي) وتعقيد أكبر.
في الواقع العملي، تجمع بيئات الإنتاج في الغالب بين النوعين: موازن تحميل L4 (مثل AWS NLB أو GCP TCP Proxy) عند حافة الشبكة للإنتاجية العالية والثبوتية، يُغذّي وكلاء L7 عكسية (nginx، Envoy، HAProxy) تتولى التوجيه بناءً على المحتوى وإنهاء TLS.
خوارزميات موازنة التحميل
تُحدد الخوارزمية أيّ خادم خلفي يستقبل الطلب التالي. الاختيار الخاطئ يُسبب نقاط ساخنة حتى في مجموعة "متوازنة".
- Round Robin (التناوب الدائري) — تتناوب الطلبات على الخوادم بالتسلسل. بسيط وعادل عندما تكون جميع الخوادم متماثلة وتكلفة الطلبات موحدة. الإعداد الافتراضي في معظم الوكلاء.
- Weighted Round Robin (التناوب المرجّح) — تحصل الخوادم على نسبة من الحركة تتناسب مع وزن مُعيَّن. مفيد خلال النشر التجريبي (10% للإصدار الجديد، 90% للمستقر) أو عند اختلاف القدرات.
- Least Connections (أقل الاتصالات) — يذهب الطلب التالي إلى الخادم ذي أقل اتصالات نشطة. أفضل من Round Robin للاتصالات طويلة الأمد (WebSocket، gRPC streaming، اتصالات قواعد البيانات).
- IP Hash / Sticky Sessions (التثبيت) — يُجزئ IP العميل (أو كوكيز) لربطه دائماً بنفس الخادم. ضروري للتطبيقات التي تخزن بيانات الجلسة في الذاكرة. نمط مضادّ خطير في الخدمات المصغرة عديمة الحالة لأنه يمنع التوزيع المتوازن.
- Power of Two Choices (قوة الاختيارين) — اختيار خادمَين عشوائيَّين والتوجيه لأقلّهما اتصالات. يُحقق توزيعاً شبه مثالي بتكلفة O(1). مستخدم داخلياً في Envoy وكثير من الأنظمة الكبرى.
- Least Response Time (أقل وقت استجابة) — يوجّه إلى الخادم ذي أدنى متوسط تأخير. مفيد عند تفاوت أداء الخوادم.
فحوصات الصحة: قلب موازن التحميل العامل
موازن التحميل لا يتجاوز جودة فحوصاته. بدونها، سيُرسل بسعادة الحركةَ إلى خادم يستمع على المنفذ لكنه يُعيد 500 — وهو أسوأ أنواع الأعطال لأنه صامت من منظور العميل.
ثلاثة أنواع من فحوصات الصحة، بترتيب متصاعد التطور:
- فحص TCP — يفتح الموازن اتصال TCP إلى الخادم. إذا اتصل، يُعدّ الخادم "نشطاً". يُثبت أن العملية تستمع لكن ليس أنها تستطيع تقديم الخدمة فعلاً.
- فحص HTTP — يُرسل الموازن طلب HTTP (عادةً
GET /healthz) ويتوقع استجابة 2xx ضمن مهلة. المعيار للخدمات HTTP. - فحص مستوى التطبيق — يُرسل الموازن طلباً إلى نقطة نهاية
/readyzيتحقق فيها تطبيقك بنشاط: هل مجموعة اتصالات قاعدة البيانات سليمة؟ هل الكاش متاح؟ هل العمال الخلفيون يعملون؟ هذا ما تُطبّقه مسبارات الجاهزية في Kubernetes.
تهيئة nginx L7 حقيقية: مجموعة Upstream مع فحوصات صحة
HAProxy: مثال كامل على L4 + L7
معاملات مهمة: inter 2s — المسح كل ثانيتين؛ fall 3 — وضع علامة "معطل" بعد 3 فشل متتاليين؛ rise 2 — استعادة الخدمة بعد نجاحَين متتاليَّين. عدم التماثل (3 للتعطيل / 2 للاستعادة) مقصود: تريد التأكد من أن الخادم فعلاً سليم قبل إرسال حركة إنتاج إليه.
معمارية الطبقة المتوازنة
أنماط الفشل الشائعة في الإنتاج
- القطيع الرعدي بعد إعادة تشغيل الخادم — عند عودة الخادم للعمل، ترسل إليه جميع الموازنات الحركة المتراكمة في آنٍ واحد. خففه بالتدريج التدريجي:
slowstart 30sفي HAProxy، أوslow_start_windowفي Envoy. - تذبذب فحوصات الصحة — خادم يتردد بين الصحة والمرض مما يُسبب توجيهاً غير منتظم. اضبط
rise(2-3 نجاح على الأقل قبل الاستعادة) وأضف تشويشاً لفترات الفحص لمنع تزامن جميع الموازنات. - الجلسات الثابتة تُخفي السعة — مع IP hash، يُثبَّت عميل ثقيل واحد على خادم بعينه. تحت الحركة العالية من CDN (كل الحركة تبدو قادمة من بضعة عناوين IP)، يمكن أن يُفرط هذا في تحميل خادم واحد بينما يخمل الباقون. الحل: استخدام الثبات عبر كوكيز، أو — الأفضل — إزالة حالة الجلسة من الخادم.
- استنفاد مجموعة الاتصالات — يحتفظ الموازن بـ1000 اتصال keepalive لخادم يقبل 100 فقط. اضبط
keepaliveفي كتلة upstream لقيمة أقل من حدmax_connectionsللخادم.
Kubernetes: موازنة التحميل التلقائية
في Kubernetes، كل خدمة ClusterIP هي IP افتراضي مدعوم بقواعد iptables أو IPVS يُديرها kube-proxy. عند إنشاء Deployment بـ5 نسخ متماثلة، يُضيف kube-proxy تلقائياً قواعد توزّع الحركة (سلسلة احتمالات عشوائية في iptables أو least-connections في IPVS) على عناوين IP الـPods الصحيحة. يُزيل متحكم نقاط النهاية Pod من شريحة نقاط النهاية فور فشل مسبار جاهزيته — قبل إنهاء الـPod.
النقاط الرئيسية
- موازنات L4 تُمرّر تدفقات TCP دون تحليل الحمولة — سريعة، تعمل مع أي بروتوكول، لكن بلا توجيه URL.
- موازنات L7 تُحلّل HTTP — تتيح التوجيه بالمسار/المضيف، وإنهاء TLS، والتلاعب بالرؤوس، وإعادة المحاولة الذكية.
- اختيار الخوارزمية مهم: least connections للاتصالات الطويلة أو متغيرة التكلفة؛ round robin فقط عند تماثل الطلبات والخوادم.
- فحوصات الصحة يجب أن تتحقق من جاهزية التطبيق الفعلية، لا مجرد توافر المنفذ. فرّق بين liveness وreadiness.
- صمّم للفشل: التدريج التدريجي، وعدم تماثل rise/fall، وحدود مجموعة الاتصالات تمنع الأعطال المتسلسلة.
- في Kubernetes، يتولى كائن Service + kube-proxy موازنة L4 تلقائياً؛ أضف Ingress controller (nginx، Envoy/Contour) لـL7.