วิธีปรับขนาดผู้ใช้ตั้งแต่ 1 ถึง 100 คน

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

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

ลองกรองข้อมูลและเขียนสูตรพื้นฐานดู เราจะขยายไซต์แบ่งปันรูปภาพใหม่ของเรา Graminsta ทีละขั้นตอนจากผู้ใช้ 1 คนเป็น 100 คน

มาจดบันทึกว่าต้องดำเนินการอะไรบ้างเมื่อผู้ชมเพิ่มขึ้นเป็น 10, 100, 1000, 10 และ 000 คน

ผู้ใช้ 1 คน: 1 เครื่อง

เกือบทุกแอปพลิเคชัน ไม่ว่าจะเป็นเว็บไซต์หรือแอปพลิเคชันบนมือถือ มีองค์ประกอบหลักสามประการ:

  • API
  • ฐานข้อมูล
  • ลูกค้า (แอปพลิเคชันมือถือหรือเว็บไซต์)

ฐานข้อมูลจัดเก็บข้อมูลถาวร API ตอบสนองคำขอไปยังและรอบๆ ข้อมูลนี้ ลูกค้าส่งข้อมูลไปยังผู้ใช้

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

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

ตามทฤษฎีแล้ว เราสามารถปรับใช้ในระบบคลาวด์บน DigitalOcean Droplet หรือ AWS EC2 instance เดียวได้ ดังที่แสดงด้านล่าง:
วิธีปรับขนาดผู้ใช้ตั้งแต่ 1 ถึง 100 คน
ดังที่กล่าวไปแล้ว หากมีผู้ใช้มากกว่าหนึ่งรายบนไซต์ การอุทิศเลเยอร์ฐานข้อมูลมักจะสมเหตุสมผลเสมอไป

ผู้ใช้ 10 ราย: ย้ายฐานข้อมูลไปยังระดับที่แยกจากกัน

การแยกฐานข้อมูลออกเป็นบริการที่ได้รับการจัดการ เช่น Amazon RDS หรือ Digital Ocean Managed Database จะให้บริการเราอย่างดีเป็นเวลานาน มีราคาแพงกว่าการโฮสต์ด้วยตนเองบนเครื่องเดียวหรือ EC2 instance เล็กน้อย แต่ด้วยบริการเหล่านี้ คุณจะได้รับส่วนขยายที่มีประโยชน์มากมายซึ่งจะมีประโยชน์ในอนาคต เช่น การสำรองข้อมูลหลายภูมิภาค การจำลองการอ่าน อัตโนมัติ การสำรองข้อมูลและอื่น ๆ

นี่คือลักษณะของระบบตอนนี้:
วิธีปรับขนาดผู้ใช้ตั้งแต่ 1 ถึง 100 คน

ผู้ใช้ 100 ราย: ย้ายไคลเอนต์ไปยังระดับที่แยกจากกัน

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

นี่คือเหตุผลที่ฉันชอบคิดว่าไคลเอนต์แยกจาก API สิ่งนี้ทำให้ง่ายมากที่จะคิดเกี่ยวกับการพัฒนาสำหรับหลายแพลตฟอร์ม: เว็บ, เว็บบนมือถือ, iOS, Android, แอปพลิเคชันเดสก์ท็อป, บริการของบุคคลที่สาม ฯลฯ ทั้งหมดเป็นเพียงลูกค้าที่ใช้ API เดียวกัน

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

นี่คือลักษณะของระบบดังกล่าว:

วิธีปรับขนาดผู้ใช้ตั้งแต่ 1 ถึง 100 คน

ผู้ใช้ 1000 ราย: เพิ่มโหลดบาลานเซอร์

สิ่งต่าง ๆ กำลังมองหา ผู้ใช้ Graminsta กำลังอัปโหลดรูปภาพมากขึ้นเรื่อยๆ จำนวนการลงทะเบียนก็เพิ่มขึ้นเช่นกัน เซิร์ฟเวอร์ API เดี่ยวของเรากำลังประสบปัญหาในการติดตามการรับส่งข้อมูลทั้งหมด ต้องการเหล็กเพิ่ม!

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

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

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

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

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

วิธีปรับขนาดผู้ใช้ตั้งแต่ 1 ถึง 100 คน

บันทึก. ขณะนี้ระบบของเราคล้ายกันมากกับสิ่งที่บริษัท PaaS เช่น Heroku หรือ Elastic Beanstalk บน AWS เสนอให้ทันที (ซึ่งเป็นเหตุผลว่าทำไมจึงได้รับความนิยมมาก) Heroku วางฐานข้อมูลบนโฮสต์ที่แยกต่างหาก จัดการโหลดบาลานเซอร์ที่ปรับขนาดอัตโนมัติ และอนุญาตให้คุณโฮสต์เว็บไคลเอ็นต์แยกต่างหากจาก API นี่เป็นเหตุผลที่ดีในการใช้ Heroku สำหรับโครงการระยะเริ่มต้นหรือสตาร์ทอัพ คุณจะได้รับบริการพื้นฐานทั้งหมดทันที

ผู้ใช้ 10 ราย: CDN

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

ในขั้นตอนนี้ คุณต้องใช้บริการคลาวด์เพื่อจัดเก็บเนื้อหาคงที่ เช่น รูปภาพ วิดีโอ และอื่นๆ อีกมากมาย (AWS S3 หรือ Digital Ocean Spaces) โดยทั่วไป API ของเราควรหลีกเลี่ยงการจัดการสิ่งต่างๆ เช่น การแสดงรูปภาพและการอัพโหลดรูปภาพไปยังเซิร์ฟเวอร์

ข้อดีอีกประการหนึ่งของโฮสติ้งบนคลาวด์ก็คือ CDN (AWS เรียกส่วนเสริมนี้ว่า Cloudfront แต่ผู้ให้บริการพื้นที่เก็บข้อมูลบนคลาวด์หลายรายเสนอบริการดังกล่าวทันที) CDN จะแคชรูปภาพของเราในศูนย์ข้อมูลต่างๆ ทั่วโลกโดยอัตโนมัติ

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

วิธีปรับขนาดผู้ใช้ตั้งแต่ 1 ถึง 100 คน

ผู้ใช้ 100 ราย: ปรับขนาดชั้นข้อมูล

CDN ช่วยได้มาก: ปริมาณการใช้ข้อมูลเพิ่มขึ้นด้วยความเร็วสูงสุด Mavid Mobrick บล็อกเกอร์วิดีโอชื่อดังเพิ่งลงทะเบียนกับเราและโพสต์ "เรื่องราว" ของเขาตามที่พวกเขาพูด ต้องขอบคุณโหลดบาลานเซอร์ที่ทำให้การใช้งาน CPU และหน่วยความจำบนเซิร์ฟเวอร์ API อยู่ในระดับต่ำ (อินสแตนซ์ API สิบรายการทำงานอยู่) แต่เราเริ่มได้รับการหมดเวลาจำนวนมากสำหรับคำขอ... ความล่าช้าเหล่านี้มาจากไหน

เมื่อเจาะลึกตัวชี้วัดเล็กน้อย เราจะเห็นว่า CPU บนเซิร์ฟเวอร์ฐานข้อมูลมีการโหลด 80-90% เรามาถึงขีดจำกัดแล้ว

การปรับขนาดชั้นข้อมูลอาจเป็นส่วนที่ยากที่สุดของสมการ เซิร์ฟเวอร์ API ให้บริการคำขอแบบไม่เก็บสถานะ ดังนั้นเราจึงเพิ่มอินสแตนซ์ API เพิ่มเติม จมูก ส่วนใหญ่ ฐานข้อมูลไม่สามารถทำเช่นนี้ได้ เราจะพูดถึงระบบการจัดการฐานข้อมูลเชิงสัมพันธ์ยอดนิยม (PostgreSQL, MySQL ฯลฯ)

เก็บเอาไว้

วิธีที่ง่ายที่สุดวิธีหนึ่งในการเพิ่มประสิทธิภาพฐานข้อมูลของเราคือการแนะนำส่วนประกอบใหม่: เลเยอร์แคช วิธีการแคชที่พบบ่อยที่สุดคือการจัดเก็บบันทึกคีย์-ค่าในหน่วยความจำ เช่น Redis หรือ Memcached คลาวด์ส่วนใหญ่มีบริการเวอร์ชันที่ได้รับการจัดการเหล่านี้: Elasticache บน AWS และ Memorystore บน Google Cloud

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

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

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

ข้อดีอีกประการหนึ่งของบริการแคชส่วนใหญ่ก็คือ ปรับขนาดได้ง่ายกว่าเซิร์ฟเวอร์ฐานข้อมูล Redis มีโหมด Redis Cluster ในตัว คล้ายกับโหลดบาลานเซอร์1ช่วยให้คุณสามารถกระจายแคช Redis ของคุณไปยังเครื่องหลายเครื่อง (ไปยังเซิร์ฟเวอร์นับพันหากจำเป็น)

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

อ่านแบบจำลอง

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

นี่คือระบบของเราตอนนี้:

วิธีปรับขนาดผู้ใช้ตั้งแต่ 1 ถึง 100 คน

ขั้นตอนถัดไป

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

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

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

แหล่งที่มา

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

เชิงอรรถ

  1. แม้ว่าจะคล้ายกันในแง่ของการกระจายโหลดในหลายอินสแตนซ์ แต่การใช้งานพื้นฐานของคลัสเตอร์ Redis นั้นแตกต่างจากโหลดบาลานเซอร์อย่างมาก [กลับ]

วิธีปรับขนาดผู้ใช้ตั้งแต่ 1 ถึง 100 คน

ที่มา: will.com

เพิ่มความคิดเห็น