İçeriğe geç

Asenkron Mesajlaşma Temelleri

Asenkron bir mesaj, bir producer’ın broker’a teslim ettiği ve ardından beklemeyi bıraktığı bir iş birimi ya da bir olgu bildirimidir. Broker onu kalıcı olarak saklar; producer’ın belki hiç duymadığı bir consumer da onu daha sonra işler: normalde milisaniyeler sonra, bir kesintiden sonra saatler sonra, yeni bir consumer geçmişi baştan oynattığında (replay) günler sonra. Bu tek değişiklik, senkron bir çağrıyı tanımlayan bağımlılığı (coupling) ortadan kaldırır. Producer’ın gecikmesi artık consumer’ın gecikmesini içermez, producer’ın erişilebilirliği consumer’ın ayakta olmasına bağlı değildir ve çağrılan tarafı aşırı yükleyecek bir ani yük artışı (burst), consumer’ın sürdürebildiği hızda eriyen bir birikmiş iş kuyruğuna (backlog) dönüşür.

Bu bölümün ele aldığı tek problem, bağımsız takvimlerle çalışan, çöken ve deploy edilen programlar arasında iş ve olguların kaybolmadan, etkileri çoğalmadan ve onları okuyan programlar bozulmadan nasıl taşınacağıdır. Sekiz konunun hepsinden geçen gerilim şudur: zamanda ayrıştırmak, hatayı da nedeninden ayırır. Senkron bir çağrıda hatalı biçimlendirilmiş bir istek, uyumsuz bir alan ya da çökmüş bir karşı taraf, çağıranın isteğini anında ve hatayı yapan mühendisin gözü önünde başarısız kılar. Broker üzerinde ise aynı mesaj kabul edilir, replike edilir, producer’a onaylanır ve daha sonra, tekrar tekrar, başka bir ekibe ait bir consumer’ın içinde başarısız olur. Bölümdeki her mekanizma, broker’ın elinden aldığı görünürlüğün bir kısmını geri satın alma girişimidir: hangi consumer neyi işledi, bir etki kaç kez gerçekleşti, bir topic üzerindeki mesajın neyi içermesine izin var ve hiçbir zaman işlenemeyecek mesajlar nereye gitti.

İkinci bir eksen birinciyi keser: tüketim durumunun nerede tutulduğu. Kuyruk tabanlı bir broker her mesajın durumunu hatırlar ve onay (acknowledgement) geldiğinde mesajı siler; log tabanlı bir broker ise consumer’lar hakkında hiçbir şey hatırlamaz ve her birinin, saklanan ve sıralı bir dizi içinde kendi konumunu tutmasına izin verir. Bu seçim sıralamayı, replay’i, paralelliği, fan-out maliyetini ve takılan bir mesajın komşularına ne yaptığını belirler; bölümün her sayfasında yeniden karşımıza çıkar.

Broker Modellerinden Hata Çıkışına: Konular Birbirinin Üzerine Nasıl Kurulur

Section titled “Broker Modellerinden Hata Çıkışına: Konular Birbirinin Üzerine Nasıl Kurulur”

Bölüm dört katmandan oluşur: iki broker modeli ve onları uygulayan üç gerçek broker; garantileri tek bir sisteme değil yolun tamamına ait olduğu için tüm broker’ların üstünde duran teslim semantiği; bir mesajın zaman içinde taşıdığı sözleşme üzerine iki sayfa; ve hiçbir sözleşmenin ya da retry’ın kurtaramayacağı mesaj.

partitioned log in practice

same log, storage separated

queues fed by exchanges

leases and offsets cause redelivery

commit timing

structure enforced on the wire

at-least-once redelivers poison forever

undecodable records

dead-letter exchanges

2.2.1 Queue vs. event streaming

2.2.2 Kafka architecture

2.2.3 Pulsar vs. Kafka

2.2.4 RabbitMQ routing

2.2.5 Delivery semantics

2.2.6 AsyncAPI contracts

2.2.7 Schema evolution and registry

2.2.8 DLQ and poison messages

partitioned log in practice

same log, storage separated

queues fed by exchanges

leases and offsets cause redelivery

commit timing

structure enforced on the wire

at-least-once redelivers poison forever

undecodable records

dead-letter exchanges

2.2.1 Queue vs. event streaming

2.2.2 Kafka architecture

2.2.3 Pulsar vs. Kafka

2.2.4 RabbitMQ routing

2.2.5 Delivery semantics

2.2.6 AsyncAPI contracts

2.2.7 Schema evolution and registry

2.2.8 DLQ and poison messages

Bölümdeki konular arasındaki bağımlılıklar. Her ok, bir sayfanın üzerine kurulduğu sayfadan neyi devraldığını adlandırır.

Kuyruk ile event streaming karşılaştırması kök sayfadır, çünkü sonraki her sayfa onun iki durum makinesini varsayar: bir kuyruğun hazır, işlemde (in-flight) ve onaylanmış durumlarıyla mesaj başına kiralama (lease) modeli ve bir log’un saklama (retention) ve sıra başı tıkanması (head-of-line blocking) ile partition başına offset modeli. Kafka, partition’lı log’un somutlaşmış hâlidir ve sayfası Pulsar için ön koşuldur; Pulsar consumer’a görünen aynı log’u korur ve byte’larını broker’ların dışına taşır. RabbitMQ kuyruk tarafını farklı bir yönde genişletir: kuyrukların önüne bir yönlendirme katmanı koyar. Teslim semantiği her iki modele de dayanır, çünkü çift kayıtlar tam olarak o sayfaların anlattığı mekanizmalar tarafından üretilir: süresi dolan bir lease, commit edilmemiş bir offset, bir producer retry’ı. Dead-letter sayfası en sona gelir, çünkü önceki üç girdiyi birleştirir: bir poison message’ı döngüye sokan at-least-once yeniden teslimi, şema evriminin önlemek için var olduğu deserialization hatalarını ve RabbitMQ ile diğer sistemlerin broker’a gömülü dead-letter mekanizmalarını.

Mesaj Kuyruğu ve Event Streaming: Farklar ve Kullanım Senaryoları, broker’ın her mesajı izlemesiyle her consumer’ın kendi konumunu izlemesi arasında neyin değiştiğini ve bu tek seçimin neden sıralamayı, replay’i, paralelliği ve takılan bir mesajın komşularına nasıl zarar verdiğini belirlediğini yanıtlar. Yeni bir iş yükü için broker seçmeden önce ve bir tasarım hem iş dağıtımına hem de yeniden oynatılabilir geçmişe ihtiyaç duyduğunda açın.

Kafka Mimarisi: Topic, Partition, Consumer Group, Offset, partition’ın neden Kafka’nın sıralama, replikasyon, yerleşim ve paralellik için tek birimi olduğunu, onaylanmış bir yazmanın acks, min.insync.replicas ve replication factor’ün her bileşiminde neye dayanabildiğini ve commit edilmiş bir offset’in neyi vaat ettiğini yanıtlar. Topic’leri ve partition sayılarını boyutlandırırken, dayanıklılık ayarlarını seçerken ve reddedilen yazmaları, sıcak partition’ları ya da sessizce sıfırlanan consumer’ları teşhis ederken açın.

Pulsar ve Kafka: Mimari Karşılaştırma, broker’lar topic’lere hizmet verip hiçbir şey saklamadığında ve log kendi quorum ve fencing protokolüne sahip ayrı bir depolama cluster’ında yaşadığında ne kazanılıp ne ödendiğini yanıtlar. Pulsar’ı değerlendirirken, Kafka operasyonlarına partition taşımaları ve broker yeniden inşaları hâkim olduğunda ve tek bir topic’in hem log tarzı hem kuyruk tarzı consumer’lara hizmet etmesi gerektiğinde açın.

RabbitMQ: Exchange Türleri ve Yönlendirme, bir broker’ın her mesajın kopyasını hangi kuyrukların alacağına nasıl karar verdiğini, her exchange türünün eşleştirme maliyetini ve hiçbir şeyle eşleşmeyen bir mesaj hakkında publisher’ın ne öğrenebileceğini yanıtlar. Routing key’e ya da header’a göre abonelik topolojileri tasarlarken ve mesajlar hata vermeden kaybolduğunda ya da fan-out diski ve belleği tükettiğinde açın.

En Az Bir Kez, En Fazla Bir Kez ve Tam Olarak Bir Kez Semantiği, kayıplı bir ağ üzerinde hiçbir protokolün neden tam olarak bir kez teslim edemeyeceğini, tam olarak bir kez etkinin at-least-once teslimden ve etkiyle birlikte commit edilen tekilleştirmeden (deduplication) nasıl inşa edildiğini ve her üreticinin exactly-once sınırının nerede bittiğini yanıtlar. Herhangi bir consumer bir veritabanına yazmadan ya da harici bir API çağırmadan önce ve bir çökme ya da rebalance sonrasında çift kayıtlar veya boşluklar görüldüğünde açın.

AsyncAPI: Asenkron Sözleşmeleri Belgelemek, bir uygulamanın channel’larının, operasyonlarının ve mesajlarının makine tarafından okunabilir bir belgede nasıl tanımlandığını ve bu belgenin koddan uzaklaşmasını neyin engellediğini yanıtlar. Bir topic’i kimin tükettiğini kimse söyleyemediğinde ve olay güdümlü servisler için kod üretimi ya da deploy öncesi uyumluluk kontrolleri kurarken açın.

Şema Evrimi ve Schema Registry: Avro, Protobuf ve Uyumluluk Modları, her uyumluluk modunda hangi okuyucunun hangi yazıcıyı okuyabilmesi gerektiğini, her modun hangi deploy sırasını dayattığını, her formatın bir uyumsuzluğu nasıl çözdüğünü ve bir registry’yi veri yoluna koymanın ne anlama geldiğini yanıtlar. Saklanan verisi olan bir topic’te ilk şema değişikliğinden önce ve bir producer deploy’undan sonra consumer’lar deserialize edemediğinde açın.

Dead Letter Queues ve Poison Message Yönetimi, hiçbir zaman başarılı olamayacak bir mesajın kaybedilmeden akıştan nasıl çıkarılacağını, kaç retry’ı hak ettiğini, dead-letter’a göndermenin sıralamaya ne yaptığını ve yönlendirilen mesajların nasıl incelenip yeniden kaynağa gönderildiğini (redrive) yanıtlar. Bir partition tek bir kaydın arkasında durduğunda, worker’lar döngü hâlinde çöktüğünde ve herhangi bir consumer için retry katmanları tasarlamadan önce açın.

KonuYanıtladığı soruNe zaman açılmalı
Kuyruk ve event streamingNeyin tüketildiğini kim hatırlar ve bundan ne çıkar?Broker modeli seçerken, replay veya fan-out gerektiğinde, head-of-line blocking’i giderirken
Kafka mimarisiPartition’lar, replikalar ve offset’ler neyi garanti eder?Partition boyutlandırırken, dayanıklılığı ayarlarken, sıcak partition’ları veya offset sıfırlamalarını teşhis ederken
Pulsar ve KafkaHizmeti depolamadan ayırmak ne kazandırır, neye mal olur?Pulsar’ı değerlendirirken, yavaş veri taşımalarından muzdaripken, kuyruk ve log consumer’larını karıştırırken
RabbitMQYazma anındaki yönlendirme hedef kuyrukları nasıl seçer?Topic veya header aboneliklerini tasarlarken, sessiz kayıpları veya fan-out baskısını kovalarken
Teslim semantiğiBir etki uçtan uca kaç kez gerçekleşebilir?Yan etkili herhangi bir consumer yazarken, çift kayıtları veya kayıpları incelerken
AsyncAPIBir uygulama makine tarafından okunabilir biçimde neyi gönderir ve alır?Topic bağımlılıklarını haritalarken, kod üretirken, sözleşmeleri CI’da kontrol ederken
Şema evrimi ve registryHangi şema değişiklikleri canlı her okuyucuyu çalışır durumda tutar?Bir mesaj şemasını değiştirirken, format ve uyumluluk modu seçerken
DLQ ve poison message’larHiçbir zaman başarılı olamayacak bir mesaj nereye gider?Retry tasarlarken, takılı bir partition’ı açarken, başarısız mesajları redrive ederken

Bölüm, tek bir mesajın yolu boyunca her adımın hangi sayfaya ait olduğu sorularak da okunabilir. Broker sayfaları yolun ortasına sahiptir, ama bölümdeki olayların (incident) çoğu yolun uçlarında yaşanır.

serialize with schema ID

lease or fetch from offset

effect plus dedup record

ack or commit offset

permanent failure

describes channels and messages

Producer object

Publish and ack

Broker: queue or log

Deserialize

Handler

Effect store

Dead-letter destination

AsyncAPI document

serialize with schema ID

lease or fetch from offset

effect plus dedup record

ack or commit offset

permanent failure

describes channels and messages

Producer object

Publish and ack

Broker: queue or log

Deserialize

Handler

Effect store

Dead-letter destination

AsyncAPI document

Serileştirmeden etkiye kadar tek bir mesajın yolu. İki serileştirme adımı şema evrimine, depo ve lease ya da offset broker sayfalarına, etki ile onay arasındaki ilişki teslim semantiğine, hata dalı dead-letter sayfasına aittir; AsyncAPI ise kenarların üzerinde durmadan onları tanımlar.

Yolun iki özelliği bölümün neden bu biçimde kurulduğunu açıklar. Handler’ın dışarıya giden iki yazması vardır, etki ve onay, ve bunlar farklı sistemlere gider; teslim semantiği sayfasında anlatılan tekilleştirme olmadan bu iki yazmanın bir çökme karşısında güvenli olan hiçbir sıralaması yoktur. Noktalı kenarlar AsyncAPI belgesinin veri yolunda hiç bulunmadığını gösterir: neyin gönderilmesi gerektiğini kısıtlar, neyin gerçekten okunabileceğine ise registry ve deserializer karar verir.

İlk okumada bölümü sidebar sırasıyla okuyun. Kuyruk ve event streaming karşılaştırması önce gelmelidir, çünkü onun lease ve offset durum makineleri sonraki her sayfada yeniden açıklanmadan referans verilir. Kafka, Pulsar’dan önce gelmelidir, çünkü Pulsar sayfası Kafka’nın replikasyonunu, high watermark’ını ve offset’lerini yeniden tanımlamak yerine onlarla karşılaştırır. Teslim semantiği dead-letter sayfasından önce gelmelidir, çünkü dead-letter’a göndermenin korunum argümanı (bir mesaj kaynakta ancak başka bir yere güvenle yazıldıktan sonra onaylanır) ikinci bir hedefe uygulanmış at-least-once kuralıdır.

Üç kısayol makuldür. Broker seçen bir mühendis kuyruk ve event streaming sayfasını, ardından Kafka, Pulsar ya da RabbitMQ’dan hangisi değerlendiriliyorsa onu, sonra da o broker’ın garantilerinin uygulamaya neyi bıraktığını öğrenmek için teslim semantiğini okumalıdır. Mevcut bir platform üzerine consumer yazan bir mühendis teslim semantiğini ve dead-letter sayfasını, ardından şema sayfasını okumalıdır; bir consumer’ın çökmelere, yeniden teslimlere ve producer deploy’larına dayanıp dayanamayacağına bu üçü karar verir. Birçok ekip arasındaki sözleşmelerden sorumlu bir mühendis AsyncAPI ile şema evrimini birlikte okumalıdır; biri bir channel üzerinde neyin aktığını tanımlar, diğeri bunu zorunlu kılar.

Bu bölüm, kendisinden öncekinin alternatifidir. Senkron İletişim Protokolleri, çağıranın beklediği ve çağrılanın gecikmesini ve hatalarını devraldığı çağrıları ele alır; bu bölüm ise çağıran beklemeyi bıraktığında ne olduğunu anlatır. İkisi de ilk bölümün kısmi hata (partial failure) anlatımına dayanır: Hata Modelleri, onay ikileminin arkasındaki crash-recovery süreçlerini ve kayıplı bağlantıları tanımlar; Hata Yayılımı: Kaskad Hata Analizi ise bir broker’ın backlog olarak emdiği aşırı yükü gösterir.

crash-recovery, lossy links

what to decouple and why

idempotency keys, contract tests

log as data infrastructure, CDC

outbox and sagas over messages

events as system of record

backpressure, retry storms

storage, KRaft, rebalancing, EOS

1.2 System Models and Failure Types

2.1 Synchronous Communication Protocols

2.2 Asynchronous Messaging

2.3 API Gateway and Service Contracts

4.3 Hybrid Architectures and the Log

5.1 Distributed Transactions

6.5 Event Sourcing and CQRS

7.1 Flow Control

13.1 Apache Kafka case study

crash-recovery, lossy links

what to decouple and why

idempotency keys, contract tests

log as data infrastructure, CDC

outbox and sagas over messages

events as system of record

backpressure, retry storms

storage, KRaft, rebalancing, EOS

1.2 System Models and Failure Types

2.1 Synchronous Communication Protocols

2.2 Asynchronous Messaging

2.3 API Gateway and Service Contracts

4.3 Hybrid Architectures and the Log

5.1 Distributed Transactions

6.5 Event Sourcing and CQRS

7.1 Flow Control

13.1 Apache Kafka case study

Solda ön koşullar, sağda bu bölümün üzerine kurulan bölümler. Her ok neyin devredildiğini adlandırır.

Bu bölümün dayandığı birçok mekanizmanın kanonik sayfası başka yerdedir. Kafka vaka çalışması, Kafka sayfasının yalnızca özetlediği iç yapıların sahibidir: Disk Tabanlı Kalıcılık ve Sıfır Kopyalama Optimizasyonu, KRaft Modu, Consumer Group Yeniden Dengeleme ve idempotent ve transactional producer’lar için Tam Olarak Bir Kez Semantiği. Commit Log Soyutlaması, Log Compaction ve Değişiklik Verisi Yakalama (CDC) log’u bir taşıma aracı olarak değil, genel bir veri altyapısı olarak ele alır.

El kitabının geri kalanı mesajlaşmayı bir yapı taşı olarak kullanır. Outbox Deseni, teslim semantiğinin consumer tarafında çözdüğü çift yazma (dual-write) probleminin producer tarafındaki karşılığını çözer; SAGA Deseni ise birden fazla servise yayılan işi mesajlar üzerinden koordine eder. Olay Versiyonlama ve Şema Evrimi, şema evrimini asla atılamayacak olan, sistemin asıl kaydı (system of record) niteliğindeki event’lere uygular. Idempotency ve Güvenli HTTP Metotları, idempotent consumer’ın istek-yanıt dünyasındaki karşılığıdır; Tüketici Güdümlü Sözleşme Testi ise mesaj sözleşmelerini gerçek consumer’lara karşı doğrular. Dayanıklılık tarafında Geri Baskı ve Kuyruk Teorisi Temelleri: Little Yasası backlog’ların nasıl büyüyüp eridiğini açıklar, Üstel Geri Çekilme ve Jitter ile Yeniden Deneme retry katmanlarının aralığını belirler ve Retry Fırtınaları ve Metastabil Hatalar dikkatsiz bir redrive’ın başlatabileceği olayı anlatır. Olay Güdümlü Sistemleri Test Etmek ve Dağıtık İzleme, hiçbir tekil isteğin kapsamadığı akışların nasıl doğrulanıp gözlemleneceğini ele alır.