بنية أنظمة الدردشة اللحظية: من WebSockets إلى Message Queues

بنية أنظمة الدردشة اللحظية: من WebSockets إلى Message Queues

أنظمة الدردشة اللحظية (Real-Time Chat Systems) أصبحت جزءًا أساسيًا من أغلب التطبيقات الحديثة: منصات الدعم الفني، تطبيقات العمل الجماعي، الألعاب، وحتى تطبيقات التجارة الإلكترونية. لكن خلف واجهة الدردشة البسيطة، توجد بنية معمارية معقدة تتعامل مع اتصالات مستمرة، عدد ضخم من الرسائل، وضمان وصولها بأقل زمن تأخير ممكن.

في هذا المقال سنحلل Real Time Chat Architecture من زاوية هندسة البرمجيات، بداية من طبقة الاتصال باستخدام WebSockets، مرورًا بـ Message Queues وPub/Sub، وحتى قواعد البيانات الموزعة ومعضلات التوسّع (Scalability) والموثوقية (Reliability).

ما المقصود بـ Real Time Chat Architecture؟

ببساطة، Real Time Chat Architecture هي التصميم المعماري للنظام الذي يسمح بتبادل الرسائل فورًا تقريبًا بين المستخدمين، مع:

  • زمن تأخير (Latency) منخفض.
  • دعم آلاف أو ملايين الاتصالات المتزامنة.
  • إمكانية التوسع أفقيًا (Scale Out) بسهولة.
  • ضمان تسليم الرسائل وترتيبها قدر الإمكان.

أي تطبيق دردشة حديث يحتاج إلى بنية تدعم:

  • قناة اتصال ثنائية الاتجاه (Full-Duplex) مثل WebSockets.
  • طبقة لتوجيه الرسائل بين الخوادم (Message Broker / Message Queues).
  • تخزين دائم للرسائل (Persistent Storage) باستخدام قاعدة بيانات مناسبة.
  • آليات Presence (معرفة من المتصل الآن) وTyping Indicators وRead Receipts.

الطبقة الأولى: WebSockets كقناة اتصال لحظية

بروتوكول HTTP التقليدي مبني على طلب/استجابة (Request/Response)، وهذا يجعل بناء دردشة حقيقية فوقه تحديًا. هنا يأتي دور WebSockets، وهو بروتوكول يسمح بإنشاء اتصال مستمر وثنائي الاتجاه بين العميل (المتصفح أو التطبيق) والخادم.

لماذا WebSockets في أنظمة الدردشة؟

  • اتصال مستمر بدون الحاجة لعمل Polling متكرر.
  • إرسال واستقبال الرسائل في اتجاهين في أي وقت.
  • تقليل الحمل على الخادم مقارنة بـ Long Polling التقليدي.

إذا كنت تعمل بـ Django أو FastAPI، يمكنك الاطلاع على تطبيق عملي لبناء شات لحظي في مقال: شرح WebSockets في Django وFastAPI: بناء شات لحظي.

كيف يعمل WebSocket في سياق Real Time Chat Architecture؟

  1. المستخدم يفتح تطبيق الدردشة، فينشئ اتصال WebSocket مع خادم الـ Chat.
  2. الخادم يحتفظ باتصال حي (Open Connection) مع كل عميل متصل.
  3. عند إرسال رسالة، يرسل العميل البيانات عبر WebSocket إلى الخادم.
  4. الخادم لا يرد فقط على نفس الاتصال، بل قد يرسل نفس الرسالة لمستخدمين آخرين عبر اتصالاتهم المفتوحة.

الكود في الجانب الخلفي (Back-End) غالبًا يعتمد على إطار مثل:

الطبقة الثانية: غرف الدردشة (Rooms) وإدارة الجلسات

أغلب أنظمة الدردشة لا تتعامل مع قناة واحدة فقط، بل مع:

  • محادثات فردية (One-to-One Chats).
  • مجموعات (Group Chats).
  • قنوات (Channels) أو غرف دردشة (Rooms).

المفاهيم الأساسية هنا:

  • Connection: اتصال WebSocket بين مستخدم وخادم.
  • Session/User: هوية المستخدم المرتبطة بهذا الاتصال.
  • Room/Channel: مجموعة من المستخدمين تُبث إليها الرسائل.

كيف نربط الاتصال بغرفة chat؟

عند اتصال المستخدم، يقوم الخادم بـ:

  1. مصادقة المستخدم (JWT, Cookies, Token…).
  2. تخزين معلومات الاتصال في Memory أو Cache (مثل Redis) مع معرف المستخدم.
  3. انضمام الاتصال إلى قناة/غرفة (Join Room) غالبًا في الـ WebSocket Layer أو عبر Message Broker.

في Django Channels مثلاً، يتم استخدام Channel Layers (غالبًا مع Redis) لتوصيل الرسائل بين عمليات مختلفة في الخادم، بحيث يمكن بث الرسالة لجميع الاتصالات المشتركة في نفس الغرفة.

الطبقة الثالثة: Message Queues وPub/Sub

في التطبيقات الصغيرة، يمكن لخادم واحد أن يستقبل رسائل WebSocket ويُرسلها مباشرة للمستخدمين المتصلين. لكن عندما يزداد عدد المستخدمين، نحتاج إلى فصل مكوّنات النظام عن بعضها (Decoupling) واستخدام Message Queues أو نظام Pub/Sub.

لماذا نستخدم Message Queues في Real Time Chat Architecture؟

  • التوسع الأفقي: عندما يكون لديك عدة خوادم Chat، تحتاج لقناة مشتركة لتبادل الرسائل بين هذه الخوادم.
  • ضمان التسليم: بعض الـ Message Brokers تدعم إعادة المحاولة (Retry) والـ Acknowledgements.
  • فصل المسؤوليات: خادم الاستقبال (Gateway) وخادم المعالجة (Processor) وخادم التخزين (Storage) يمكن أن تكون مكونات مستقلة.

يمكن استخدام نظم مثل:

  • RabbitMQ كـ Message Queue كلاسيكي (Queues, Exchanges).
  • Kafka كمنصة Streaming وPub/Sub عالية الأداء.
  • Redis Pub/Sub كحل بسيط وسريع، خاصة للتطبيقات متوسطة الحجم.

سيناريو نموذجي لتدفق الرسائل

  1. العميل يرسل رسالة عبر WebSocket إلى خادم الـ Gateway.
  2. خادم الـ Gateway يتحقق من:
    • صلاحيات المستخدم.
    • تنسيق الرسالة (Validation).
  3. الخادم ينشر (Publish) الرسالة في موضوع (Topic) معين داخل Message Broker (مثلاً Topic خاص بالغرفة).
  4. خوادم أخرى مشترِكة (Subscribers) في هذا الـ Topic تستقبل الرسالة:
    • خادم مسؤول عن بث الرسالة للمستخدمين المتصلين (Delivery Service).
    • خادم مسؤول عن تخزين الرسالة في قاعدة البيانات (Persistence Service).

هذا النمط يشبه إلى حد كبير تصميم نظام Notifications قابل للتوسع باستخدام Message Queues كما في المقال: تصميم نظام Notifications قابل للتوسع باستخدام Message Queues.

الطبقة الرابعة: قواعد البيانات وتخزين الرسائل

نقطة محورية في أي Real Time Chat Architecture هي كيفية اختيار وتكوين قاعدة البيانات لتخزين:

  • الرسائل (Messages).
  • قوائم المحادثات (Conversations / Threads).
  • حالة الرسالة (مقروءة/غير مقروءة، وقت التسليم، وقت القراءة).
  • حالة المستخدم (Online/Offline) – غالبًا تُخزن في Cache وليس في DB مباشرة.

هل أستخدم SQL أم NoSQL؟

الجواب يعتمد على حجم التطبيق وخصائصه، لكن شائع في أنظمة الدردشة:

  • Relational DB (مثل PostgreSQL, MySQL):
  • NoSQL (مثل MongoDB, Cassandra):
    • مناسبة للتوسع الأفقي جدًا.
    • مناسبة لتخزين الرسائل كسجلات (Events) بزمن معين.
    • أضعف نوعًا ما في العلاقات المعقدة والاستعلامات المتقدمة.

نموذج بيانات شائع للرسائل

غالبًا ما يكون لدينا جداول/Collections مثل:

  • users: بيانات المستخدمين.
  • conversations: تمثل محادثة فردية أو جماعية.
  • conversation_participants: ربط المستخدمين بالمحادثات.
  • messages:
    • id
    • conversation_id
    • sender_id
    • content (نص، ملف، صورة…)
    • created_at (وقت الإرسال)
    • delivered_at, read_at (اختياري)

مع الحجم الكبير للرسائل، من الضروري:

  • استخدام فهارس على الأعمدة: conversation_id, created_at.
  • تقسيم الجداول (Sharding/Partitioning) عندما يكبر النظام.

المعادلة الصعبة: Consistency vs Availability

في أنظمة موزعة (Distributed Systems)، هناك دائمًا توازن (Trade-offs) بين:

  • اتساق البيانات (Consistency): أن ترى كل العقد (Nodes) نفس الحالة في نفس الوقت.
  • التوافر (Availability): قدرة النظام على الاستجابة دائمًا حتى مع فشل بعض العقد.

في Real Time Chat Architecture، غالبًا:

  • نقبل ببعض التأخير البسيط في مزامنة الرسائل بين الأجهزة (Eventual Consistency).
  • نُعطي الأولوية لتجربة المستخدم (سرعة ظهور الرسالة) على الاتساق القوي في كل اللحظات.

مثال:

  • المستخدم يرسل رسالة من الهاتف.
  • يتم إرسالها فورًا للطرف الآخر (عبر WebSocket وMessage Broker).
  • تُحفظ في قاعدة البيانات، وقد تتأخر أجزاء من الثانية قبل المزامنة مع نسخة أخرى من قاعدة البيانات أو مع جهاز آخر للمستخدم نفسه.

Presence وTyping Indicators وRead Receipts

هذه الميزات تبدو صغيرة، لكنها معمارياً تضيف تعقيدًا:

  • Presence (متصل/غير متصل):
    • تُدار عادةً في طبقة In-Memory مثل Redis.
    • كل اتصال WebSocket يسجّل نفسه كـ Online، وعند الانقطاع يتم تحديث حالته.
  • Typing Indicators:
    • أحداث قصيرة العمر (Short-lived Events).
    • يمكن إرسالها عبر WebSocket دون تخزين دائم في DB.
  • Read Receipts:
    • عند قراءة الرسالة، يرسل العميل حدثًا (Message Read Event).
    • يتم تحديث حالة الرسالة في DB، وبث التغيير للطرف الآخر.

التحكم في الحمل والتوسع (Scalability)

أي Real Time Chat Architecture ناجح يجب أن يدعم التوسع التدريجي. بعض التقنيات الأساسية:

1. فصل الأدوار (Microservices أو على الأقل Logical Separation)

  • خادم Gateway للتعامل مع WebSockets والاتصالات الواردة.
  • خدمة Message Processing لمعالجة الرسائل والمنطق التجاري (Business Logic).
  • خدمة Storage للتعامل مع قاعدة البيانات.
  • خدمة Notification للتنبيهات الخارجية (Push Notifications على الجوال مثلًا).

2. استخدام Load Balancer

لتوزيع اتصالات WebSocket على عدة خوادم، مع الانتباه إلى:

  • دعم الـ Sticky Sessions إذا كان لا بد أن يبقى المستخدم مع نفس الخادم.
  • أو استخدام Message Broker بحيث يمكن لأي خادم التعامل مع أي رسالة دون الاعتماد على خادم محدد.

3. Caching وIn-Memory Stores

  • Redis أو Memcached لتخزين:
    • Presence.
    • آخر الرسائل أو ملخصات المحادثات (للأداء العالي).

الأمان في أنظمة الدردشة اللحظية

جانب لا يمكن تجاهله في أي Real Time Chat Architecture هو الأمان:

  • المصادقة (Authentication):
    • جعل اتصال WebSocket يعتمد على توكن آمن (JWT, OAuth2…).
    • التحقق من صلاحيات المستخدم في كل حدث مهم (إرسال رسالة، الانضمام لغرفة…).
  • التشفير (Encryption):
    • استخدام WSS (WebSocket فوق TLS) لحماية البيانات أثناء النقل.
    • في تطبيقات حساسة، يمكن تطبيق تشفير End-to-End على مستوى التطبيق نفسه.
  • التحكم في المعدل (Rate Limiting):
    • منع إرسال رسائل بوتيرة عالية (Spam / Abuse).
    • تنفيذ Limits على مستوى المستخدم أو IP أو Token.

مثال مبسط على بنية Real Time Chat Architecture

لنربط كل ما سبق في صورة معمارية مبسطة:

  1. المستخدم يفتح تطبيق الويب أو الموبايل:
    • يتم إنشاء اتصال WebSocket مع Gateway Service.
    • يتم التحقق من JWT وتحديد هوية المستخدم.
  2. إرسال رسالة:
    • العميل يرسل JSON عبر WebSocket (message, conversation_id …).
    • Gateway ينشر الحدث في Topic داخل Message Broker (مثلاً: chat.conversation.<id>).
  3. معالجة وتخزين:
    • Message Processor يستهلك الرسالة:
      • يتحقق أن المرسل عضو في هذه المحادثة.
      • يضيف Metadata (وقت الإرسال، معرف الرسالة الفريد…).
      • يرسلها إلى Storage Service لتخزينها في DB.
  4. التسليم للمستقبل:
    • خدمة Delivery تشترك في نفس Topic:
      • تحدّد من هم المستلمون المتصلون حاليًا (من Redis مثلاً).
      • تبث الرسالة عبر اتصالات WebSocket المفتوحة معهم.
      • إن لم يكونوا متصلين، تسجل ذلك ليتم إرسال Push Notification لاحقًا.

خلاصة: كيف تفكر معماريًا عند بناء نظام دردشة لحظي؟

عند تصميم Real Time Chat Architecture، فكر في الطبقات بشكل منفصل:

  • طبقة الاتصال: WebSockets (أو بدائل مثل WebRTC في بعض الحالات) لإدارة الاتصال اللحظي.
  • طبقة التوجيه: Message Queues / Pub/Sub لفصل استقبال الرسائل عن معالجتها وتسليمها.
  • طبقة التخزين: قاعدة بيانات (SQL أو NoSQL) مع تصميم جداول وفهارس ملائم لحجم الرسائل.
  • طبقة الحالة اللحظية: Presence, Typing, Read Receipts غالبًا فوق In-Memory Store مثل Redis.
  • طبقة الأمان والتوسع: مصادقة قوية، تشفير، Rate Limiting، Load Balancing، وفصل للخدمات.

كلما نمت قاعدة المستخدمين وزادت المتطلبات (مثل إرسال مرفقات، دعم الفيديو، دعم البحث المتقدم)، ستحتاج إلى تطوير هذه البنية تدريجيًا، لكن فهم الأساسيات: WebSockets + Message Queues + قواعد البيانات الموزعة، هو نقطة الانطلاق لبناء نظام دردشة حديث، قابل للتوسع، وموثوق.

حول المحتوى:

تحليل معماري لكيفية بناء أنظمة الدردشة الحديثة مع WebSockets وقواعد البيانات الموزعة.

هل كان هذا مفيدًا لك؟

أضف تعليقك