Bỏ qua để đến nội dung
Knowledge Hub

Kafka là distributed log: topic, partition và offset Cơ bản

Thời gian đọc ước tính: 6 phút

Service đơn hàng phát ba event cho một đơn: created, paid, shipped. Billing cần đọc để tính tiền, analytics cần đọc để làm báo cáo. Nếu coi Kafka như queue truyền thống (consumer lấy message ra là message biến mất), bạn sẽ không giải thích được:

  • Vì sao hai service cùng đọc đủ ba event.
  • Vì sao analytics đọc lại được từ đầu.
  • Vì sao một consumer chậm có thể mất dữ liệu mà không ai xoá thủ công.

Mô hình đúng là distributed log: mỗi partition là một dãy record chỉ append, mỗi record có một offset. Đọc không xoá record. Broker dọn dữ liệu theo retention/compaction, không quan tâm consumer đã đọc hay chưa.

Khái niệm Một câu
Topic Tên luồng record, ví dụ orders
Partition Một log có thứ tự; offset chỉ có nghĩa trong cặp (topic, partition)
Offset Vị trí record trong partition, tăng dần, không dùng làm bộ đếm nghiệp vụ
Consumer group Nhóm consumer chia partition; mỗi group giữ offset riêng
Retention Thời gian/dung lượng giữ dữ liệu, độc lập với consumer
Replication Mỗi partition có leader và follower trên các broker khác nhau (bài ISR)

Đang tải diagram…

  • Dữ liệu chia theo partition để scale ngang; mỗi partition được nhân bản sang broker khác.
  • Thứ tự chỉ được bảo đảm trong một partition, không có thứ tự toàn topic. Cách chọn partition cho record: xem message key.
  • Trong một group, mỗi partition tại một thời điểm chỉ thuộc một consumer (consumer group và rebalance).
  • Group khác đọc độc lập, nên billing và analytics không ảnh hưởng nhau.
Producer append; consumer đọc và commit vị trí riêng
Producer append; consumer đọc và commit vị trí riêngBước 1/4: Producer gửi record với key. Partitioner chọn partition; trong demo chỉ có một partition.ProducerPartition logConsumer grouporder-created
Producer → Partition logorder-created
Bước 1/4

Producer gửi record với key. Partitioner chọn partition; trong demo chỉ có một partition.

Sau ba lần append vào partition mới, log trông như sau:

Offset Value
0 created
1 paid
2 shipped

Billing xử lý xong offset 2 thì commit 3 (offset sẽ đọc tiếp). Group analytics mới vẫn đọc lại từ offset 0 được, miễn là dữ liệu chưa bị retention dọn. Chi tiết commit nằm ở bài commit offset.

Với cleanup.policy=delete (mặc định), Kafka xoá cả segment cũ theo retention.ms (mặc định 7 ngày) hoặc retention.bytes (mặc định không giới hạn). Một consumer lag quá cửa sổ này sẽ không đọc lại được phần đã xoá. Chi tiết và compaction: retention và compaction.

Quy tắc thiết kế: cửa sổ retention phải lớn hơn thời gian sự cố tệ nhất mà bạn chấp nhận được trước khi consumer bắt kịp.

Từ Kafka 4.0, ZooKeeper đã bị loại bỏ: Kafka chỉ chạy ở chế độ KRaft (metadata cluster do chính các controller của Kafka quản lý bằng Raft, không cần cụm ZooKeeper riêng). Cluster mới nên dựng ở KRaft; cluster cũ dùng ZooKeeper phải migrate trước khi nâng lên 4.0.

Demo trong repo chạy trên image Confluent Platform 7.6 (Kafka 3.6) với ZooKeeper, qua examples/docker-compose.yml. Offset, partition và consumer group hoạt động giống nhau giữa các phiên bản; chỉ phần dựng cluster khác. Các bài khác trong chuỗi mô tả cấu hình theo Kafka 4.x và sẽ ghi rõ khi một demo dùng phiên bản cũ.

Dùng Kafka log khi Cân nhắc công cụ khác khi
Nhiều service cần đọc cùng event độc lập Chỉ cần chia job cho worker, không cần replay (xem queue types RabbitMQ hoặc share groups)
Cần replay để dựng lại projection hoặc điều tra lỗi Cần routing phức tạp theo pattern, priority queue
Throughput cao, ghi tuần tự Volume rất nhỏ và không cần retention

Chạy demo một broker (một partition, replication factor 1, chỉ để nhìn offset; không chứng minh chịu lỗi nhiều broker):

Terminal window
docker compose -f examples/docker-compose.yml up -d zookeeper kafka
npx --prefix examples ts-node examples/src/kafka-log/log-demo.ts

Script tạo topic mới, ghi created, paid, shipped, rồi một group mới đọc từ đầu và in partition, offset, key, value (partition 0, offset 0 đến 2). Log JSON của KafkaJS và TimeoutNegativeWarning xen vào output là nhiễu của client.

Lợi ích của log

  • Nhiều consumer group đọc cùng dữ liệu theo tốc độ riêng.
  • Replay trong cửa sổ retention để dựng lại projection hoặc điều tra lỗi.
  • Partition cho phép tăng throughput và giữ thứ tự theo key.

Trách nhiệm chuyển sang ứng dụng

  • Thứ tự chỉ trong partition; key skew tạo partition nóng.
  • Retention không chờ consumer chậm.
  • Offset commit và side effect ngoài Kafka là hai việc riêng; cần idempotency hoặc outbox.
  1. Đặt replication.factor=3 và min.insync.replicas=2 cho topic quan trọng (mặc định broker là RF=1, min ISR=1).
  2. Chọn số partition theo throughput và số consumer song song tối đa, vì giảm partition không được.
  3. Đặt retention theo SLA khôi phục, không để mặc định 7 ngày một cách vô thức.
  4. Chọn key theo entity cần thứ tự.
  5. Theo dõi consumer lag theo từng partition và theo thời gian.
  6. Cluster mới dùng KRaft; không lên kế hoạch dựa vào ZooKeeper.

Tự kiểm tra: (1) Billing commit offset 3, analytics group mới có đọc lại offset 0 được không, điều kiện gì cần đúng? (2) Vì sao cùng key giúp thứ tự nhưng không bảo đảm thứ tự mọi event trong topic? (3) DB đã ghi nhưng offset chưa commit rồi consumer crash: chuyện gì xảy ra khi restart?