almessadi.
العودة إلى الفهرس

يجب أن تكون مستهلكات Kafka ذات إيديمبوسية حتى عند سماعك 'مرة واحدة فقط'_

إن دلالات (Exactly-once) في Kafka أضيق مما تفترضه العديد من الفرق. الإيديمبوسية على جانب المستهلك لا تزال التصميم الأكثر أمانًا للتأثيرات الجانبية.

تاريخ النشر25 أبريل 2024
وقت القراءة7 min read

إذا أدى مستهلك Kafka إلى تأثير جانبي، افترض أن التكرارات ممكنة حتى تثبت العكس.

هذا هو الافتراض الأكثر أمانًا.

لدى Kafka ميزات (exactly-once)، ولكن كثيرًا ما يبالغ المهندسون في تفسير ما تغطيه تلك الضمانات. إنها تساعد كثيرًا داخل نموذج معالجة Kafka الخاص به. لكنها لا تجعل كل كتابة لقاعدة بيانات تالية أو اتصال API خارجي خاليًا من التكرارات بشكل سحري.

مشكلة المستهلك

تبدو النمط المحفوف بالمخاطر على الشكل التالي:

  1. استهلاك الرسالة
  2. تحديث قاعدة البيانات
  3. تأكيد التقدم

إذا تعطلت الخدمة بين الخطوتين، قد يحدث إعادة تشغيل.

هذا لا يعني أن هناك خللًا في Kafka. إنما هو سلوك طبيعي في الأنظمة الموزعة تحت الفشل.

استخدم مفتاح إيديمبوسية

كل حدث يمكن أن يؤدي إلى تأثير جانبي يجب أن يحمل معرفًا ثابتًا:

{
  "eventId": "evt_01HS8T0X8Q5Q8X4X8H2K2YJ6FD",
  "type": "PaymentCharged",
  "walletId": "wal_123"
}

ثم اجعل التأثير الجانبي مشروطًا على ما إذا كان ذلك الحدث قد تم تطبيقه بالفعل.

دع قاعدة البيانات تفرض ذلك

أحد الأساليب الشائعة والموثوقة هو قيد فريد:

CREATE TABLE processed_events (
  event_id text PRIMARY KEY,
  processed_at timestamptz NOT NULL DEFAULT now()
);

ثم قم بالمعالجة داخل عملية واحدة:

BEGIN;

INSERT INTO processed_events (event_id)
VALUES ($1);

UPDATE wallets
SET balance = balance - $2
WHERE id = $3;

COMMIT;

إذا تم إعادة تشغيل نفس الحدث، ستفشل الإدراج بسبب القيد الفريد ويمكن للمستهلك أن يعتبره قد تم التعامل معه بالفعل.

هذا غالبًا ما يكون أبسط وأكثر موثوقية من عمليات التخلص من التكرارات في الذاكرة عشوائيًا.

النموذج العقلي المفيد

لا تستهدف "عدم حدوث التكرارات أبدًا."

استهدف "التكرارات لا تغير الحالة النهائية."

هذا ما تشتريه لك الإيديمبوسية.

قراءة إضافية