[Series Hệ thống chịu tải cao] Bài 2: Mổ xẻ Kafka – Tại sao nó có thể "nuốt" hàng triệu Message mỗi giây?
Chào anh em! Ở bài trước, mình đã ví Kafka như một cái hồ chứa nước khổng lồ cho hệ thống Metro. Hôm nay, chúng ta sẽ đi sâu vào cấu tạo của cái hồ đó.
Nhiều người mới tiếp cận thường coi Kafka là một cái Message Queue (hàng đợi tin nhắn) giống như RabbitMQ. Nhưng thực tế, Anthropic (cha đẻ của Claude) hay LinkedIn (nơi khai sinh ra Kafka) coi nó là một Distributed Streaming Platform. Sự khác biệt nằm ở chính "nội tạng" của nó.
1. Cơ chế Append-only Log: Bí mật của tốc độ
Đa số các Database truyền thống (như MySQL) khi ghi dữ liệu phải tìm đúng chỗ, cập nhật index, kiểm tra ràng buộc... rất tốn tài nguyên ổ cứng (Disk I/O).
Kafka thì khác. Nó ghi dữ liệu theo kiểu Append-only. Tức là dữ liệu mới cứ thế "đắp" vào cuối file log.
- Việc ghi tuần tự (Sequential Write) trên ổ cứng nhanh hơn gấp hàng trăm lần so với ghi ngẫu nhiên (Random Write).
- Kafka không bao giờ đi tìm để sửa dữ liệu đã ghi. Đã vào Log là nằm đó, bất biến (Immutable).
2. Topic và Partition: Chìa khóa để Scale "vô cực"
Nếu bạn chỉ có một cái file Log duy nhất, thì dù nhanh đến mấy cũng sẽ có giới hạn. Để giải quyết, Kafka chia nhỏ dữ liệu ra:
- Topic: Giống như một cái bàn ăn lớn (ví dụ: Topic
METRO_TAP_EVENTS). - Partition: Là việc chia cái bàn đó ra thành nhiều phần nhỏ.
Giả sử hệ thống Metro của bạn có 10 ga. Thay vì dồn hết dữ liệu vào 1 chỗ, bạn chia Topic thành 10 Partitions. Lúc này, bạn có thể dùng 10 con Server (Consumers) để xử lý song song dữ liệu từ 10 vùng này. Đây chính là cách Kafka giúp bạn mở rộng hệ thống không giới hạn.
3. Broker và Replication: "Chết nhưng không mất"
Trong một hệ thống chịu tải cao (High Availability), việc một con server lăn quay ra chết là chuyện... thường ngày ở huyện. Kafka xử lý việc này bằng cơ chế
Replication:
- Mỗi Partition sẽ có một bản chính (Leader) và các bản sao (Followers).
- Khi bạn ghi dữ liệu vào Leader, nó sẽ được copy sang các Followers ở các server (Brokers) khác nhau.
- Nếu con Server chứa Leader "tèo", một con Follower sẽ lập tức đứng lên thay thế. Hệ thống quẹt thẻ của bạn vẫn chạy phăm phăm như chưa có chuyện gì xảy ra.
4. Consumer Group: Chia để trị
Một điểm cực hay của Kafka là Consumer Group. Nhiều Service khác nhau (Thông báo, Kế toán, Signal) có thể cùng đọc một Topic mà không tranh giành nhau. Mỗi Service sẽ có một "con trỏ" (Offset) riêng để biết mình đã đọc đến đâu. Nếu Service Thông báo bị lag, nó cũng không làm ảnh hưởng đến Service Kế toán.
Kinh nghiệm thực tế từ hệ thống Metro (AFC)
Khi làm về hệ thống quẹt thẻ, mình thường chia Partition dựa trên Station_ID.
- Việc này đảm bảo thứ tự các sự kiện của cùng một nhà ga luôn được giữ nguyên (ví dụ: Khách vào ga rồi mới ra ga).
- Đồng thời, nó giúp mình dễ dàng scale: Nếu ga Bến Thành quá đông khách, mình chỉ cần cấp thêm tài nguyên xử lý cho Partition tương ứng của ga đó.
Tạm kết
Kafka nhanh không phải vì nó có phép thuật, mà vì nó tận dụng tối đa sức mạnh của việc ghi tuần tự và khả năng xử lý song song.
Hiểu được những khái niệm này, bạn sẽ không còn thấy Kafka là một "hộp đen" bí ẩn nữa. Ở bài tiếp theo (Bài 3), chúng ta sẽ rời xa những dòng Log khô khan để đến với thế giới của Elasticsearch – nơi dữ liệu được biến hóa để có thể tìm kiếm trong "chớp mắt".
Bạn đã từng gặp rắc rối với việc mất dữ liệu khi server bị sập chưa? Kafka chính là cứu cánh đấy. Hẹn gặp lại anh em ở bài sau!
All Rights Reserved