การสาธิตการออกแบบระบบ

ผู้ชม

บทความนี้เป็นบทความถัดไปในชุดของฉันเกี่ยวกับวิธีที่ฉันจะออกแบบแอปพลิเคชันยอดนิยม ขอแนะนำ (แม้ว่าจะไม่จำเป็นทั้งหมด) ให้อ่านโพสต์ก่อนหน้านี้ที่ฉันรวบรวมไว้อย่างเป็นประโยชน์ในรายการ "ที่นี่"

เราคาดว่าจะมีความคุ้นเคยขั้นพื้นฐานเกี่ยวกับหลักการสถาปัตยกรรมและ AWS แต่หวังว่าวิศวกรส่วนใหญ่เข้าถึงโพสต์นี้ได้

การโต้แย้ง

ขั้นแรก มาดูคำชี้แจงปัญหาของเรากัน

ระบบการออกแบบ

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

  1. เราควรจะสามารถอัปโหลดวิดีโอได้
  2. เราควรจะสามารถดูวิดีโอได้
  3. เราควรจะสามารถค้นหาตามชื่อวิดีโอได้

เราจะเพิกเฉยต่อความจริงที่ว่าคุณไม่สามารถอัปโหลดวิดีโอไปยัง Netflix ได้ เว้นแต่คุณจะเป็นสตูดิโอผลิตภาพ ลองจินตนาการว่าคุณคือ Quentin Tarantino

วิธีการ

เรามีแนวทางมาตรฐานในการออกแบบระบบ ซึ่งมีการอธิบายอย่างละเอียดในบทความ ที่นี่ อย่างไรก็ตาม มีขั้นตอนโดยสรุปดังนี้:

  1. การชี้แจงข้อกำหนด: ตรวจสอบให้แน่ใจว่าเรามีข้อมูลทั้งหมดก่อนที่จะเริ่มต้น ซึ่งอาจรวมถึงจำนวนคำขอหรือผู้ใช้ที่เราคาดหวัง
  2. การประมาณค่าด้านหลังซองจดหมาย:ทำการคำนวณอย่างรวดเร็วเพื่อประเมินประสิทธิภาพของระบบที่จำเป็น ตัวอย่างเช่น เราต้องการพื้นที่เก็บข้อมูลหรือแบนด์วิธเท่าใด
  3. การออกแบบอินเทอร์เฟซระบบ:ระบบของเราจะมีลักษณะอย่างไรเมื่อมองจากภายนอก ผู้คนจะมีปฏิสัมพันธ์กับระบบอย่างไร โดยทั่วไปนี่คือสัญญา API
  4. การออกแบบโมเดลข้อมูล:ข้อมูลของเราจะมีลักษณะอย่างไรเมื่อเราจัดเก็บ ณ จุดนี้ เราอาจกำลังคิดถึงโมเดลเชิงสัมพันธ์และโมเดลที่ไม่เชิงสัมพันธ์
  5. การออกแบบเชิงตรรกะ:ประกอบเข้าด้วยกันในระบบที่หยาบกร้าน! ณ จุดนี้ ฉันกำลังคิดในระดับ 'ฉันจะอธิบายแนวคิดของฉันให้คนที่ไม่รู้เกี่ยวกับเทคโนโลยีได้อย่างไร'
  6. การออกแบบทางกายภาพ:ตอนนี้เราเริ่มกังวลเกี่ยวกับเซิร์ฟเวอร์ ภาษาการเขียนโปรแกรม และรายละเอียดการใช้งาน เราสามารถวางสิ่งเหล่านี้ทับการออกแบบเชิงตรรกะได้
  7. ระบุและแก้ไขจุดคอขวด:ในขั้นตอนนี้ เราจะมีระบบที่ใช้งานได้! ตอนนี้เราปรับปรุงการออกแบบ

ด้วยที่กล่าวว่ามาติดกันเถอะ!

การชี้แจงข้อกำหนด

ลองคิดถึงคำถามเบื้องต้นบ้าง ในตอนแรก ฉันสงสัยว่าขนาดสูงสุดและขนาดเฉลี่ยของวิดีโอคือเท่าใด จากนั้น ฉันจะคิดถึงจำนวนผู้ใช้และอัตราส่วนการอ่าน/เขียน/การค้นหา

นอกจากนี้ ไคลเอนต์ใช้อุปกรณ์/ความเร็วการเชื่อมต่อใด เราอาจจำเป็นต้องปรับรูปแบบและขนาดไฟล์ให้เหมาะสมตามสิ่งนี้

การประมาณค่าด้านหลังของซองจดหมาย

สมมติว่าเรามีผู้ใช้ 100 ล้านคน (จริงๆ แล้วน่าจะมากกว่านั้น!) อ่านและเขียนในอัตราส่วนรายวัน 100:1 ขนาดไฟล์โดยเฉลี่ยคือ 1GB สำหรับ HD และขนาดไฟล์สูงสุดคือ 50GB (ไม่สำคัญว่าจะแม่นยำแค่ไหน)

ซึ่งหมายความว่าเราจะมีความจุคร่าวๆ 100,000,000 * 1GB = 100PB/d สำหรับการอัปโหลดเท่านั้น! เราสามารถทำงานได้ในคำขอต่อวินาทีตามความยาววิดีโอโดยเฉลี่ย แต่ก็ปลอดภัยที่จะบอกว่าเรากำลังจัดการกับข้อมูลจำนวนมาก!

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

การออกแบบส่วนต่อประสานระบบ

เมื่อได้เรียนรู้เพิ่มเติมเล็กน้อยเกี่ยวกับระบบของเราแล้ว เราก็สามารถตัดสินใจได้ว่าต้องการโต้ตอบกับระบบอย่างไร การโต้ตอบมีสามประเด็นหลัก

  1. อัปโหลดวิดีโอ
  2. ดาวน์โหลดวิดีโอ
  3. ค้นหา

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

สิ่งที่ฉันอยากจะแนะนำให้ทำคือการสร้างแบบฟอร์มเริ่มต้นเพื่อส่งข้อมูลเมตาที่เกี่ยวข้องกับไฟล์ (ชื่อ แท็ก สิ่งใดก็ตามที่ไม่ใช่ตัววิดีโอ) ซึ่งจะส่งคืน GGUID ที่เกี่ยวข้องกับไฟล์

จากนั้นเราสามารถใช้ JavaScript File และ Blob APIs เพื่อ ตัดไฟล์วิดีโอและส่งคำขอบางส่วน โดยมีส่วนหัว Content-Range แสดงถึงช่วงไบต์ที่คำขอนี้เป็นตัวแทน ประเภทเนื้อหาของเราจะเป็น application/octet-stream และเซิร์ฟเวอร์มีหน้าที่รับผิดชอบในการประกอบชิ้นส่วนต่างๆ เข้าด้วยกัน

ซึ่งหมายความว่าเราจำเป็นต้องมีจุดสิ้นสุดสำหรับการสร้างไฟล์ POST ที่จุดสิ้นสุด /file ซึ่งสร้างออบเจ็กต์ไฟล์ใหม่ที่มีข้อมูลเมตา และจุดสิ้นสุดอีกจุดหนึ่งที่ POST file/{id}/chunk ซึ่งอนุญาตให้ผู้ใช้สามารถโพสต์ส่วนข้อมูลได้

สิ่งที่เราคิดได้อีกอย่างก็คือการแฮชไฟล์บนไคลเอนต์ จากนั้นเปรียบเทียบแฮชหลังจากที่เราประกอบไฟล์บนเซิร์ฟเวอร์อีกครั้ง เพื่อให้แน่ใจว่าตรงกัน

การดาวน์โหลดสามารถใช้ "คำขอช่วง HTTP" ได้ ซึ่งช่วยให้เราสามารถขอบางส่วนของวิดีโอได้ในแต่ละครั้ง (ส่งคืน 206) ซึ่งหมายความว่าเราสามารถขอส่วนวิดีโอแบบไดนามิกตามที่เราต้องการ การใช้ GET file/{id}/chunk กับส่วนหัวของ Content-Range อาจเป็นวิธีแก้ปัญหาหนึ่ง

โชคดีที่การค้นหานั้นง่ายกว่าเล็กน้อย เราสามารถ GET ถึง /search?title=<search title> และรับรหัสตอบกลับตามปกติ

การออกแบบตัวแบบข้อมูล

ตอนนี้เรามีไอเดียแล้วว่าเราจะโต้ตอบกับระบบของเราอย่างไร ลองคิดถึงประเภทของข้อมูลที่เราต้องการจัดเก็บกัน บางส่วนจะขึ้นอยู่กับไบต์ของวิดีโอ และบางส่วนจะขึ้นอยู่กับข้อมูลเมตา

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

ไฟล์

id               BIGINT    PRIMARY KEY 
title            VARCHAR

ตอนนี้เราต้องคิดถึงไฟล์ชิ้นของเรา จำไว้ว่าเราจำเป็นต้องให้บริการกับเครือข่ายและอุปกรณ์มากมาย! ซึ่งหมายความว่าเราจะต้องการจัดเก็บชิ้นส่วนในคุณภาพและรูปแบบไฟล์ที่แตกต่างกันมากมาย ด้วยการมาถึงของพื้นที่จัดเก็บอ็อบเจ็กต์ เช่น AWS S3 เราสามารถอ้างอิงได้ว่าไฟล์ของเราอยู่ที่ใดใน S3

ก้อน

id           BIGINT    PRIMARY KEY 
file_id      BIGINT    FOREIGN KEY REFERENCES file(id)
format       VARCHAR
quality      BIGINT
order        BIGINT    
location     VARCHAR

จากข้อมูลข้างต้น เราสามารถระบุได้ว่าไฟล์ชิ้นใดเป็นของไฟล์ รูปแบบของชิ้นข้อมูล ขนาดของชิ้นข้อมูล และบิตของไฟล์ที่ชิ้นส่วนนั้นเป็นตัวแทน

นี่เป็นแกนหลักของโมเดลข้อมูลของเรา มาดูการออกแบบเชิงตรรกะกันดีกว่า!

การออกแบบเชิงตรรกะ

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

บริการแยกไฟล์นี้มีหน้าที่รวบรวมไฟล์จากไคลเอนต์ให้เป็นไฟล์เดียว ตรวจสอบ และแยกไฟล์ออกเป็นไฟล์ต่าง ๆ ที่เครื่องเล่นสื่อใช้งานได้มากขึ้น

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

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

  • การแปลงรหัส: การสร้างไฟล์ในขนาดต่างๆ
  • การเข้ารหัส: การเข้ารหัสไฟล์อีกครั้งในรูปแบบอื่น

การเข้ารหัสครอบคลุมถึงการแปลงรหัส ซึ่งเป็นสาเหตุที่เราใช้คำนี้ในที่นี้

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

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

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

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

การออกแบบทางกายภาพ

ตอนนี้เราได้กล่าวถึงแนวคิดคร่าว ๆ เกี่ยวกับวิธีการรวมแพลตฟอร์มของเราเข้าด้วยกันแล้ว มาทำให้เนื้อหาเป็นสิ่งที่จับต้องได้ในโลกแห่งความเป็นจริงกัน

แม้ว่าในขณะที่ฉันกำลังเขียนอยู่ ฉันก็ยังเห็นปัญหาหลายประการเกี่ยวกับการออกแบบนี้ อย่างไรก็ตาม มาสำรวจกันดีกว่าและเราสามารถปรับแต่งมันได้ในส่วนถัดไป

ในตอนแรก บริการแบบคงที่ทั้งหมดของเราใช้ AWS ECS มีข้อโต้แย้งว่าเราอาจใช้งานแบบไร้เซิร์ฟเวอร์โดยสิ้นเชิงได้ แต่ความรู้สึกของฉันคือเราไม่ต้องการกังวลเกี่ยวกับเวลาเริ่มต้นที่เย็น เกตเวย์ของเราคือ เกตเวย์ AWS API และคิวของเราใช้ SQS

เราจัดเก็บชิ้นส่วนของเราไว้ใน S3 และใช้ AWS Elemental MediaConvert สำหรับการเข้ารหัสของเรา เครื่องมือค้นหาคือ "Amazon OpenSearch"

การระบุและการแก้ไขคอขวด

เราได้กล่าวถึงการปรับปรุงประสิทธิภาพบางอย่างที่เราสามารถทำได้ ในตอนแรก ฉันกำลังมุ่งเน้นไปที่ปริมาณข้อมูลที่เราได้รับ เราจำเป็นต้องมีระบบที่ยืดหยุ่นซึ่งสามารถจัดการกับข้อมูลจำนวนมากได้แบบเรียลไทม์ ฟังดูเหมือนเป็นงานสตรีมมิ่ง

จากแผนภาพ คุณจะเห็นว่าตอนนี้ API Gateway ของเราเขียนไปยัง "Kinesis stream" ซึ่งจะพุชไปที่ "AWS EMR" (อาจเปิด Spark Streaming ไว้) เพื่อประมวลผลและจัดกลุ่มไฟล์ของเราใหม่

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

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

ส่วนสุดท้ายของการปรับให้เหมาะสมคือการเพิ่ม CDN เนื่องจากเราจะมีผู้ใช้ทั่วโลก เราจึงไม่ต้องการให้ทุกคนพยายามเข้าถึงวิดีโอของตนจากเซิร์ฟเวอร์ในสหราชอาณาจักร เป็นเรื่องสมเหตุสมผลที่จะพยายามเผยแพร่เนื้อหาของเราให้ใกล้กับจุดที่พวกเขาอยู่มากขึ้น โปรดทราบว่า Netflix มีวิธีแก้ไขปัญหาของตัวเองที่เรียกว่า "Open Connect" ซึ่งคุ้มค่าแก่การดู!

บทสรุป

โดยสรุป เราได้กล่าวถึงวิธีการออกแบบแพลตฟอร์มสไตล์ YouTube หรือ Netflix แล้ว ควรตระหนักว่ามี "เครื่องมือจำนวนหนึ่งที่ Netflix พัฒนาขึ้นมาโดยเฉพาะ" สำหรับปัญหานี้

ตัวอย่างบางส่วนได้แก่:

  • Zuul: เกตเวย์แอปพลิเคชัน
  • Hystrix (เลิกใช้แล้ว): เบรกเกอร์
  • ยูเรก้า: การค้นพบบริการ
  • ปลอมตัว: ตัวประสานไคลเอนต์ HTTP

ตรวจสอบพวกเขาออก!