How-To Guides

تنفيذ دلالات التنفيذ مرة واحدة بالضبط في Apache Kafka: دليل عملي

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

فهم المشكلة

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

المكونات الرئيسية: المنتجون القادرون على التكرار والمعاملات

لتحقيق دلالات التنفيذ مرة واحدة بالضبط، تحتاج إلى آليتين أساسيتين تعملان معًا:

  1. المنتج القادر على التكرار (Idempotent Producer): يضمن عدم إنتاج عدة نسخ من نفس الرسالة. تتتبع خوادم Kafka معرّفات المنتجين وأرقام التسلسل لإزالة التكرار من الرسائل المرسلة من نفس جلسة المنتج.
  2. المعاملات (Transactions): تتيح لك تجميع عمليات الإنتاج والاستهلاك المتعددة في وحدة عمل ذرّية واحدة. إذا فشل أي جزء من المعاملة، يتم تراجع المعاملة بأكملها.

تنفيذ منتج قادر على التكرار

أولاً، فعّل خاصية التكرار (Idempotence) في إعدادات منتج Kafka الخاص بك. يتم ذلك من خلال تعيين enable.idempotence=true. لاحظ أنه عند تفعيل خاصية التكرار، يجب تعيين acks على all لضمان التزام الرسائل بجميع النسخ المتزامنة قبل الإقرار بها.


import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.serialization.StringSerializer;
import java.util.Properties;

public class IdempotentProducerExample {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
        
        // Enable idempotence
        props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true);
        props.put(ProducerConfig.ACKS_CONFIG, "all");

        KafkaProducer producer = new KafkaProducer<>(props);
        // Send messages...
        producer.close();
    }
}

استخدام المعاملات للمعالجة مرة واحدة بالضبط

للمعالجة من الطرف إلى الطرف مرة واحدة بالضبط، يجب عليك الجمع بين منتج قادر على التكرار ومستهلك يشارك في نفس المعاملة. المفتاح هنا هو استخدام إعداد transactional.id لربط مجموعة المستهلك بجلسة معاملية محددة.

الخطوة 1: تكوين المنتج مع المعرّف المعاملي


props.put(ProducerConfig.TRANSACTIONAL_ID_CONFIG, "my-transactional-id");
producer.initTransactions();

الخطوة 2: بدء المعاملة، معالجة البيانات، والتأكيد


producer.beginTransaction();

// Consume messages
ConsumerRecords records = consumer.poll(Duration.ofMillis(100));

for (ConsumerRecord record : records) {
    // Process the record (e.g., update external system)
    process(record);
    
    // Produce the result to a downstream topic
    producer.send(new ProducerRecord<>("output-topic", record.key(), record.value()));
}

// Commit the transaction atomically
producer.commitTransaction();

// Offset commit is optional here as Kafka manages offsets via transaction log
consumer.commitSync(); 

اعتبارات عملية

  • المواعيد النهائية (Timeouts): قم بتعيين قيم مناسبة لـ transaction.timeout.ms و session.timeout.ms لتجنب انتهاء صلاحية المعاملة قبل الأوان.
  • تنسيق مجموعة المستهلك: يجب استخدام نفس transactional.id عبر جميع حالات زوج المنتج-المستهلك في سيناريو التوسع الأفقي. يضمن Kafka أن تكون حالة واحدة فقط نشطة في كل مرة لكل معرّف معاملي.
  • الأنظمة النهائية (Downstream Systems): دلالات التنفيذ مرة واحدة بالضبط في Kafka تضمن فقط أن الرسالة كُتبت مرة واحدة في Kafka. إذا لم يكن نظامك النهائي (مثل قاعدة البيانات) قادرًا على التكرار، فيجب عليك تنفيذ منطق إزالة التكرار على مستوى المستهلك أيضًا.

الخاتمة

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

Share: