System Design: 5 สิ่งที่ช่วยอธิบายว่าทำไม Kafka ถึงเร็ว
ทำไม Kafka ถึงทำงานได้เร็ว? ที่ใครหลายๆคนบอกว่ามัน high-throughput, highly distributed, fault-tolerant low-latency ในการส่ง และ รับ message แท้จริงแล้วอะไรที่ทำให้มันเร็ว มีแนวคิดอะไรในการออกแบบระบบ และคำว่าเร็วนั้น เค้าใช้เทคนิคอะไรกัน
ในฐานะคนทำซอฟท์แวร์ เป็นคำถามที่เราสงสัยมานานแล้ว บทความนี้จะเล่าในมุมมอง software architecture landscape เจาะลึก 5 สิ่งที่ทำให้เห็นว่าแนวคิดเบื้องหลังวิธีการออกแบบระบบเป็นอย่างไรกัน
Sequential I/O
ต้องย้อนไปทำความเข้าใจกันก่อนว่า Access Patterns ของ Disk นั้นมี 2 แบบ
- Random = การอ่านและเขียน เป็นการสุ่ม
- Sequential = อ่านและเขียนตามลำดับ
จากภาพเราจะเห็นได้ว่า random access ใช้ลักษณะการสุ่มการเข้าถึง data ที่อยู่ในแต่ละ offset หรือ localtion ใน disk ทำให้มี overhead เกิดขึ้นในทุกๆครั้งที่มีการ random
Seek Time
การค้นหาข้อมูล เรารู้ดีว่า Disk มันช้ากว่า Ram แต่เพื่อให้การค้นหาข้อมูลดีขึ้น ดังนั้น Kafka จึงเลือกใช้เทคนิคการเข้าถึงข้อมูลด้วยรูปแบบ Sequential access เพื่อหลีกเลี่ยง overhead ที่เกิดขึ้นจากการใช้ Random access
ลองจินตนาการในชีวิตประจำวัน ถ้าเรามีของที่ต้องการหากระจัดกระจาย อยู่คนละห้อง เราต้องเสียเวลาเดินหา แต่ถ้าเราจัดของให้อยู่ใกล้กัน เรียงกันอย่างสวยงามมันดูดีกว่าใช่ไหมหล่ะ?
Don’t use trees
Kafka เลือกไม่ใช้ tree เหมือนกับ database ในท้องตลาดที่เราคุ้นเคย เช่น MongoDB ใช้ B-Tree หรือ Cassandra ที่ใช้ LSM Tree
ทำไมหล่ะ?
ก็เพราะว่า เวลาในการค้นหา หรือ time-complexity O(log N) ซึ่งมีเวลาแฝง seek time ในการค้นหาและรวมข้อมูล
ดังนั้นวิธีการแก้ไขปัญหาจุดนี้ Kafka เลยเลือกใช้ append-only log
Append-Only Log Data Structure
Did you know?
Kafka เก็บข้อมูลอยู่บนระบบ filesystem สำหรับงาน storage และ caching
data Structure ใช้รูปแบบ append-only log ซึ่งเป็น constant time การอ่านข้อมูล ของ จะเป็นลักษณะขยับ offset ไปลำดับถัดไป และ การเขียนข้อมูลชุดใหม่จะอยู่ตำแหน่งล่าสุด+1
Log file Thread ที่ทำหน้าที่เขียนไฟล์ มีเพียงแค่ 1 thread ทำหน้าที่เขียนข้อมูลต่อท้าย EOF เรื่อยๆเมื่อมีข้อมูลใหม่เข้ามา และจะไม่ทำการแก้ไขของเดิมก่อนหน้า
Zero-copy
kafka เลือกใช้ข้อมูล binary data formats เช่น protocol buffers หรือ Flat buffers ในการสื่อสารระหว่าง producer, brokers และ consumer แทนที่จะเป็น copy ข้อมูลรูปแบบ bytes ซึ่งนั่นทำให้ไม่ต้องทำการ serialize และ deserialize ตอนส่ง และ รับข้อมูล
1.1–1.3: Producer เขียนข้อมูลลง disk
การอ่านข้อมูลแบบไม่มี zero copy
2.1: โหลด data จาก disk ลง os cache
2.2: data ถูก copy จาก OS cache ไปยัง Kafka application
2.3: Kafka copy ข้อมูลเข้า socket buffer
2.4: data ถูก copy จาก socket buffer เข้าสู่ NIC (network interface card)
2.5: data ถูกส่งจาก NIC ไปสู่ consumer
การอ่านข้อมูลแบบ zero copy
3.1: โหลด data จาก disk ลง os cache
3.2: OS cache ทำการ copy data ไปลง NIC (network interface card) เลย โดยใช้ คำสั่ง sendfile()
3.3: data ถูกส่งจาก NIC ไปสู่ consumer
สรุปได้ว่า zero-copy ช่วยเมื่อข้อมูลโหลดลง OS cache จากนั้น kafka สามารถส่งข้อมูลไปยัง NIC และ ส่งต่อไปที่ consumer ได้เลย แทนที่จะส่งข้อมูลกลับไปยัง application buffer ซึ่งมันมีหลาย hops มากสำหรับการทำ copy
Compression Algorithms
Kafka มี compression algorithms สำหรับ batch messages โดยรองรับ LZ4, SNAPPY หรือ GZIP ซึ่งช่วยให้ compression ratios ได้ผลออกมาดี
สำหรับผู้อ่านบล็อกนี้ หากยังไม่รู้ว่า Kafka คืออะไร เป็นเครื่องมือประเภทไหน งานแบบไหนเหมาะที่จะเอามาใช้ สามารถอ่านบทความฉบับผู้เริ่มต้นได้ข้างล่างนี้ครับ
ขอบคุณ Neng Liangpornrattana และ Burasakorn Sabyeying สำหรับบทความครับ