11 Aralık 2020 Cuma

Apache Kafka Message Delivery Semantics

Giriş
Message Delivery Semantics açısından olasılıklar şöyle
1. No guarantee
2. At most once : Best effort denilebilir. Mesaj işlenebilir veya kaybolabilir ancak tekrar gelmez.
3. At least once : Mesaj asla kaybolmaz ancak tekrar gelebilir. Varsayılan bu
4. Effectively once veya Exactly once : Mesaj kaybolmaz ve tek bir kere gelir

1. No guarantee
Problem consumer tarafından kaynaklanıyor. enable.auto.commit = true atanmıştır ve mesajları asenkron olarak işleriz. Bence senkron da işleseydik yine No Guarantee kapsamına girerdi. Açıklaması şöyle
With auto commit enabled, the consumer will save offsets back to Kafka periodically at the start of subsequent poll calls. The frequency of these commits is determined by the configuration parameter auto.commit.interval.ms
 - If you save the messages to the database then the application crashes before the progress is saved, you will reprocess those messages again the next run and save them to the database twice. 
- If progress is saved prior to the results being saved to the database, then the program crashes, these messages will not be reprocessed in the next run meaning you have data loss.
Yani her 5 saniyedeki poll() çağrısında offset ilerletilir, ancak mesaj asenkron işlenirken bir hata oluşur ve mesaj kaybolur

2. At Most Once
Problem producer ve consumer tarafından kaynaklanabilir.

Producer Açısından
Açıklaması şöyle. Yani producer yazma hatasına bakmadan source sistem için kullanılan offset'i ilerletiyor.
1. A common example that results in at most once semantics is where a producer performs a ‘fire-and-forget’ approach sending a message to Kafka with no retries and ignoring any response from the broker. This approach is useful where progress is a higher priority than completeness.


2. A producer saves its progress reading from a source system first, then writes data into Kafka. If the producer crashes before the second step, the data will never be delivered to Kafka.
Consumer Açısından
enable.auto.commit = false atanmıştır ve 
1. Önce Kafka'ya 
2. Sonra veri tabanına commit yapılır. 

Burada consumer commit offset'ini ilerletiyor ancak mesajları işlemeden çöküyor. Bu yüzden  mesajlar kaybolabilir. Açıklaması şöyle
A consumer receives a batch of messages from Kafka, transforms these and writes the results to a database. The consumer application has enable.auto.commit set to false and is programmed to commit their offsets back to Kafka prior to writing to the database. If the consumer fails after saving the offsets back to Kafka but before writing the data to the database, it will skip these records next time it runs and data will be lost.
Açıklaması şöyle
It can read the messages, then save its position in the log, and finally process the messages. In this case there is a possibility that the consumer process crashes after saving its position but before saving the output of its message processing. In this case the process that took over processing would start at the saved position even though a few messages prior to that position had not been processed. This corresponds to "at-most-once" semantics as in the case of a consumer failure messages may not be processed.
3. At Least Once - Mesaj Tekrar Gelebilir
Problem producer ve consumer tarafından kaynaklanabilir.

Producer Açısından
Açıklaması şöyle. Yani producer beklediği cevabı almadığı için aynı mesajı tekrar gönderir.
An application sends a batch of messages to Kafka. The application never receives a response so sends the batch again. In this case it may have been the first batch was successfully saved, but the acknowledgement was lost, so the messages end up being added twice.

Consumer Açısından
enable.auto.commit = false atanmıştır ve batch okuma yapılır
1. Önce veri tabanında
2. Sonra Kafka'ya commit yapılır. 

Açıklaması şöyle
1. An application processes a large file containing events. It starts processing the file sending a message to Kafka for each event. Half way through processing the file the process dies and is restarted. It then starts processing the file again from the start and only marks it as processed when the whole file has been read. In this case the events from the first half of the file will be in Kafka twice.

2. A consumer receives a batch of messages from Kafka, transforms these and writes the results to a database. The consumer application has enable.auto.commit set to false and is programmed to commit their offsets back to Kafka once the database write succeeds. If the consumer fails after writing the data to the database but before saving the offsets back to Kafka, it will reprocess the same records next time it runs and save them to the database once more.
Açıklaması şöyle. Burada consumer mesajları okuyor işlemeye başlıyor ancak offset'ini ilerletmiyor ve tüm mesajları işlemeden çöküyor. Bu yüzden yeni gelen consumer eski offset'ten başlıyor ve mesajlar tekrar geliyor (redelivered). 
It can read the messages, process the messages, and finally save its position. In this case there is a possibility that the consumer process crashes after processing messages but before saving its position. In this case when the new process takes over the first few messages it receives will already have been processed. This corresponds to the "at-least-once" semantics in the case of consumer failure. In many cases messages have a primary key and so the updates are idempotent (receiving the same message twice just overwrites a record with another copy of itself).
Duplicate mesaj'dan kaçınmak için iki tane yöntem var
1. Idempotent client yazmak
2. Tüm işlenen mesajları (tracking message ids) veri tabanına kaydetmek ve çift olanları elemek

Tracking Message IDs şeklen şöyle

Açıklaması şöyle
In this example, a Consumer inserts a row containing messageId into the PROCESSED_MESSAGE table. If a message is a duplicate, the INSERT operation will fail and Consumer discards this message without updating the Order entity.

4. Exactly once
Transaction kullanır. Exactly once yazısına taşıdım

Dead Letter Queue - DLQ
Kafka DLQ sağlamıyor. Error handling için şu yöntemler kullanılabilir.
1. Lack of error handling
2. Infinite retry
3. Finite retry at the point of an error. Burada DLQ kullanılıyor
4. Finite retry on a separate topic





Hiç yorum yok:

Yorum Gönder