في تصميم النظام الحديث، تركز الهندسة المعمارية المحفزة بالأحداث (EDA) على إنشاء واكتشاف واستخدام والاستجابة للأحداث داخل النظام. الأحداث هي الحوادث الهامة التي يمكن أن تؤثر على الأجهزة أو البرمجيات في النظام، مثل إجراءات المستخدم، تغييرات الحالة، أو تحديثات البيانات.

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

التطبيقات الجديدة والحديثة الآن تعتمد بشكل كبير على معالجة البيانات في الوقت الحقيقي والاستجابة الفورية. لا يمكن المبالغة في أهمية الهندسة المعمارية المحفزة بالأحداث لأنها توفر الإطار الذي يدعم تلك المتطلبات. من خلال استخدام الاتصال الغير متزامن والتفاعل المحفز بالأحداث، يمكن للأنظمة التعامل بكفاءة مع حجم كبير من المعاملات والحفاظ على الأداء تحت حمولات غير مستقرة. تُقدّر هذه الميزات بشكل خاص في البيئات التي تكون فيها التغييرات عفوية للغاية، مثل منصات التجارة الإلكترونية أو تطبيقات الإنترنت للأشياء (IoT).

بعض المكونات الرئيسية للهندسة المعمارية المحفزة بالأحداث تشمل:

  • مصادر الأحداث: وهذه هي المنتجات التي تولّد الأحداث عندما تحدث إجراءات هامة داخل النظام. أمثلة على ذلك تشمل تفاعلات المستخدمين أو تغييرات البيانات.

  • المستمعون: هذه الكيانات التي تشترك في الأحداث المحددة وتستجيب عند حدوث تلك الأحداث. يتيح المستمعون للنظام الاستجابة ديناميكيًا للتغييرات.

  • المعالجون: هؤلاء مسؤولون عن معالجة الأحداث بمجرد اكتشافها من قبل المستمعين، وتنفيذ المنطق التجاري الضروري أو سياق العمل الذي يتم تشغيله بواسطة الحدث.

في هذه المقالة، ستتعلم كيفية تنفيذ معالجة البيانات المستندة إلى الأحداث باستخدام Traefik، Kafka، و Docker.

هنا تطبيق بسيط مستضاف على GitHub يمكنك تشغيله بسرعة للحصول على نظرة عامة على ما ستقوم ببنائه اليوم.

جدول المحتويات

إليك ما سنغطيه:

لنبدأ!

المتطلبات الأساسية

قبل أن تبدأ:

  • نشر نسخة من أوبونتو 24.04 بذاكرة وصول عشوائي بحجم 4 غيغابايت على الأقل وحد أدنى من 20 غيغابايت من مساحة القرص الحرة لاستيعاب صور Docker وحاويات وبيانات كافكا.

  • الوصول إلى النسخة باستخدام مستخدم غير جذري يمتلك امتيازات sudo.

  • تحديث فهرس الحزم.

sudo apt update

فهم التقنيات

أباتشي كافكا

أباتشي كافكا هو منصة تدفق أحداث موزعة مصممة لخطوط أنابيب البيانات ذات الطاقة الكبيرة وتطبيقات التدفق في الوقت الحقيقي. يعمل كظهرية لتنفيذ EDA من خلال إدارة بشكل كفء حجم كبير من الأحداث. يستخدم كافكا نموذج النشر والاشتراك حيث يرسل المنتجون الأحداث إلى مواضيع، ويشترك المستهلكون في هذه المواضيع لاستقبال الأحداث.

بعض ميزات كافكا الرئيسية تشمل:

  • عالية الطاقة الاستيعابية: يمكن لكافكا التعامل مع ملايين الأحداث في الثانية مع تأخير منخفض، مما يجعله مناسبًا لتطبيقات الحجم الكبير.

  • تحمل الأخطاء: تضمن البنية الموزعة لـ Kafka قدرة البيانات على التحمل والتوفر حتى في حالة فشل الخادم. يتم نسخ البيانات عبر عدة وسطاء داخل العنقود.

  • التوسيعية: يمكن لـ Kafka أن تتوسع بسهولة أفقيًا من خلال إضافة مزيد من الوسطاء إلى العنقود أو الأجزاء إلى المواضيع، مما يلبي احتياجات البيانات المتزايدة دون إعادة تكوين كبيرة.

ترافيك

ترافيك هو بروكسي HTTP عكسي وموازن حمل حديث مصمم خصيصًا لبنية الخدمات الصغيرة. يكتشف تلقائيًا الخدمات التي تعمل في بنيتك التحتية ويوجه حركة المرور وفقًا لذلك. يبسط ترافيك إدارة الخدمات الصغيرة عن طريق توفير إمكانيات التوجيه الديناميكي بناءً على بيانات خدمة.

بعض الميزات الرئيسية لـ ترافيك تشمل:

  • تكوين ديناميكي: يقوم ترافيك تلقائيًا بتحديث تكوين التوجيه الخاص به عند إضافة الخدمات أو إزالتها، مما يقضي على التدخل اليدوي.

  • توازن الحمل: يوزع الطلبات الواردة بكفاءة عبر عدة حالات خدمة، مما يحسن الأداء والموثوقية.

  • لوحة تحكم متكاملة: يوفر Traefik لوحة تحكم سهلة الاستخدام لمراقبة حركة المرور وصحة الخدمة في الوقت الحقيقي.

من خلال استخدام Kafka وTraefik في هندسة الأحداث، يمكنك بناء أنظمة استجابية تتعامل بكفاءة مع معالجة البيانات في الوقت الحقيقي مع الحفاظ على التوفرية العالية والقابلية للتوسيع.

كيفية إعداد البيئة

كيفية تثبيت Docker على أوبونتو 24.04

  1. قم بتثبيت الحزم المطلوبة.
sudo apt install ca-certificates curl gnupg lsb-release
  1. أضف المفتاح العام الرسمي لـ Docker.
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
  1. أضف مستودع Docker إلى مصادر APT الخاصة بك.
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  1. قم بتحديث فهرس الحزم مرة أخرى وقم بتثبيت محرك Docker مع ملحق Docker Compose.
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
  1. تحقق للتأكد من التثبيت.
sudo docker run hello-world

الناتج المتوقع:

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
Digest: sha256:305243c734571da2d100c8c8b3c3167a098cab6049c9a5b066b6021a60fcb966
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

كيفية تكوين Docker Compose

يبسط Docker Compose إدارة التطبيقات متعددة الحاويات، مما يتيح لك تعريف الخدمات وتشغيلها في ملف واحد.

  1. أنشئ دليل مشروع
mkdir ~/kafka-traefik-setup && cd ~/kafka-traefik-setup
  1. أنشئ ملف docker-compose.yml.
nano docker-compose.yml
  1. أضف التكوين التالي إلى الملف لتعريف خدماتك.
version: '3.8'

services:
  kafka:
    image: wurstmeister/kafka:latest
    ports:
      - "9092:9092"
    environment:
      KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:9092,OUTSIDE://localhost:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
      KAFKA_LISTENERS: INSIDE://0.0.0.0:9092,OUTSIDE://0.0.0.0:9092
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181

  zookeeper:
    image: wurstmeister/zookeeper:latest
    ports:
      - "2181:2181"

  traefik:
    image: traefik:v2.9
    ports:
      - "80:80"       # حركة HTTP
      - "8080:8080"   # لوحة تحكم Traefik (غير آمنة)
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"

احفظ تغييراتك باستخدام ctrl + o، ثم اخرج باستخدام ctrl + x.

  1. ابدأ خدماتك.
docker compose up -d

الناتج المتوقع:

[+] Running 4/4
 ✔ Network kafka-traefik-setup_default        Created                  0.2s
 ✔ Container kafka-traefik-setup-zookeeper-1  Started                  1.9s
 ✔ Container kafka-traefik-setup-traefik-1    Started                  1.9s
 ✔ Container kafka-traefik-setup-kafka-1      Started                  1.9s

كيفية بناء النظام المحفز بالأحداث

كيفية إنشاء منتجي الأحداث

لإنتاج الأحداث في Kafka، ستحتاج إلى تنفيذ منتج Kafka. فيما يلي مثال باستخدام Java.

  1. أنشئ ملف kafka-producer.java.
nano kafka-producer.java
  1. أضف التكوين التالي لمُنتج Kafka.
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;

import java.util.Properties;

public class SimpleProducer {
    public static void main(String[] args) {
        // قم بإعداد خصائص المُنتج
        Properties props = new Properties();
        props.put("bootstrap.servers", "localhost:9092");
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

        // أنشئ المُنتج
        KafkaProducer<String, String> producer = new KafkaProducer<>(props);

        try {
            // أرسل رسالة إلى الموضوع "my-topic"
            ProducerRecord<String, String> record = new ProducerRecord<>("my-topic", "key1", "Hello, Kafka!");
            RecordMetadata metadata = producer.send(record).get(); // إرسال متزامن
            System.out.printf("Sent message with key %s to partition %d with offset %d%n", 
                              record.key(), metadata.partition(), metadata.offset());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // أغلق المُنتج
            producer.close();
        }
    }
}

احفظ تغييراتك باستخدام ctrl + o، ثم اخرج باستخدام ctrl + x.

في التكوين أعلاه، يُرسل المُنتج رسالة بالمفتاح “key1” والقيمة “مرحبًا، Kafka!” إلى الموضوع “my-topic”.

كيفية إعداد مواضيع Kafka

قبل إنتاج أو استهلاك الرسائل، تحتاج إلى إنشاء مواضيع في Kafka.

  1. استخدم النصي kafka-topics.sh المضمن مع تثبيت Kafka الخاص بك لإنشاء موضوع.
kafka-topics.sh --bootstrap-server localhost:9092 --create --topic <TopicName> --partitions <NumberOfPartitions> --replication-factor <ReplicationFactor>

على سبيل المثال، إذا كنت ترغب في إنشاء موضوع يسمى my-topic بـ 3 أقسام وعامل تكرار بمعدل 1، قم بتشغيل:

docker exec <Kafka Container ID> /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --create --topic my-topic --partitions 3 --replication-factor 1

النتيجة المتوقعة:

Created topic my-topic.
  1. تحقق للتأكد مما إذا تم إنشاء الموضوع بنجاح.
docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --list

النتيجة المتوقعة:

my-topic

كيفية إنشاء مستهلكي الأحداث

بعد أن تم إنشاء منتجيك ومواضيعك، يمكنك إنشاء مستهلكين لقراءة الرسائل من تلك المواضيع.

  1. أنشئ ملفًا kafka-consumer.java.
nano kafka-consumer.java
  1. أضف التكوين التالي لمستهلك Kafka.
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.clients.consumer.ConsumerRecord;

import java.time.Duration;
import java.util.Collections;
import java.util.Properties;

public class SimpleConsumer {
    public static void main(String[] args) {
        // قم بتهيئة خصائص المستهلك
        Properties props = new Properties();
        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
        props.put(ConsumerConfig.GROUP_ID_CONFIG, "my-group");
        props.put(ConsumerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
        props.put(ConsumerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");

        // إنشاء المستهلك
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

        // الاشتراك في الموضوع
        consumer.subscribe(Collections.singletonList("my-topic"));

        try {
            while (true) {
                // استطلاع السجلات الجديدة
                ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
                for (ConsumerRecord<String, String> record : records) {
                    System.out.printf("Consumed message with key %s and value %s from partition %d at offset %d%n",
                                      record.key(), record.value(), record.partition(), record.offset());
                }
            }
        } finally {
            // إغلاق المستهلك
            consumer.close();
        }
    }
}

احفظ التغييرات الخاصة بك باستخدام ctrl + o، ثم اخرج باستخدام ctrl + x.

في التكوين أعلاه، يشترك المستهلك في my-topic ويقوم بفحص مستمر للرسائل الجديدة. عند استلام الرسائل، يقوم بطباعة مفاتيحها وقيمها مع معلومات التقسيم والإزاحة.

كيفية دمج Traefik مع Kafka

قم بإعداد Traefik كوكيل عكسي.

تتيح لك دمج Traefik كوكيل عكسي لـ Kafka إدارة حركة المرور الواردة بكفاءة مع توفير ميزات مثل التوجيه الديناميكي وإنهاء SSL.

  1. قم بتحديث ملف docker-compose.yml.
version: '3.8'

services:
  kafka:
    image: wurstmeister/kafka:latest
    ports:
      - "9092:9092"
    environment:
      KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:9092,OUTSIDE://localhost:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
      KAFKA_LISTENERS: INSIDE://0.0.0.0:9092,OUTSIDE://0.0.0.0:9092
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.kafka.rule=Host(`kafka.example.com`)"
      - "traefik.http.services.kafka.loadbalancer.server.port=9092"

  zookeeper:
    image: wurstmeister/zookeeper:latest
    ports:
      - "2181:2181"

  traefik:
    image: traefik:v2.9
    ports:
      - "80:80"        # حركة مرور HTTP
      - "8080:8080"    # لوحة معلومات Traefik (غير مؤمنة)
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"

في هذا التكوين، استبدل kafka.example.com باسم المجال الفعلي الخاص بك. تحدد التسميات قواعد التوجيه التي سيستخدمها Traefik لتوجيه الحركة إلى خدمة Kafka.

  1. أعد تشغيل خدماتك.
docker compose up -d
  1. قم بالوصول إلى لوحة معلومات Traefik الخاصة بك عن طريق الدخول إلى http://localhost:8080 في متصفح الويب الخاص بك.

    توازن التحميل مع Traefik

    يوفر Traefik قدرات مدمجة لتوازن التحميل يمكن أن تساعد في توزيع الطلبات عبر عدة نسخ من منتجي ومستهلكي Kafka لديك.

    استراتيجيات لتوازن التحميل في الخدمات المصغرة المدفوعة بالحدث

    1. جولة دائرية:

افتراضيًا، يستخدم Traefik استراتيجية الدوران الدوري لتوزيع الطلبات الواردة بالتساوي عبر جميع الحالات المتاحة من خدمة ما. هذا فعّال لتوازن الحمل عند تشغيل عدة حالات من منتجي أو مستهلكي Kafka.

  1. جلسات لاصقة:

إذا كنت بحاجة إلى توجيه الطلبات من عميل معين دائمًا إلى نفس الحالة (على سبيل المثال، للحفاظ على حالة الجلسة)، يمكنك تكوين جلسات لاصقة في Traefik باستخدام الكوكيز أو الهيدرز.

  1. فحوصات الصحة:

قم بتكوين فحوصات الصحة في Traefik للتأكد من توجيه حركة المرور إلى حالات صحية فقط من خدماتك Kafka. يمكنك القيام بذلك عن طريق إضافة معلمات فحص الصحة في تعريفات الخدمة داخل ملف الـ docker-compose.yml الخاص بك:

    labels:
      - "traefik.http.services.kafka.loadbalancer.healthcheck.path=/health"
      - "traefik.http.services.kafka.loadbalancer.healthcheck.interval=10s"
      - "traefik.http.services.kafka.loadbalancer.healthcheck.timeout=3s"

اختبار الإعداد

التحقق من إنتاج الأحداث واستهلاكها

  1. يوفر Kafka أدوات سطر أوامر مدمجة للاختبار. ابدأ منتجًا بالوحدة.
    docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic my-topic

بعد تشغيل هذا الأمر، يمكنك كتابة الرسائل في الطرفية، التي سترسل إلى موضوع Kafka المحدد.

  1. ابدأ جلسة طرفية أخرى وابدأ مستهلك وحدة التحكم.
    docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic my-topic --from-beginning

سيعرض هذا الأمر جميع الرسائل في my-topic، بما في ذلك تلك التي تم إنتاجها قبل بدء المستهلك.

  1. لرؤية مدى توافق مستهلكيك مع المنتجين، يمكنك تشغيل الأمر التالي للتحقق من التأخير لمجموعة مستهلكين محددة.
    docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group <your-consumer-group>

المراقبة والتسجيل

  1. مؤشرات كافكا:

تعرض كافكا العديد من المؤشرات التي يمكن مراقبتها باستخدام JMX (امتدادات إدارة جافا). يمكنك تكوين JMX لتصدير هذه المؤشرات إلى أنظمة المراقبة مثل بروميثيوس أو غرافانا. تشمل المؤشرات الرئيسية التي يجب مراقبتها:

  • معدل الرسائل: معدل الرسائل المنتجة والمستهلكة.

  • تأخير المستهلك: الفرق بين آخر موضع رسالة منتجة وآخر موضع رسالة مستهلكة.

  • صحة الوسيط: مؤشرات تتعلق بأداء الوسيط، مثل معدلات الطلب ومعدلات الخطأ.

  1. تكامل بروميثيوس وغرافانا:

لتصور مؤشرات كافكا، يمكنك إعداد بروميثيوس لجمع المؤشرات من وسطاء كافكا لديك. اتبع هذه الخطوات:

  • قم بتمكين JMX Exporter على وسطاء Kafka الخاصة بك عن طريق إضافته كوكيل Java في تكوين وسيطك.

  • قم بتكوين Prometheus عن طريق إضافة وظيفة الفحص في ملف تكوينه (prometheus.yml) التي تشير إلى نقطة نهاية JMX Exporter الخاصة بك.

  • استخدم Grafana لإنشاء لوحات تظهر هذه البيانات الرياضية في الوقت الحقيقي.

كيفية تنفيذ مراقبة Traefik

  1. نقطة نهاية مقاييس Traefik.

يوفر Traefik دعمًا مدمجًا لتصدير المقاييس عبر Prometheus. لتمكين هذه الميزة، قم بإضافة التكوين التالي في تعريف خدمة Traefik ضمن docker-compose.yml:

    command:
      - "--metrics.prometheus=true"
      - "--metrics.prometheus.addservice=true"
  1. تصوير مقاييس Traefik باستخدام Grafana.

بمجرد أن يقوم Prometheus بجمع مقاييس Traefik، يمكنك تصويرها باستخدام Grafana:

  • إنشاء لوحة تحكم جديدة في Grafana وإضافة لوحات تعرض مقاييس Traefik الرئيسية مثل:

  • traefik_entrypoint_requests_total: عدد الطلبات الكلي المستلمة.

  • traefik_backend_request_duration_seconds: أوقات الاستجابة لخدمات الخلفية.

  • traefik_service_requests_total: إجمالي الطلبات الموجهة إلى خدمات الخلفية.

  1. إعداد التنبيهات.

قم بتكوين التنبيهات في Prometheus أو Grafana بناءً على عتبات محددة (على سبيل المثال، تأخر المستهلك العالي أو معدلات الأخطاء المتزايدة).

الاستنتاج

في هذا الدليل، نفذت بنجاح معمارية الحدث المدفوعة (EDA) باستخدام Kafka و Traefik ضمن بيئة Ubuntu 24.04.

الموارد الإضافية

لمعرفة المزيد يمكنك زيارة: