Mesaj kuyruklarında at-most-once, at-least-once ve exactly-once teslim garantileri ne anlama gelir? Idempotent consumer nasıl yazılır?

Cevap

GarantiAnlamıNasıl oluşurRisk
At-most-onceMesaj en fazla bir kez işlenirConsumer önce ack/commit eder, sonra işlerÇökme durumunda mesaj kaybolur
At-least-onceMesaj en az bir kez işlenirÖnce işler, sonra ack/commit ederÇökme veya timeout'ta mesaj tekrar gelir
Exactly-onceEtki tam olarak bir kez oluşurEk mekanizmalar gerekirPahalı, kapsamı sınırlı

Çoğu gerçek sistem at-least-once kullanır (RabbitMQ manuel ack, Kafka'da işlem sonrası offset commit, SQS) ve tekrarları consumer tarafında zararsız hale getirir.

Exactly-once neden zor?

Ağda bir onay mesajı kaybolduğunda gönderen, mesajın işlenip işlenmediğini bilemez; ya tekrar gönderir (duplicate) ya göndermez (kayıp). Kafka'nın exactly-once semantics özelliği (idempotent producer + transactions) yalnızca Kafka'dan okuyup Kafka'ya yazan akışlar için geçerlidir; consumer bir DB'ye yazıyor veya e-posta gönderiyorsa bu garanti dışarıya uzanmaz. Pratikte hedef: at-least-once teslim + idempotent işleme = etkin exactly-once.

Idempotent consumer

Her mesajın benzersiz bir ID'si olur; işlenen ID'ler iş verisiyle aynı transaction'da kaydedilir.

CREATE TABLE processed_messages (
    message_id   text PRIMARY KEY,
    processed_at timestamptz DEFAULT now()
);
def handle(msg):
    with db.transaction():
        inserted = db.execute(
            "INSERT INTO processed_messages (message_id) VALUES (%s) "
            "ON CONFLICT DO NOTHING", (msg.id,)).rowcount
        if inserted == 0:
            return                      # daha önce işlenmiş, atla
        db.execute("UPDATE accounts SET balance = balance + %s WHERE id = %s",
                   (msg.amount, msg.account_id))
    msg.ack()                           # commit'ten sonra ack

Diğer teknikler: doğal olarak idempotent işlemler (SET status = 'paid' gibi, balance + 10 değil), unique constraint'ler, versiyon numaraları.

İlgili kavramlar

  • Dead letter queue (DLQ): belirli sayıda denemeden sonra hâlâ başarısız olan mesajlar ayrı kuyruğa alınır ki kuyruğu tıkamasın (poison message).
  • Sıralama: Kafka sıralamayı yalnızca partition içinde garanti eder; aynı entity'nin mesajları aynı key ile gönderilmelidir.
  1. Mesaj kuyruğu (RabbitMQ, Kafka) ne zaman kullanılır?ZorSistem TasarımıBackend
  2. Monolith ile mikroservis mimarisi arasındaki fark nedir? Mikroservislere ne zaman geçilmeli?ZorSistem TasarımıBackend
  3. CAP teoremi nedir? Gerçek sistemlerde nasıl yorumlanır?ZorSistem TasarımıBackend
  4. Dikey ve yatay ölçekleme arasındaki fark nedir?KolaySistem TasarımıFull Stack
  5. Hangi cache stratejilerini biliyorsunuz?OrtaSistem TasarımıFull Stack
  6. REST ile GraphQL arasındaki farklar nelerdir?OrtaSistem TasarımıFull Stack

Bu konuda başka bir soru biliyor musun?

Mülakatta karşılaştığın soruları ekle, onaylandıktan sonra yayına alınsın.

Soru ekle