الشبكات والاتصال

مشروع: تصميم طبقة الاتصال

18 دقيقة الدرس 10 من 10

مشروع: تصميم طبقة الاتصال

قضيت الدروس التسعة الماضية في بناء مفردات تقنية: توجيه IP، ونظام أسماء النطاقات، وHTTP/HTTPS، وTCP مقابل UDP، وREST، وgRPC، وWebSockets، وبوابات API، وSSE، والاستطلاع الطويل. يجمع هذا الدرس الختامي كل ذلك معاً في تطبيق عملي. ستعمل على تصميم تطبيق تعاون في الوقت الفعلي لتحرير المستندات (على غرار Notion أو Figma)، وستتخذ كل قرار يتعلق بالبروتوكولات وشكل الواجهة البرمجية من الصفر، مع تبرير صريح لكل اختيار.

هدف هذا الدرس: تطوير عادة التعامل مع اختيار البروتوكول باعتباره قراراً هندسياً، لا مجرد تفصيل تنفيذي. عند كل حدود في بنيتك المعمارية، اسأل: ما البيانات التي تتدفق هنا؟ وبأي تكرار؟ وما حساسيتها للتأخير؟ وما أنماط الفشل المهمة؟ إجاباتك هي التي تحدد الاختيار.

النظام الذي نصممه

ملخص المنتج: محرر مستندات تعاوني يمكن لـ 500 مستخدم تحرير نفس مساحة العمل فيه بشكل متزامن. تشمل الميزات: المؤشرات الحية، ومزامنة النصوص الفورية، والتعليقات، ومرفقات الملفات، وتدفق الإشعارات. يجب أن يدعم النظام 10 ملايين مستخدم مسجل مع وصول أقصى للمحررين المتزامنين إلى 50,000.

سنصمم طبقة الاتصال فقط — لا محرك التخزين ولا شبكة توصيل المحتوى — بل البروتوكولات وأشكال الواجهة البرمجية وتدفقات الرسائل التي تربط العملاء بالخوادم والخدمات ببعضها.

الخطوة الأولى — رسم خريطة لكل حدود اتصال

قبل اختيار أي بروتوكول، حدد ما يتواصل فعلياً. في نظامنا، هناك خمسة حدود متمايزة:

  1. المتصفح ↔ بوابة API — إجراءات المستخدم (إنشاء مستند، دعوة متعاون)
  2. المتصفح ↔ خدمة التعاون — التعديلات الفورية ومواضع المؤشرات
  3. المتصفح ↔ خدمة الإشعارات — تحديثات التدفق (تمت إضافة تعليق، ذكر)
  4. بوابة API ↔ الخدمات المصغرة الداخلية — استدعاءات بين الخدمات (المصادقة، البحث، الفوترة)
  5. الخدمات ↔ ناقل الرسائل — توزيع الأحداث غير المتزامن (تم حفظ المستند ← تشغيل المفهرس، إشعار المشتركين)

رسم خريطة الحدود أولاً يمنع الخطأ الشائع المتمثل في اختيار بروتوكول واحد لكل شيء ثم محاولة تكييفه مع الحالات التي لا يناسبها.

الخطوة الثانية — تطبيق معايير القرار على كل حدود

الحدود الأولى — المتصفح إلى بوابة API (إجراءات CRUD)

البيانات: إنشاء/قراءة/تحديث/حذف المستندات، وإدارة المستخدمين، ورفع البيانات الوصفية. النمط: طلب-استجابة، مدفوع بإجراء صريح من المستخدم. هدف التأخير: 200–500 ميلي ثانية مقبول. الاختيار: REST عبر HTTPS.

يفوز REST هنا لأن: الموارد تتناسب بشكل طبيعي مع مسارات URL مثل /docs/{id} و/workspaces/{id}/members؛ وتخزين HTTP المؤقت (ETags، Cache-Control) يقلل حمل القراءة؛ ويتعامل معه fetch() في المتصفح بشكل أصلي؛ وتُفهم دلالات الأخطاء (400، 401، 404، 409، 422) من قِبل كل مطور frontend. استخدم هيئة JSON للطلبات والاستجابات. قسّم المجموعات الكبيرة باستخدام التقسيم المستند إلى المؤشر بدلاً من الإزاحة — التقسيم بالإزاحة غير متسق في ظل الكتابات المتزامنة.

أضف إصدارات لواجهة REST من اليوم الأول. استخدم بادئة URL مثل /v1/ وليس ترويسة. الترويسات غير مرئية في عناوين URL للمتصفح وأصعب في التوجيه. عندما تكسر عقداً، زِد الإصدار — لا تغيّر الاستجابات بصمت.

الحدود الثانية — المتصفح إلى خدمة التعاون (التعديلات الفورية)

البيانات: تحولات عملياتية أو CRDTs — عمليات دلتا صغيرة جداً مثل "أدخل الحرف X في الموضع 47"، عشرات في الثانية لكل مستخدم نشط. النمط: ثنائي الاتجاه، مستمر، منخفض التأخير، عالي التكرار. الاختيار: WebSockets.

هذه هي حالة الاستخدام المثالية لـ WebSocket. يحتاج كل من العميل والخادم إلى الإرسال في أي لحظة؛ وسيضيف الاستطلاع تأخيراً غير مقبول. اتصال WebSocket واحد لكل علامة تبويب يحمل جميع عمليات المستندات وأحداث المؤشرات وإشارات الحضور بتأخير ذهاب وإياب أقل من 100 ميلي ثانية.

استخدم تنسيق رسائل ثنائي مضغوط مثل MessagePack بدلاً من JSON. عند وجود 50,000 محرر متزامن يولد كل منهم 20 عملية في الثانية، تضيف كثافة JSON تكاليف CPU وعرض نطاق ترددي حقيقية.

الحدود الثالثة — المتصفح إلى خدمة الإشعارات (تحديثات التدفق)

البيانات: أحداث مثل "علّقت آنا على مستندك"، "تصديرك جاهز". النمط: يرسل الخادم بشكل متقطع؛ لا يرسل العميل أبداً. هدف التأخير: 5–30 ثانية مقبول. الاختيار: SSE (الأحداث المرسلة من الخادم).

SSE أبسط من WebSockets للإرسال أحادي الاتجاه: استجابة HTTP/2 عادية لا تنتهي، ترسل قطع text/event-stream. تُعيد واجهة EventSource الأصلية للمتصفح الاتصال تلقائياً عند الانقطاع. تجنب مصافحة ترقية WebSocket، ويتشارك الاتصال نفس اتصال HTTP/2 مع استدعاءات REST.

الحدود الرابعة — بوابة API إلى الخدمات المصغرة الداخلية

البيانات: استدعاءات RPC هيكلية — "تحقق من رمز المصادقة هذا"، "ابحث في المستندات لهذا المستخدم". النمط: داخلي، متزامن، حساس للتأخير، صارم في المخطط. الاختيار: gRPC.

يُسلسل gRPC عبر HTTP/2 باستخدام Protocol Buffers — أصغر بـ 3–10 مرات من JSON وأسرع في الترميز. يوفر عقوداً قوية النوع يُنفذها الكود المولّد. ينخفض التأخير لاستدعاء التحقق من الرمز من ~2 ميلي ثانية (REST/JSON) إلى ~0.3 ميلي ثانية (gRPC/Protobuf) — توفير ذو معنى عندما يقع في المسار الحرج لكل طلب.

الحدود الخامسة — الخدمات إلى ناقل الرسائل (الأحداث غير المتزامنة)

البيانات: أحداث نطاق مثل DocumentSaved، CommentCreated، UserInvited. النمط: توزيع، منتجون ومستهلكون منفصلون، تسليم مرة واحدة على الأقل. الاختيار: رسائل غير متزامنة (Kafka أو ما شابهه) مع مخطط حدث محدد.

هذه الحدود ليست HTTP على الإطلاق. عند حفظ مستند، يجب ألا تُجري خدمة التعاون استدعاءات HTTP متزامنة إلى المفهرس والمُشعر ومسجّل التدقيق — هذا الاقتران الشديد يُبطئ الحفظ ويُتتالى الإخفاقات. بدلاً من ذلك، انشر حدثاً واحداً إلى موضوع؛ يقرأ كل مستهلك داخلي بشكل مستقل.

الخطوة الثالثة — مخطط البنية الكاملة

Communication layer architecture for the collaborative document editor Browser Client (User) API Gateway TLS Termination Rate Limiting Collaboration Service Notification Service Auth Service Message Bus Kafka / Queue Indexer Consumer REST WebSocket SSE gRPC events REST (HTTPS) WebSocket SSE gRPC (internal) Async Events (Kafka)
طبقة الاتصال الكاملة: كل حدود تستخدم البروتوكول الأنسب لشكل بياناتها ومتطلبات التأخير.

الخطوة الرابعة — التعامل مع الحالات الصعبة

إعادة الاتصال واستعادة الحالة لـ WebSockets

تنقطع اتصالات الهواتف المحمولة باستمرار. عند إعادة اتصال عميل بخدمة التعاون، يُرسل آخر رقم تسلسلي شاهده (مثلاً { "reconnect": true, "last_seq": 1482 }). يُعيد الخادم إرسال أي عمليات فات العميل منذ ذلك الرقم. بدون هذا، ينحرف العميل المُعاد اتصاله بصمت عن حالة المستند.

التدهور الرشيق لـ SSE

إذا كان المستخدم خلف وكيل HTTP/1.1 يخزّن هيئة الاستجابة مؤقتاً، تنكسر SSE بصمت. نفّذ نبضة قلب كل 30 ثانية. إذا لم يتلقَ العميل نبضة خلال 45 ثانية، انتقل تلقائياً إلى الاستطلاع الطويل كل 15 ثانية. ظهور ارتفاع في حركة الاستطلاع الطويل يُشير إلى مشكلة بنية تحتية.

الضغط الخلفي على ناقل الرسائل

إذا تأخر مستهلك المفهرس (مثلاً أثناء إعادة الفهرسة)، يتراكم تأخر موضوع Kafka. لا تدع المنتجين يتعطلون — بدلاً من ذلك، اضبط حداً أقصى للتنبيه (مثلاً 100,000 رسالة) وقُم بتوسيع المستهلكين أفقياً. يجب ألا تنتظر خدمة التعاون أبداً على المستهلكين البعيدين.

الخطوة الخامسة — جدول ملخص القرارات

Protocol decision summary table Boundary Protocol Key Reason Browser → API Gateway REST / HTTPS Cacheable, standard HTTP errors Browser → Collab Service WebSocket Bidirectional, sub-100 ms, high freq Browser → Notification Svc SSE Server-push only, simpler than WS Gateway → Microservices gRPC Typed contract, low latency, binary Services → Event Bus Async Messaging Decoupled fan-out, burst absorption لا يوجد بروتوكول واحد صحيح لجميع الحدود — طابق الأداة مع نمط الاتصال.
ملخص اختيار البروتوكول: كل حدود في النظام تُعيَّن إلى البروتوكول الذي يناسب نمط تفاعلها.

العقلية التي تأخذها معك

المخرج الحقيقي من هذا التمرين ليس اختياراً محدداً للبروتوكول — بل هو إطار اتخاذ القرار:

  • الاتجاه: أحادي (SSE) أم ثنائي الاتجاه (WebSocket)؟
  • التكرار: متقطع (REST) أم مستمر (WebSocket / gRPC streaming)؟
  • الاقتران: متزامن (REST، gRPC) أم غير متزامن (ناقل الرسائل)؟
  • الجمهور: عملاء خارجيون يحتاجون إلى قابلية التشغيل البيني (REST) أم خدمات داخلية تحتاج إلى الأداء (gRPC)؟
  • نمط الفشل: ماذا يحدث إذا كان المستهلك بطيئاً أو معطلاً؟ هل يتعطل المنتج؟
أكثر الأخطاء شيوعاً في مقابلات تصميم الأنظمة هو استخدام نفس البروتوكول في كل مكان — "REST لكل شيء" أو "WebSockets لكل شيء". يبحث المحاورون عن المرشحين القادرين على تبرير اختيار بروتوكول محدد عند حدود معينة، بما في ذلك ما استبعدوه ولماذا.
تمرين تطبيقي: خذ أي نظام تستخدمه يومياً — Slack، أو Google Docs، أو Uber، أو Twitter — وارسم خريطة لحدود اتصاله. لكل حدود، افترض البروتوكول الذي يستخدمونه على الأرجح ولماذا. ستبدأ في ملاحظة أنماط: تتبع الموضع الفوري هو WebSocket دائماً تقريباً؛ شارات الإشعارات هي SSE أو long-poll دائماً تقريباً؛ استدعاءات الخدمات الداخلية غالباً gRPC؛ واجهات برمجة التطبيقات العامة هي REST. بناء هذه الحدسية الآن يجعل قرارات البروتوكول في المقابلات والعمل تبدو طبيعية.

الشبكات والاتصالات هي النسيج الضام لكل نظام موزع. لديك الآن المفردات الكاملة وإطار القرار. طبّقهما باستمرار في كل مرة ترسم فيها مخططاً معمارياً.

اكتمل الدرس!

تهانينا! لقد أكملت جميع الدروس في هذا البرنامج التعليمي.