Skip to main content

Kafka Fundamentals

Topic & Partition — หน่วยจัดเก็บข้อมูลพื้นฐาน​

Topic คือ "ชื่อกลุ่มข้อมูล" เชิง logical (เหมือนชื่อตารางใน database) แต่ข้างใน Topic จริงๆ ถูกแบ่งเป็น Partition หลายตัว — แต่ละ Partition คือ append-only log ที่เรียงลำดับ (ordered, immutable) และมี offset (เลขลำดับ) กำกับทุก message ไว้

Topic: orders
├── Partition 0: [msg0][msg1][msg2][msg3]... offset 0,1,2,3...
├── Partition 1: [msg0][msg1][msg2]... offset 0,1,2...
└── Partition 2: [msg0][msg1][msg2][msg3][msg4] offset 0,1,2,3,4...

Partition คือหน่วยของ parallelism — ยิ่งมี partition เยอะ ยิ่งกระจายงานให้หลาย consumer ทำงานพร้อมกันได้มากขึ้น (รายละเอียดอยู่ใน Producer & Consumer)

🧠 จำง่ายๆ

"Topic คือชื่อสมุดบันทึก, Partition คือเล่มย่อยที่แยกเขียน" — สมุดเล่มเดียวเขียนได้คนเดียวที่ละ บรรทัด (ตามลำดับ) แต่ถ้าแบ่งเป็นหลายเล่มย่อย (partition) หลายคนเขียนพร้อมกันได้ แต่ละเล่มก็ยัง เรียงบรรทัดในตัวเองอยู่ดี (ordered ภายใน partition)

🎯 Beyond: จุดที่ชาวบ้านไม่ค่อยรู้

Partition ไม่ได้เป็นไฟล์เดียวบน disk — มันถูกแบ่งเป็น segment files ย่อยๆ (default ขนาด 1 GB ต่อ segment หรือตามเวลา log.segment.ms) เหตุผลที่ไม่เก็บเป็นไฟล์เดียวยาวๆ คือ Kafka ต้อง ลบข้อมูลเก่าทิ้งตาม retention policy การลบทำได้ง่ายแค่ "ลบทั้ง segment file ที่หมดอายุ" (O(1) ไม่ต้อง rewrite อะไร) ต่างจากถ้าเป็นไฟล์เดียวที่ต้องมานั่งตัดข้อมูลเก่าออกจากกลางไฟล์ซึ่ง แพงกว่ามาก — segment ล่าสุดที่กำลังถูกเขียนอยู่เรียกว่า active segment และมีแค่ segment เดียวเท่านั้นที่เปิดเขียนได้ในแต่ละ partition ณ เวลาหนึ่ง

Broker & Cluster​

Broker คือ Kafka server หนึ่งตัว (process เดียว) ที่เก็บ partition บางส่วนไว้ — Cluster คือกลุ่ม broker หลายตัวทำงานร่วมกัน แต่ละ partition ถูกกระจาย (distribute) ไปอยู่ บน broker ต่างๆ ไม่ใช่ broker เดียวเก็บทุกอย่าง

Cluster (3 brokers)
Broker 1: orders-partition-0 (leader), orders-partition-1 (replica)
Broker 2: orders-partition-1 (leader), orders-partition-2 (replica)
Broker 3: orders-partition-2 (leader), orders-partition-0 (replica)
🧠 จำง่ายๆ

"Broker = คลังสินค้าแต่ละสาขา, Partition = กล่องสินค้าที่กระจายไปเก็บ" — กล่องเดียวกัน (replica) อาจถูกเก็บซ้ำไว้หลายสาขาเผื่อสาขาหลักไฟไหม้ (broker ล่ม) แต่ "สาขาหลัก" ของกล่องนั้น (leader) มีแค่ที่เดียว

🎯 Beyond: จุดที่ชาวบ้านไม่ค่อยรู้

ตั้งแต่ Kafka 2.8+ มี mode ใหม่ที่ไม่ต้องพึ่ง ZooKeeper อีกต่อไปเรียกว่า KRaft (Kafka Raft metadata mode) — เดิมที Kafka ใช้ ZooKeeper แยกต่างหากเก็บ cluster metadata (broker ไหนอยู่ คุมพาร์ติชันไหน) ซึ่งเป็นจุดอ่อนเพราะต้องดูแลระบบสองระบบคู่กัน (Kafka + ZooKeeper) KRaft เปลี่ยนมาเก็บ metadata ไว้ใน Kafka เองผ่าน Raft consensus algorithm (คล้ายกับที่ etcd ใช้ใน Kubernetes) ทำให้ไม่ต้องรัน ZooKeeper แยกอีกต่อไป ลด operational complexity ลงมาก Kafka เวอร์ชันใหม่ (4.0+) ตัด ZooKeeper ออกไปเลย — ถ้า interviewer ถามเรื่อง "Kafka ไม่ใช้ ZooKeeper แล้วได้ยินมา จริงไหม" คือจริง และเป็นหนึ่งใน architectural change ที่สำคัญที่สุดของ Kafka ในรอบหลายปี

Offset — ตำแหน่งที่อ่านถึง​

Offset คือเลขลำดับที่กำกับแต่ละ message ภายใน partition (เริ่มจาก 0 เพิ่มขึ้นเรื่อยๆ) Consumer เป็นคนจำเองว่าตัวเองอ่านถึง offset ไหนแล้ว (เก็บไว้ใน topic พิเศษชื่อ __consumer_offsets) — Kafka broker ไม่ได้ติดตามว่า consumer อ่านอะไรไปแล้วบ้าง ต่างจาก message queue แบบดั้งเดิม (เช่น RabbitMQ) ที่ broker เป็นคนจัดการ state การอ่านให้

Partition 0: [msg0][msg1][msg2][msg3][msg4][msg5]
^
consumer offset = 3 (อ่านถึง msg2 แล้ว ตัวต่อไปคือ msg3)
🧠 จำง่ายๆ

"Offset คือที่คั่นหนังสือของผู้อ่านแต่ละคน ไม่ใช่ของห้องสมุด" — ห้องสมุด (broker) แค่เก็บ หนังสือไว้ให้ครบทุกหน้า ส่วน "อ่านถึงหน้าไหนแล้ว" เป็นหน้าที่ผู้อ่าน (consumer) ต้องจำเอง — ผู้อ่านหลายคนอ่านหนังสือเล่มเดียวกันได้โดยมีที่คั่นหนังสือคนละอัน ไม่ชนกัน

🎯 Beyond: จุดที่ชาวบ้านไม่ค่อยรู้

เพราะ consumer เป็นคนควบคุม offset เอง สิ่งที่ตามมาคือ Kafka รองรับ pattern ที่ message queue ทั่วไปทำได้ยากมาก: "replay" ข้อมูลเก่าได้ตามต้องการ แค่สั่ง seek() offset กลับไปที่ตำแหน่ง เก่า (หรือ reset consumer group offset ด้วย kafka-consumer-groups --reset-offsets) ก็อ่าน ข้อมูลเดิมซ้ำได้ทันที — เป็นประโยชน์มากตอน deploy consumer logic ใหม่ที่ต้องการประมวลผลข้อมูล เก่าใหม่ทั้งหมด (backfill) หรือตอน debug ปัญหาที่ต้องดู sequence การประมวลผลซ้ำ ความสามารถนี้ มาจากดีไซน์พื้นฐานที่ว่า message ใน Kafka ไม่ถูกลบทิ้งทันทีหลังถูกอ่าน (ต่างจาก queue ทั่วไปที่ message หายไปหลังถูก consume) — message จะอยู่ต่อจนกว่าจะหมดอายุตาม retention policy เท่านั้น ไม่ว่าจะมี consumer อ่านไปแล้วกี่ตัวก็ตาม

Replication Factor — ความทนทานต่อความล้มเหลว​

Replication factor คือจำนวนสำเนาของแต่ละ partition ที่กระจายเก็บไว้คนละ broker (เช่น replication.factor=3 หมายถึงแต่ละ partition มี 3 สำเนา) หนึ่งในนั้นเป็น leader (รับ read/write ทั้งหมด) ที่เหลือเป็น follower (คอย sync ข้อมูลจาก leader เผื่อ leader ล่ม)

🧠 จำง่ายๆ

"Replication factor = จำนวนสำเนาเอกสารสำคัญที่เก็บไว้คนละตู้เซฟ" — ตู้เซฟหลัก (leader) พังไป ยังมีสำเนาในตู้อื่น (follower) ที่พร้อมเลื่อนขึ้นมาเป็นตู้หลักแทนได้ทันที ยิ่งมีสำเนาเยอะยิ่ง ทนทาน แต่ก็ยิ่งเปลือง storage และ network bandwidth สำหรับ sync มากขึ้นตามไปด้วย

🎯 Beyond: จุดที่ชาวบ้านไม่ค่อยรู้

Replication factor สูงไม่ได้แปลว่าข้อมูลปลอดภัย 100% เสมอไป — ต้องดูคู่กับแนวคิด ISR (In-Sync Replicas) ซึ่งเป็น subset ของ replica ที่ "sync ทันกับ leader จริงๆ" เท่านั้น (ไม่ใช่ทุก replica ที่ assign ไว้) follower ที่ sync ช้าเกินไป (เกิน replica.lag.time.max.ms) จะถูกเตะออกจาก ISR ชั่วคราว — ถ้า producer ตั้งค่า acks=all (รอ confirm จากทุก ISR ก่อนถือว่าเขียนสำเร็จ) และ ISR เหลือ broker เดียว (leader เดี่ยวๆ เพราะ follower ตามไม่ทันหมด) การันตีความทนทานจะลดลงเหลือเท่ากับไม่มี replication เลย แม้ replication factor จะตั้งไว้สูงแค่ไหนก็ตาม — รายละเอียดเรื่อง ISR และ acks เจาะลึกใน Reliability & Ordering

English Summary

A Topic is a logical name split into ordered, append-only Partitions — the unit of parallelism. Partitions are physically stored as rotating segment files (not one giant file), which makes retention-based deletion cheap. Brokers form a Cluster, each holding a subset of partitions; Kafka 2.8+ can run without ZooKeeper via KRaft, storing cluster metadata through its own Raft consensus instead. Offsets are tracked by the consumer, not the broker (stored in __consumer_offsets) — this is why Kafka supports replaying old data via seek(), since messages aren't deleted on read, only on retention expiry. Replication Factor sets how many copies of each partition exist across brokers (one leader, rest followers); durability actually depends on the In-Sync Replica (ISR) set, not the raw replication factor — a lagging follower drops out of ISR, and acks=all only guarantees as much durability as the current ISR size.