Apache Kafka 4.x: Kỷ nguyên Event Streaming không còn ZooKeeper
Posted on: 4/26/2026 7:15:51 AM
Table of contents
- 1. KRaft Mode: Vĩnh biệt ZooKeeper
- 2. Share Groups: Khi Kafka cũng có Queue
- 3. Consumer Rebalance Protocol thế hệ mới (KIP-848)
- 4. Eligible Leader Replicas — Không còn mất dữ liệu khi bầu Leader
- 5. Kafka Streams 4.2: Dead Letter Queue & Server-Side Rebalance
- 6. Tích hợp Kafka 4.x với .NET
- 7. Kiến trúc Event-Driven hoàn chỉnh với Kafka 4.x
- 8. Migration từ ZooKeeper sang KRaft
- 9. Kafka 4.x so với các Messaging Systems khác
- 10. Best Practices cho Kafka Production
- Kết luận
- Tham khảo
Apache Kafka vừa đánh dấu cột mốc lịch sử lớn nhất kể từ ngày ra đời: loại bỏ hoàn toàn ZooKeeper. Với phiên bản 4.0 (tháng 3/2025) và 4.2 (tháng 2/2026), Kafka không chỉ đơn giản hóa kiến trúc mà còn mang đến những tính năng mới thay đổi hoàn toàn cách chúng ta xây dựng hệ thống event-driven. Bài viết này sẽ đi sâu vào KRaft mode, Share Groups (Queues), Consumer Rebalance Protocol thế hệ mới, và cách tích hợp Kafka 4.x với .NET.
1. KRaft Mode: Vĩnh biệt ZooKeeper
Suốt hơn một thập kỷ, ZooKeeper là thành phần không thể thiếu trong mọi deployment Kafka. Nó đảm nhận việc quản lý metadata, bầu chọn leader cho partition, và lưu trữ cấu hình cluster. Nhưng ZooKeeper cũng là nguồn gốc của vô số vấn đề vận hành: thêm một hệ thống phân tán phải quản lý, giới hạn số lượng partition (~200K), và bottleneck khi metadata thay đổi.
KRaft (Kafka Raft) là giải pháp: Kafka tự quản lý metadata của chính mình thông qua giao thức Raft consensus, được tích hợp trực tiếp vào broker. Không cần cluster ZooKeeper riêng biệt. Không cần vận hành thêm hệ thống nào.
graph LR
subgraph "Kafka < 4.0 (ZooKeeper)"
P1[Producer] --> B1[Broker 1]
P1 --> B2[Broker 2]
P1 --> B3[Broker 3]
B1 --> ZK[ZooKeeper Ensemble]
B2 --> ZK
B3 --> ZK
ZK --> ZK1[ZK Node 1]
ZK --> ZK2[ZK Node 2]
ZK --> ZK3[ZK Node 3]
C1[Consumer] --> B1
C1 --> B2
C1 --> B3
end
style ZK fill:#ff9800,stroke:#e65100,color:#fff
style ZK1 fill:#ffe0b2,stroke:#ff9800,color:#333
style ZK2 fill:#ffe0b2,stroke:#ff9800,color:#333
style ZK3 fill:#ffe0b2,stroke:#ff9800,color:#333
style B1 fill:#e94560,stroke:#fff,color:#fff
style B2 fill:#e94560,stroke:#fff,color:#fff
style B3 fill:#e94560,stroke:#fff,color:#fff
style P1 fill:#2c3e50,stroke:#fff,color:#fff
style C1 fill:#2c3e50,stroke:#fff,color:#fff
Kiến trúc Kafka trước 4.0: cần cluster ZooKeeper riêng biệt
graph LR
subgraph "Kafka 4.x (KRaft)"
P2[Producer] --> KB1[Broker 1]
P2 --> KB2[Broker 2]
P2 --> KB3[Broker 3]
KB1 ---|Raft Consensus| KB2
KB2 ---|Raft Consensus| KB3
KB3 ---|Raft Consensus| KB1
C2[Consumer] --> KB1
C2 --> KB2
C2 --> KB3
end
style KB1 fill:#4CAF50,stroke:#fff,color:#fff
style KB2 fill:#4CAF50,stroke:#fff,color:#fff
style KB3 fill:#4CAF50,stroke:#fff,color:#fff
style P2 fill:#2c3e50,stroke:#fff,color:#fff
style C2 fill:#2c3e50,stroke:#fff,color:#fff
Kiến trúc Kafka 4.x: KRaft tích hợp trực tiếp, không cần ZooKeeper
Những cải tiến cốt lõi của KRaft
| Tiêu chí | ZooKeeper Mode | KRaft Mode |
|---|---|---|
| Số partition tối đa/cluster | ~200,000 | Hàng triệu |
| Thời gian khởi động cluster | Phút (phụ thuộc ZK) | Giây |
| Thành phần cần vận hành | Kafka + ZooKeeper | Chỉ Kafka |
| Controller failover | Chậm (ZK session timeout) | Nhanh (Raft leader election) |
| Metadata propagation | Async qua ZK watchers | Event-driven qua metadata log |
| Security model | 2 hệ thống ACL riêng | Thống nhất 1 hệ thống |
KRaft Controller vs Broker
Trong KRaft mode, bạn có thể chạy node ở chế độ controller-only, broker-only, hoặc combined. Với production cluster lớn, khuyến nghị tách riêng controller nodes (thường 3 hoặc 5 nodes) khỏi broker nodes để đảm bảo metadata management không bị ảnh hưởng bởi traffic xử lý message.
2. Share Groups: Khi Kafka cũng có Queue
Trước Kafka 4.x, mỗi partition chỉ có thể được consume bởi đúng một consumer trong cùng consumer group. Điều này đảm bảo ordering nhưng lại tạo ra bottleneck: nếu bạn có 10 partitions nhưng cần 20 workers xử lý, bạn phải re-partition topic — một thao tác tốn kém và gây gián đoạn.
Share Groups (KIP-932) giải quyết triệt để vấn đề này bằng cách cho phép nhiều consumer cùng đọc từ một partition với cơ chế acknowledge từng record riêng lẻ — giống hệt như một message queue truyền thống (RabbitMQ, SQS) nhưng chạy trên hạ tầng Kafka.
graph TD
T[Topic: order-processing] --> P1[Partition 0]
T --> P2[Partition 1]
T --> P3[Partition 2]
subgraph "Consumer Group truyền thống"
P1 --> CG1[Consumer A]
P2 --> CG2[Consumer B]
P3 --> CG3[Consumer C]
end
subgraph "Share Group (Kafka 4.x)"
P1 -.-> SG1[Worker 1]
P1 -.-> SG2[Worker 2]
P2 -.-> SG1
P2 -.-> SG3[Worker 3]
P3 -.-> SG2
P3 -.-> SG3
end
style T fill:#e94560,stroke:#fff,color:#fff
style P1 fill:#f8f9fa,stroke:#e94560,color:#333
style P2 fill:#f8f9fa,stroke:#e94560,color:#333
style P3 fill:#f8f9fa,stroke:#e94560,color:#333
style CG1 fill:#2c3e50,stroke:#fff,color:#fff
style CG2 fill:#2c3e50,stroke:#fff,color:#fff
style CG3 fill:#2c3e50,stroke:#fff,color:#fff
style SG1 fill:#4CAF50,stroke:#fff,color:#fff
style SG2 fill:#4CAF50,stroke:#fff,color:#fff
style SG3 fill:#4CAF50,stroke:#fff,color:#fff
So sánh Consumer Group truyền thống vs Share Group: workers có thể chia sẻ partition
Các loại Acknowledgement trong Share Groups
Kafka 4.2 bổ sung thêm kiểu RENEW bên cạnh ACCEPT và REJECT, cho phép consumer gia hạn thời gian xử lý khi gặp tác vụ chạy lâu:
- ACCEPT: Record đã được xử lý thành công, đánh dấu hoàn thành
- REJECT: Record xử lý thất bại, trả lại cho Share Group để worker khác nhận
- RENEW (mới trong 4.2): Gia hạn thời gian xử lý cho các tác vụ chạy lâu như ML inference hay video transcoding
Share Groups không thay thế Consumer Groups
Share Groups được thiết kế cho các use case point-to-point messaging nơi ordering không quan trọng bằng throughput. Nếu ứng dụng yêu cầu xử lý theo đúng thứ tự trong partition (ví dụ: event sourcing, CDC), hãy tiếp tục sử dụng Consumer Groups truyền thống.
3. Consumer Rebalance Protocol thế hệ mới (KIP-848)
Một trong những "nỗi đau" lớn nhất khi vận hành Kafka là stop-the-world rebalance. Mỗi khi một consumer join hoặc leave group, toàn bộ consumer trong group phải dừng xử lý, revoke partitions, và chờ reassignment. Với consumer group lớn (hàng trăm instances), quá trình này có thể mất hàng phút — nghĩa là hàng phút không xử lý được message nào.
KIP-848 mang đến giao thức rebalance mới, được bật mặc định trong Kafka 4.0:
| Đặc điểm | Eager Rebalance (cũ) | KIP-848 Protocol (mới) |
|---|---|---|
| Khi consumer mới join | Tất cả revoke, reassign lại | Chỉ di chuyển partition cần thiết |
| Khi consumer rời group | Stop-the-world | Incremental, không gián đoạn |
| Assignment logic | Client-side (group leader) | Server-side (broker quyết định) |
| Thời gian rebalance | Tỷ lệ thuận với số consumer | Gần như không đổi (O(1)) |
| Downtime khi scale | Có, đáng kể | Gần như bằng 0 |
Để kích hoạt trên client, chỉ cần set:
group.protocol=consumer
4. Eligible Leader Replicas — Không còn mất dữ liệu khi bầu Leader
KIP-966 giới thiệu khái niệm Eligible Leader Replicas (ELR) — một tập con của ISR (In-Sync Replicas) được đảm bảo có đầy đủ dữ liệu đến high-watermark. Trong trường hợp leader partition gặp sự cố, Kafka sẽ chỉ bầu leader mới từ các ELR, ngăn chặn việc một replica chưa đồng bộ hoàn toàn trở thành leader và gây mất dữ liệu.
sequenceDiagram
participant P as Producer
participant L as Leader Broker
participant R1 as Replica 1 (ELR)
participant R2 as Replica 2 (Non-ELR)
P->>L: Produce message (offset 100)
L->>R1: Replicate (offset 100) ✓
L->>R2: Replicate (offset 95) — lag
Note over L: High-watermark = 100
Note over R1: Caught up → ELR ✓
Note over R2: Lagging → NOT ELR ✗
L--xL: Leader crashes!
Note over R1,R2: Leader election
R1->>R1: Elected as new leader (ELR, no data loss)
R2--xR2: Rejected (not in ELR, would lose offsets 96-100)
ELR đảm bảo chỉ replica đã đồng bộ hoàn toàn mới được bầu làm leader
5. Kafka Streams 4.2: Dead Letter Queue & Server-Side Rebalance
Kafka Streams trong phiên bản 4.2 nhận được nhiều cải tiến quan trọng cho production:
Dead Letter Queue (DLQ) tích hợp
Trước 4.2, khi một record gây lỗi trong Kafka Streams topology, bạn chỉ có 2 lựa chọn: skip record hoặc crash ứng dụng. Giờ đây, exception handler có thể redirect record lỗi sang Dead Letter Queue — một topic riêng để phân tích và xử lý sau.
// Kafka Streams 4.2 — DLQ trong exception handler
StreamsConfig config = new StreamsConfig();
config.put(StreamsConfig.PROCESSING_EXCEPTION_HANDLER_CLASS_CONFIG,
DeadLetterQueueExceptionHandler.class);
config.put("dead.letter.queue.topic", "order-processing-dlq");
Server-Side Rebalance Protocol (GA)
Kafka Streams giờ sử dụng broker-side task assignment thay vì client-side, giảm đáng kể độ phức tạp và thời gian rebalance khi scale ứng dụng stream processing.
Anchored Wall-Clock Punctuation
Tính năng mới cho phép schedule punctuation tại thời điểm cố định (ví dụ: đầu mỗi giờ, đầu mỗi ngày) thay vì chỉ dựa trên interval. Hữu ích cho các tác vụ aggregation theo lịch cố định.
6. Tích hợp Kafka 4.x với .NET
Thư viện chính thức Confluent.Kafka (phiên bản 2.14.0) cung cấp high-level Producer và Consumer tương thích đầy đủ với Kafka 4.x. Dưới đây là các patterns production-ready.
Producer với Idempotent Delivery
using Confluent.Kafka;
var config = new ProducerConfig
{
BootstrapServers = "kafka-cluster:9092",
EnableIdempotence = true,
Acks = Acks.All,
MessageSendMaxRetries = 3,
LingerMs = 5,
BatchSize = 65536
};
using var producer = new ProducerBuilder<string, string>(config)
.SetErrorHandler((_, e) =>
Console.Error.WriteLine($"Kafka error: {e.Reason}"))
.Build();
var result = await producer.ProduceAsync("order-events",
new Message<string, string>
{
Key = orderId,
Value = JsonSerializer.Serialize(orderEvent),
Headers = new Headers
{
{ "correlation-id", Encoding.UTF8.GetBytes(correlationId) },
{ "event-type", Encoding.UTF8.GetBytes("OrderCreated") }
}
});
Console.WriteLine($"Delivered to {result.TopicPartitionOffset}");
Consumer với Manual Offset
var config = new ConsumerConfig
{
BootstrapServers = "kafka-cluster:9092",
GroupId = "order-processor",
GroupProtocol = "consumer", // KIP-848 protocol mới
AutoOffsetReset = AutoOffsetReset.Earliest,
EnableAutoCommit = false,
MaxPollIntervalMs = 300000
};
using var consumer = new ConsumerBuilder<string, string>(config)
.SetPartitionsAssignedHandler((c, partitions) =>
Console.WriteLine($"Assigned: {string.Join(", ", partitions)}"))
.Build();
consumer.Subscribe("order-events");
while (!cancellationToken.IsCancellationRequested)
{
var result = consumer.Consume(cancellationToken);
try
{
await ProcessOrderEvent(result.Message);
consumer.StoreOffset(result);
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to process {Key}", result.Message.Key);
await PublishToDlq(result.Message);
consumer.StoreOffset(result);
}
}
Tích hợp với .NET Aspire
Package Aspire.Confluent.Kafka cung cấp dependency injection, health checks, và telemetry tự động:
// Program.cs — .NET Aspire host
var builder = DistributedApplication.CreateBuilder(args);
var kafka = builder.AddKafka("messaging")
.WithKRaft() // Sử dụng KRaft mode
.WithDataVolume();
var orderService = builder.AddProject<Projects.OrderService>()
.WithReference(kafka);
// OrderService — DI registration
builder.AddKafkaProducer<string, OrderEvent>("messaging");
builder.AddKafkaConsumer<string, OrderEvent>("messaging", settings =>
{
settings.Config.GroupId = "order-processor";
settings.Config.GroupProtocol = "consumer";
});
7. Kiến trúc Event-Driven hoàn chỉnh với Kafka 4.x
Kafka 4.x với Share Groups mở ra khả năng xây dựng kiến trúc event-driven linh hoạt hơn, kết hợp cả pub/sub và point-to-point messaging trên cùng một platform:
graph TD
API[API Gateway] --> CMD[Command Service]
API --> QRY[Query Service]
CMD --> KT1[Topic: domain-events
Consumer Group — ordered]
CMD --> KT2[Topic: task-queue
Share Group — parallel]
KT1 --> ES[Event Store Service]
KT1 --> PROJ[Projection Service]
KT1 --> NOTIFY[Notification Service]
KT2 --> W1[Worker 1]
KT2 --> W2[Worker 2]
KT2 --> W3[Worker 3]
ES --> DB1[(Event Store)]
PROJ --> DB2[(Read DB)]
QRY --> DB2
W1 --> EXT[External APIs]
W2 --> EXT
W3 --> EXT
style API fill:#2c3e50,stroke:#fff,color:#fff
style CMD fill:#e94560,stroke:#fff,color:#fff
style QRY fill:#e94560,stroke:#fff,color:#fff
style KT1 fill:#4CAF50,stroke:#fff,color:#fff
style KT2 fill:#ff9800,stroke:#fff,color:#fff
style ES fill:#f8f9fa,stroke:#e94560,color:#333
style PROJ fill:#f8f9fa,stroke:#e94560,color:#333
style NOTIFY fill:#f8f9fa,stroke:#e94560,color:#333
style W1 fill:#f8f9fa,stroke:#ff9800,color:#333
style W2 fill:#f8f9fa,stroke:#ff9800,color:#333
style W3 fill:#f8f9fa,stroke:#ff9800,color:#333
style DB1 fill:#2c3e50,stroke:#fff,color:#fff
style DB2 fill:#2c3e50,stroke:#fff,color:#fff
style EXT fill:#9e9e9e,stroke:#fff,color:#fff
Kiến trúc kết hợp Consumer Group (ordered events) và Share Group (parallel tasks)
Khi nào dùng Consumer Group vs Share Group?
- Consumer Group: Domain events, CDC streams, event sourcing — nơi thứ tự xử lý quan trọng
- Share Group: Email gửi, image processing, report generation, API calls — nơi cần scale workers linh hoạt
8. Migration từ ZooKeeper sang KRaft
Nếu bạn đang chạy Kafka cluster với ZooKeeper, quy trình migration sang KRaft bao gồm 3 bước chính:
kafka-features.sh describe để kiểm tra feature levels.
kafka-metadata.sh snapshot để chuyển metadata từ ZooKeeper sang KRaft format. Khởi động KRaft controllers. Chuyển từng broker sang KRaft mode với rolling restart. Verify metadata consistency giữa ZK và KRaft.
zookeeper.connect khỏi broker configs. Decommission ZooKeeper ensemble. Monitor cluster health trong 48-72 giờ trước khi xóa ZK nodes.
Lưu ý quan trọng khi migration
Kafka 4.0+ không còn hỗ trợ ZooKeeper mode. Nếu cluster đang chạy ZooKeeper, bạn phải migration sang KRaft trước khi nâng cấp lên 4.x. Thực hiện migration trên phiên bản 3.7 hoặc 3.8, sau đó mới upgrade lên 4.x.
9. Kafka 4.x so với các Messaging Systems khác
| Tiêu chí | Kafka 4.x | RabbitMQ | AWS SQS/SNS |
|---|---|---|---|
| Mô hình | Pub/Sub + Queue (Share Groups) | Queue + Pub/Sub (Exchange) | Queue (SQS) + Pub/Sub (SNS) |
| Throughput | Hàng triệu msg/s | ~50K msg/s | Gần như unlimited (managed) |
| Message retention | Configurable (ngày/tuần/vĩnh viễn) | Đến khi consumed | 14 ngày (SQS) |
| Ordering | Per-partition guaranteed | Per-queue FIFO | FIFO queue hoặc best-effort |
| Consumer scaling | Consumer Group + Share Group | Competing consumers | Auto-scaling consumers |
| Stream processing | Kafka Streams, ksqlDB | Không tích hợp | Cần Lambda/Kinesis |
| Vận hành | Self-managed hoặc Confluent Cloud | Self-managed hoặc CloudAMQP | Fully managed |
| Chi phí | Infra cost (hoặc Confluent pricing) | Infra cost | Pay-per-request |
10. Best Practices cho Kafka Production
Sizing & Performance
- Partition count: Bắt đầu với số partitions = số consumers dự kiến × 2. Tăng partition dễ, giảm thì không
- Replication factor: Luôn đặt ít nhất 3 cho production. Kết hợp
min.insync.replicas=2vớiacks=all - Batch size: Tăng
batch.size(64KB-256KB) vàlinger.ms(5-20ms) để cải thiện throughput - Compression: Sử dụng
compression.type=zstdcho tỷ lệ nén tốt nhất hoặclz4cho latency thấp nhất
Monitoring essentials
- Consumer lag: Metric quan trọng nhất — nếu lag tăng liên tục, consumer không theo kịp producer
- Under-replicated partitions: Báo hiệu broker gặp vấn đề I/O hoặc network
- Request latency (p99): Theo dõi produce và fetch latency ở percentile 99
- Controller active count: Trong KRaft, luôn phải có đúng 1 active controller
Security
- Sử dụng SASL/SCRAM hoặc mTLS cho authentication
- Bật TLS encryption cho mọi kết nối inter-broker và client-broker
- Cấu hình ACLs chi tiết per-topic, per-consumer-group
- Với KRaft, chỉ cần quản lý một hệ thống ACL duy nhất (không còn ZooKeeper ACLs riêng)
Kết luận
Apache Kafka 4.x đánh dấu bước chuyển mình lớn nhất trong lịch sử của nền tảng event streaming phổ biến nhất thế giới. Việc loại bỏ ZooKeeper không chỉ đơn giản hóa vận hành mà còn mở ra khả năng scale đến hàng triệu partitions. Share Groups lấp đầy khoảng trống lớn nhất của Kafka — khả năng hoạt động như message queue — khiến nhiều hệ thống không còn cần chạy song song cả Kafka lẫn RabbitMQ. Với ecosystem .NET ngày càng hoàn thiện qua Confluent.Kafka và .NET Aspire, đây là thời điểm lý tưởng để đưa Kafka vào kiến trúc event-driven của bạn.
Tham khảo
- Apache Kafka 4.0.0 Release Announcement — kafka.apache.org
- Apache Kafka 4.2.0 Release Announcement — kafka.apache.org
- Apache Kafka 4.0: Default KRaft, Queues, Faster Rebalances — confluent.io
- .NET Client for Apache Kafka — Confluent Documentation
- Aspire.Confluent.Kafka — NuGet
- Kafka 4.0: KRaft, Queues, Better Rebalance — SoftwareMill
Disclaimer: The opinions expressed in this blog are solely my own and do not reflect the views or opinions of my employer or any affiliated organizations. The content provided is for informational and educational purposes only and should not be taken as professional advice. While I strive to provide accurate and up-to-date information, I make no warranties or guarantees about the completeness, reliability, or accuracy of the content. Readers are encouraged to verify the information and seek independent advice as needed. I disclaim any liability for decisions or actions taken based on the content of this blog.