Lập trình 22/09/2026 7 phút

At-most-once, at-least-once, exactly-once: đo thật message bị mất và bị trùng

Ba ngữ nghĩa giao nhận nghe trừu tượng cho tới khi bạn mất tiền của khách vì xử lý đơn hai lần. Bài này chạy thật trên Kafka với 1000 message đánh số: at-least-once cho đọc lại khi chưa commit — trùng đúng 1000; at-most-once dời offset vượt trước xử lý — mất đúng 1000 (mà LAG vẫn báo 0, 'khoẻ' giả); idempotent producer ghi đúng 1000 không trùng. Khác biệt nằm gọn ở chỗ commit offset trước hay sau khi xử lý.

Lập trình 22/09/2026 7 phút

Consumer group và partition: mở rộng throughput, và vì sao thêm consumer có trần

Consumer xử lý không kịp? Thêm consumer. Nhưng không phải thêm bao nhiêu cũng nhanh hơn. Bài này chạy thật trên Kafka topic 6 partition: 3 consumer trong một group chia đều mỗi cái 2 partition; nhưng khi lên 7 consumer trên 6 partition, consumer thứ 7 nhận đúng 0 partition — ngồi không, lãng phí. Partition là đơn vị song song thật, và nó là trần cứng của việc scale consumer.

Lập trình 22/09/2026 7 phút

Idempotency: xử lý message trùng mà vẫn đúng — demo trừ tiền hai lần và cách chặn

At-least-once chắc chắn sẽ giao message trùng. Nếu consumer cứ thế xử lý, khách bị trừ tiền hai lần. Bài này chạy thật: 1000 thanh toán được Kafka giao 2000 lượt (1000 trùng); consumer ngây thơ cộng ra 200.000 — sai gấp đôi; consumer idempotent dùng redis SETNX khử trùng theo id, chỉ xử lý 1000 lượt duy nhất, ra đúng 100.000. At-least-once + idempotency an toàn như exactly-once mà rẻ hơn.

Lập trình 22/09/2026 7 phút

Outbox pattern: vì sao ghi database rồi publish message là cái bẫy mất dữ liệu

Service ghi đơn hàng vào database rồi publish message sang Kafka — hai bước riêng. Nếu crash giữa hai bước, database có đơn mà message biến mất. Bài này chạy thật: dual-write để lệch 40/100 đơn; outbox pattern ghi business row và outbox row trong cùng một transaction PostgreSQL, relay đọc và publish — khớp 100%, và relay chạy lại vẫn an toàn. Chìa khoá là tính nguyên tử của database.

Lập trình 22/09/2026 8 phút

Dead Letter Queue: một message độc không được phép giữ con tin cả hàng đợi

Một message hỏng không xử lý nổi mà consumer cứ retry mãi sẽ chặn đứng mọi message sau nó. Bài này chạy thật trên Kafka: 10 message với 2 cái độc ở vị trí 3 và 7 — consumer không có DLQ kẹt tại message độc đầu tiên, chỉ xử lý được 2/10; consumer có DLQ tách 2 message độc sang topic riêng sau vài lần retry, xử lý trọn 8 message tốt và hàng đợi không kẹt.

Lập trình 22/09/2026 7 phút

Consumer lag: tín hiệu cảnh báo số một của hệ message queue, đo thật qua offset

Hệ message queue có khoẻ không? Đừng nhìn CPU hay throughput — nhìn consumer lag. Bài này đo thật trên Kafka: backlog 200.000 message, consumer chậm, producer thêm 100.000 — lag vọt từ 150.000 lên 250.000 dù consumer vẫn chạy, rồi về 0 khi bắt kịp. LAG = LOG-END-OFFSET trừ CURRENT-OFFSET, và nó là chỉ báo sớm nhất rằng hệ sắp không theo kịp.