การสัมภาษณ์การออกแบบระบบ: ออกแบบ Twitter

"ออกแบบ Twitter" เป็นปัญหาคลาสสิกของการสร้างฟีด มันดูเหมือนง่าย — โพสต์ทวีต อ่านไทม์ไลน์ — แต่ส่วนที่น่าสนใจคือการสร้างไทม์ไลน์หลักของผู้ใช้แต่ละคนในระดับขนาดใหญ่ ซึ่งคำตอบที่ถูกต้องคือกลยุทธ์ fan-out แบบไฮบริด ผู้สัมภาษณ์ต้องการเห็นคุณค้นพบว่าทั้งสองวิธีที่ตรงไปตรงมาต่างล้มเหลว และให้เหตุผลจนไปถึงส่วนผสมนั้น

ดำเนินการอย่างมีเจตนา: ชี้แจงความต้องการ ประมาณอัตราส่วนการอ่าน/เขียน ออกแบบการจัดเก็บทวีต จากนั้นออกแบบไทม์ไลน์ — เปรียบเทียบ fan-out-on-write กับ fan-out-on-read และมาถึงแบบไฮบริดที่จัดการปัญหาคนดัง คู่มือด้านล่างนี้ทำตามเส้นทางนั้น

1. ชี้แจงความต้องการ

จำกัดขอบเขตให้อยู่ที่ปัญหาฟีดหลัก ผู้ใช้โพสต์ทวีต ติดตามผู้อื่น และอ่านไทม์ไลน์หลักที่รวมทวีตจากทุกคนที่พวกเขาติดตาม โดยเรียงจากใหม่ที่สุดก่อน

  • เชิงฟังก์ชัน: โพสต์ทวีต ติดตาม/เลิกติดตาม ไทม์ไลน์หลัก (คนที่คุณติดตาม) ไทม์ไลน์ผู้ใช้ (ผู้เขียนคนเดียว) การค้นหาพื้นฐานอยู่นอกขอบเขตเว้นแต่มีการขอ
  • เชิงไม่ใช่ฟังก์ชัน: เน้นการอ่านอย่างมาก การอ่านไทม์ไลน์ความหน่วงต่ำ ความพร้อมใช้งานสูง ความสอดคล้องแบบ eventual สำหรับไทม์ไลน์เป็นที่ยอมรับได้
  • ต้องชี้แจง: มีเดีย การตอบกลับ/เธรด และการจัดอันดับ — ยอมรับสิ่งเหล่านี้ และจำกัดขอบเขตให้เป็นฟีดตามลำดับเวลาสำหรับรอบนี้

2. ประมาณสเกลและอัตราส่วนการอ่าน/เขียน

อัตราส่วนนี้ขับเคลื่อนการออกแบบทั้งหมด การอ่านมีจำนวนมากกว่าการเขียนอย่างมาก — ผู้ใช้เลื่อนไทม์ไลน์บ่อยกว่าการโพสต์มาก เมื่อมีผู้ใช้หลายร้อยล้านคน ระบบต้องทำให้การอ่านไทม์ไลน์มีราคาถูก แม้ว่าจะทำให้การเขียนมีราคาแพงขึ้น การสังเกตเพียงอย่างเดียวนี้ชี้ไปที่การคำนวณไทม์ไลน์ไว้ล่วงหน้า

3. การจัดเก็บทวีต

ทวีตเองเป็นข้อมูลที่เรียบง่าย เน้นการเพิ่มข้อมูล (append) เก็บไว้ในที่เก็บข้อมูลที่แบ่งพาร์ติชันตามแนวนอน โดยใช้ ID ทวีตเป็นคีย์ (พร้อม ID ที่เรียงตามเวลาได้ เช่น Snowflake ID เพื่อให้ลำดับฝังอยู่ในตัว) ที่เก็บข้อมูลกราฟโซเชียลแยกต่างหากจะเก็บความสัมพันธ์ของผู้ติดตาม/การติดตาม

  • ทวีต: ที่เก็บข้อมูลแบบกระจาย แบ่งพาร์ติชันตาม ID ทวีต; ID ที่เรียงตามเวลาได้ให้การจัดเรียงตามลำดับเวลาที่มีต้นทุนต่ำ
  • กราฟโซเชียล: ใครติดตามใคร ถูกปรับให้เหมาะกับ 'รับผู้ติดตามทั้งหมดของ X' และ 'รับทุกคนที่ X ติดตาม'
  • แคช (Redis) เก็บข้อมูลที่ร้อน — ทวีตล่าสุดและไทม์ไลน์ที่คำนวณไว้ล่วงหน้า

4. การสร้างไทม์ไลน์: fan-out เมื่อเขียน เทียบกับเมื่ออ่าน

นี่คือหัวใจของปัญหา fan-out-on-write (push) จะแทรกทวีตใหม่แต่ละอันเข้าไปในรายการไทม์ไลน์ที่คำนวณไว้ล่วงหน้าของผู้ติดตามแต่ละคนในขณะที่โพสต์ — การอ่านไทม์ไลน์กลายเป็นการค้นหาแคชที่ราคาถูก แต่โพสต์จากคนที่มีผู้ติดตามหลายล้านคนจะกระตุ้นการเขียนหลายล้านครั้ง fan-out-on-read (pull) จะสร้างไทม์ไลน์ในขณะที่อ่าน โดยการรวมทวีตล่าสุดจากทุกคนที่คุณติดตาม — การเขียนราคาถูก แต่การอ่านช้าและมีราคาแพงสำหรับผู้ใช้ที่ติดตามบัญชีจำนวนมาก

  • fan-out-on-write: การอ่านเร็ว การเขียนแพง เหมาะมากสำหรับผู้ใช้ทั่วไป
  • fan-out-on-read: การเขียนถูก การอ่านแพง จำเป็นสำหรับบัญชีที่มีจำนวนผู้ติดตามมหาศาล

5. ปัญหาคนดังและแบบไฮบริด

ไม่มีวิธีล้วนๆ แบบใดชนะ ดังนั้นให้รวมทั้งสองเข้าด้วยกัน ใช้ fan-out-on-write สำหรับผู้ใช้ส่วนใหญ่อย่างมาก แต่สำหรับบัญชี 'คนดัง' ที่มีจำนวนผู้ติดตามมากเป็นพิเศษ อย่าทำ fan-out ทวีตของพวกเขาตอนเขียน ให้ทำแทนในขณะที่อ่าน โดยรวมไทม์ไลน์ที่คำนวณไว้ล่วงหน้าของผู้ติดตามกับการดึงข้อมูลแบบสดจากคนดังจำนวนน้อยที่พวกเขาติดตาม วิธีนี้จำกัดการขยายตัวของการเขียนในขณะที่ยังคงให้การอ่านรวดเร็ว — นี่คือคำตอบที่ผู้สัมภาษณ์รับฟัง

6. ข้อแลกเปลี่ยนที่ควรพูดออกมา

ปิดท้ายด้วยความตึง: การขยายตัวของการเขียนเทียบกับความหน่วงของการอ่าน (การตัดสินใจ fan-out ทั้งหมด) ต้นทุนการจัดเก็บไทม์ไลน์ที่คำนวณไว้ล่วงหน้าเทียบกับการคำนวณใหม่ และความสอดคล้อง — ความล่าช้าสองสามวินาทีก่อนที่ทวีตจะปรากฏในไทม์ไลน์ของผู้ติดตามเป็นที่ยอมรับได้ ดังนั้นความสอดคล้องแบบ eventual จึงทำให้คุณขยายขนาดได้ การระบุเกณฑ์ของแบบไฮบริดอย่างชัดเจน (วิธีที่คุณจำแนก 'คนดัง') แสดงถึงการตัดสินใจระดับซีเนียร์

ฝึกการออกแบบระบบของ Twitter พร้อมความช่วยเหลือแบบเรียลไทม์

ผู้ช่วยสัมภาษณ์การออกแบบระบบของ Nativelyสามารถช่วยให้คุณมีโครงสร้างที่ชัดเจนระหว่างรอบสัมภาษณ์แบบสด — เสนอมิติต่อไปที่ควรครอบคลุมและแสดงข้อแลกเปลี่ยนแบบเรียลไทม์ ทั้งหมดบนอุปกรณ์ของคุณเอง