الإقليم ٣ — الموزِّع: Load Balancer وخوارزمياته
النبذة
قرّرنا في الإقليم ٢ أننا نريد نسختين تخدمان بدل واحدة، فبقي سؤالان معلّقان: من يوزّع المستخدمين على النسختين؟ وكيف يُخفى موتُ إحداهما؟ اسم الإجابة على السؤالين معاً هو load balancer. هنا يبدأ Task 1 فعلياً: ثلاثة خوادم — موزِّع (HAProxy) وخادمان خلفه.
لديك خادمان متطابقان، A و B، كلٌّ على IP خاص. لكن مستخدمك في العالم يعرف عنواناً واحداً (www.foobar.com ⟵ IP واحد من سجلّ A). كيف:
- يصل بعض المستخدمين إلى A وبعضهم إلى B، بعدالة، دون أن يعرف المستخدم بوجود اثنين؟
- وإذا مات B فجأةً، يتوقّف إرسال أحدٍ إليه فوراً دون أن يلاحظ أحد؟
صمّم الآلية على ورقة قبل أن تكمل. ستُجبر على اختراع شيءٍ يقف أمام الخادمين، يملك العنوان العام، ويقرّر لكل طلبٍ وجهته — وهذا بالضبط ما اخترعته الصناعة وسمّته load balancer.
الدرس
ليش يقف عنصرٌ أمام الخوادم — تعريف الموزّع
Load balancer: عنصرٌ يستقبل كل الطلبات الواردة على عنوانٍ واحد، ويوزّعها على عدّة خوادم خلفية (backends) وفق خوارزمية، ويتوقّف عن إرسالها لأي خادمٍ يكتشف أنه معطَّل.
لاحظ أنه يحلّ مشكلتين وُلدتا من التكرار دفعةً واحدة: توزيع الحِمل (لا يختنق خادمٌ بينما الآخر فارغ) وإخفاء الأعطال (يحوّل الحركة بعيداً عن الميت). من ناحية المستخدم، الموزّع هو الموقع: عنوانٌ واحد، خلفه ما خلفه.
تذكير دمج: الموزّع يعمل على مستوى TCP (L4) أو HTTP (L7) — وكلاهما بنيتَه في منهج الشبكات. الموزّع L4 يوزّع اتصالات TCP؛ الموزّع L7 يفهم HTTP ويوزّع حسب محتواه (المسار، الـ host). لا نعيد شرح الطبقات — نستعملها.
ليش «خوارزمية» — وكيف تعمل كلٌّ منها
«التوزيع بعدالة» ليس تعريفاً واحداً؛ العدالة تعتمد على ما تقيس. لذلك للموزّع خوارزمية توزيع (distribution algorithm). المشروع يسألك صراحةً «ما الخوارزمية وكيف تعمل»، فاعرف أشهرها واشتقّ منطق كلٍّ منها:
| الخوارزمية | كيف تعمل | متى تناسب |
|---|---|---|
| Round Robin | أعطِ الطلب التالي للخادم التالي بالدور، بالتناوب الدائري (A,B,A,B…). | الخوادم متماثلة والطلبات متشابهة. هي الافتراضية في HAProxy. |
| Weighted Round Robin | round robin لكن بأوزان: خادمٌ أقوى يأخذ نصيباً أكبر. | خوادم غير متماثلة القوة. |
| Least Connections | أعطِ الطلب للخادم صاحب أقل اتصالاتٍ نشطة الآن. | الطلبات متفاوتة المدّة (بعضها يدوم طويلاً). |
| Source IP Hash | احسب hash لـ IP المصدر، ووجّهه دائماً لنفس الخادم. | حين تريد أن يعود المستخدم لنفس الخادم (sticky). |
اختر واحدةً لمشروعك (round robin يكفي ووفّ الافتراضي)، لكن افهم لماذا قد تبدّلها: المعيار دائماً «ما الذي يجعل التوزيع عادلاً في حالتي؟».
ليش يحتاج الموزّع أن «يفحص» الخوادم — Health Checks
كيف يعرف الموزّع أن B مات ليتوقّف عن إرساله إليه؟ لا يعرف بالغيب — يفحص دورياً (health check): يرسل طلباً صغيراً لكل خادم (فتح TCP، أو طلب HTTP على مسارٍ صحّي) كل بضع ثوانٍ. إن فشل الردّ عدّة مرات، يضع الخادم خارج الخدمة (out of rotation) ويوقف الحركة عنه؛ وحين يعود، يعيده. هذا هو الجزء الذي «يُخفي العطل»: بدون health check، الموزّع سيظلّ يرسل ثلث مستخدميك إلى خادمٍ ميت.
ليش مصطلحا Active-Active و Active-Passive — الآن نحسمهما
زرعناهما في الإقليم ٢؛ الآن مع الموزّع بين أيدينا نوضّح الفرق الذي يسأل عنه المشروع مباشرةً:
- Active-Active: الموزّع يرسل حركةً حيّةً إلى كل الخوادم الخلفية في آنٍ واحد. كلها تعمل وتتقاسم الحِمل. ربحٌ مزدوج: تكرار + توزيع. هذا هو الوضع الطبيعي لموزّعٍ أمام خادمين متماثلين (حالة Task 1).
- Active-Passive: خادمٌ واحدٌ (active) يأخذ كل الحركة، وآخرُ (passive) ينتظر ساكناً يراقب. إن مات الـ active، يحدث failover: يتولّى الـ passive. لا توزيع حِمل هنا — فقط تأمينٌ ضد العطل. شائعٌ حيث لا يمكن للنسختين أن تعملا معاً (مثل قاعدة بياناتٍ بكاتبٍ واحد — إقليم ٤).
كيف تحدّد أيّهما يفعّله موزّعك؟ انظر: هل يستقبل خادمٌ واحدٌ فقط حركةً والباقي احتياط (passive)؟ أم تتدفّق الحركة لكل الخوادم (active)? في إعداد Task 1 المعتاد (round robin على خادمين)، فالموزّع Active-Active.
بذرة: الموزّع نفسه صار SPOF
طبّق العدسة فوراً: أضفنا الموزّع ليزيل SPOF الخادم — لكن الآن كل الحركة تمرّ عبر الموزّع الواحد. لو مات هو، مات الموقع كله، رغم أن الخادمين بصحّة. هذا التهديد الجديد هو ما يدفع Task 3 لاحقاً إلى عنقود موزّعات (LB cluster). سجّله في جدولك الثلاثي ولا تنسه.
ارسم مخطّط Task 1: موزّع HAProxy أمام خادمين، كلٌّ منهما يحوي web + app + db. لكل عنصرٍ أضفته عن Task 0 اكتب جملةً تجيب: لماذا أضفته؟ (هذا سؤال المشروع الحرفي «for every additional element, why you are adding it»). ثم جاوب على ورقة:
- ما خوارزمية موزّعك وكيف تعمل؟
- Active-Active أم Active-Passive، ولماذا؟
- أين الـ SPOF المتبقّية في هذا المخطّط؟ (تلميح: عنصران على الأقل — الموزّع، وشيءٌ في طبقة البيانات ستكتشفه في الإقليم ٤.)
الخلاصة — وصلٌ في الشجرة
- اشتققتَ load balancer كجوابٍ مزدوج: توزيع الحِمل + إخفاء العطل.
- ملكتَ الخوارزميات (round robin الافتراضي، weighted, least-conn, IP hash) ومنطق كلٍّ منها، وhealth checks كآلية كشف الموت.
- حسمتَ Active-Active مقابل Active-Passive بعد أن زرعتهما في الإقليم ٢.
- طبّقتَ العدسة: الموزّع وَلَدَ SPOF جديداً ⟵ بذرة Task 3.
البذرة الأكبر المتروكة: وزّعنا المستخدمين على خادمين بسهولة لأن الـ web/app عديما الحالة (stateless) — أي طلبٍ يصلح على أيّ خادم. لكن داخل كل خادمٍ قاعدة بيانات. ماذا لو كتب مستخدمٌ بياناً على خادم A وقرأه التالي من خادم B؟ البيانات لا تتوزّع كالكود. هذا هو الإقليم ٤ — أصعب أقاليم التكرار.
A load balancer (HAProxy) sits in front of the servers on the public IP and spreads incoming requests across them, while health-checking each backend so it stops sending traffic to a server that's down.
I configured it with Round Robin (HAProxy's default): each new request goes to the next server in turn. (Alternatives: weighted RR, least-connections, source-IP hash.)
Because traffic flows to both servers at once, this is Active-Active. In Active-Passive, only one server takes traffic and a standby takes over (failover) if it dies — that's redundancy without load sharing.
New SPOF introduced: the load balancer itself — we'll cluster it later.
وقفة الانضباط: «how the algorithm works» = جملة واحدة لكل خوارزمية. لا تشرح الأربع كلها ما لم يُطلب؛ اشرح المختارة، واذكر البدائل بالاسم.