Developers ต้องพบกับสถานการณ์ที่แอปพลิเคชันที่เพิ่งเปิดตัวใหม่เกิดอาการค้างทันทีที่มีผู้ใช้ไม่กี่พันคนคลิก “เริ่มใช้งาน” และความล่าช้านั้นมักไม่ใช่บั๊กในโค้ด แต่มันคือการที่ CPU และ RAM ของเซิร์ฟเวอร์กำลังแย่งชิงทรัพยากรกัน คอขวดนี้จะแสดงออกมาในรูปแบบของการโหลดหน้าเว็บที่นานขึ้น, การหมดเวลา (time-outs) หรือแม้แต่การล่มไปเลย ซึ่งส่งผลเสียต่อประสบการณ์ผู้ใช้ รายได้ และความเชื่อมั่นในแบรนด์

ทำไมเซิร์ฟเวอร์ที่ทำงานได้ดีในห้องแล็บถึงอาจหยุดชะงักเมื่อใช้งานจริง

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

  • CPU (central processing unit) – หน่วยประมวลผลกลางที่รันทุกลูป ฟังก์ชัน และการคำนวณ ให้ลองนึกภาพว่าเป็นเชฟที่สามารถเตรียมอาหารได้ในจำนวนจำกัดต่อครั้ง หากมีออเดอร์เดียว อาหารจะถูกเสิร์ฟทันที แต่ถ้ามีร้อยออเดอร์ เชฟยังคงทำงานด้วยความเร็วเท่าเดิม แต่ลูกค้าต้องรอนานขึ้น
  • RAM (random-access memory) – หน่วยความจำชั่วคราวสำหรับข้อมูลที่ CPU ต้องใช้ในขณะจัดการคำขอ เปรียบเสมือนโต๊ะที่เชฟใช้สำหรับวางวัตถุดิบของแต่ละจาน หากโต๊ะเต็ม เชฟต้องหยุดรับออเดอร์ใหม่จนกว่าจะมีพื้นที่ว่าง

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

ความเย้ายวนใจที่จะ “แค่ซื้อเครื่องที่ใหญ่กว่าเดิม”

ปฏิกิริยาแรกที่พบบ่อยคือการอัปเกรดเครื่อง ซึ่งเรียกว่า vertical scaling การเพิ่มจำนวน CPU cores หรือ RAM มากขึ้นช่วยเพิ่มขีดความสามารถได้จริง เช่น การเปลี่ยนจาก 4 cores เป็น 16 cores หรือจาก 8 GB เป็น 64 GB สามารถรองรับปริมาณทราฟฟิกที่พุ่งสูงขึ้นได้โดยไม่ต้องแก้ไขโค้ดใดๆ

อย่างไรก็ตาม vertical scaling มีข้อจำกัดที่ข้ามผ่านได้ยาก:

  • Physical limits – เมนบอร์ดทุกตัวสามารถรองรับจำนวน cores และหน่วยความจำได้ในจำนวนที่จำกัด
  • Diminishing returns – แต่ละ core หรือแต่ละ gigabyte ที่เพิ่มขึ้นจะมีราคาสูงกว่าตัวก่อนหน้า ในขณะที่ประสิทธิภาพที่ได้รับกลับลดน้อยลงเรื่อยๆ
  • Single point of failure – หากเซิร์ฟเวอร์ขนาดใหญ่เครื่องนั้นล่ม บริการทั้งหมดก็จะหายไปทันที

เนื่องจากข้อจำกัดเหล่านี้ ยักษ์ใหญ่ในอุตสาหกรรม ไม่ว่าจะเป็นแพลตฟอร์มสตรีมมิ่ง, เครื่องมือค้นหา (search engines) หรือเว็บไซต์อีคอมเมิร์ซ จึงเปลี่ยนจากการใช้เครื่องยักษ์เพียงเครื่องเดียว

ทางเลือกอื่น: การกระจายโหลดไปยังเครื่องขนาดเล็กหลายๆ เครื่อง

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

การประสานงานเครื่องจำนวนมากจำเป็นต้องมี load balancer ซึ่งเป็นซอฟต์แวร์หรือฮาร์ดแวร์ที่รับทุกคำขอที่เข้ามาและส่งต่อไปยังเซิร์ฟเวอร์ที่มีทรัพยากรว่างมากที่สุด ตัว balancer จะซ่อนความซับซ้อนจากฝั่ง client ไว้ ในมุมมองของผู้ใช้ เว็บไซต์ยังคงดูเหมือนเป็นจุดเชื่อมต่อ (endpoint) เดียว

Horizontal scaling ยังช่วยเพิ่มความยืดหยุ่น (resilience) หากโหนด (node) หนึ่งล่ม ตัว balancer จะเปลี่ยนเส้นทางทราฟฟิกไปยังโหนดอื่นๆ ที่ยังทำงานปกติ ทำให้บริการยังคงดำเนินต่อไปได้

สิ่งที่ต้องระวังเมื่อคุณเริ่มเพิ่มเครื่อง

  • Stateless design – คำขอไม่ควรพึ่งพาข้อมูลที่เก็บไว้ในหน่วยความจำของเซิร์ฟเวอร์เครื่องใดเครื่องหนึ่งเท่านั้น มิฉะนั้นผู้ใช้อาจถูกส่งไปยังโหนดที่ไม่มีข้อมูลบริบท (context) ที่จำเป็น การใช้ shared caches หรือฐานข้อมูลจะช่วยแก้ปัญหานี้ได้
  • Health checks – ตัว balancer ต้องสามารถตรวจพบเซิร์ฟเวอร์ที่กำลังมีปัญหาได้อย่างรวดเร็วและหยุดส่งทราฟฟิกไปที่เครื่องนั้น
  • Auto-scaling policies – แพลตฟอร์มคลาวด์หลายแห่งอนุญาตให้คุณกำหนดเกณฑ์ (เช่น การใช้งาน CPU, ความหน่วงของคำขอ) เพื่อสั่งให้เปิดหรือปิด instances โดยอัตโนมัติ ช่วยให้ต้นทุนสอดคล้องกับความต้องการใช้งานจริง

มุมมองต่าง: vertical scaling ยังไม่ตาย

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

กุญแจสำคัญคือการรู้ว่าเมื่อไหร่ที่เทคนิค “ซื้อเครื่องที่ใหญ่กว่า” เริ่มไม่คุ้มค่ากับสิ่งที่ได้รับ และเริ่มวางแผนสำหรับการกระจายโหลด

บทสรุป

การที่เซิร์ฟเวอร์ทำงานช้าลงหลังจากการเปิดตัว มักเป็นปัญหาเรื่องการแย่งชิงทรัพยากร (resource contention) ไม่ใช่ข้อผิดพลาดของโค้ด เนื่องจากรอบการทำงานของ CPU และหน่วยความจำ RAM นั้นมีจำกัด และเมื่อมีคำขอ (requests) จำนวนมากเข้ามาพร้อมกัน คำขอเหล่านั้นจะถูกจัดเข้าคิว ส่งผลให้ระยะเวลาในการตอบสนองนานขึ้น การขยายระบบในแนวตั้ง (Vertical scaling) ช่วยเพิ่มพื้นที่การทำงาน (headroom) ให้คุณได้อีกเล็กน้อย แต่ในไม่ช้าก็จะเผชิญกับขีดจำกัดทั้งทางกายภาพและทางเศรษฐศาสตร์ ส่วนการขยายระบบในแนวนอน (Horizontal scaling)—ซึ่งเป็นการเพิ่มเซิร์ฟเวอร์ที่มีขนาดเล็กลงแต่มีจำนวนมากขึ้นไว้หลัง Load Balancer—เป็นแนวทางที่ประหยัดกว่าและมีความยืดหยุ่น (resilient) มากกว่าเมื่อปริมาณการใช้งาน (traffic) เพิ่มสูงขึ้น ทันทีที่คุณสังเกตเห็นว่าคิวเริ่มยาวขึ้น นั่นคือเวลาที่คุณต้องประเมินว่าการเพิ่มจำนวน Core เพียงไม่กี่คอร์จะเพียงพอหรือไม่ หรือคุณควรเริ่มกระจายภาระงาน (load) ไปยังเครื่องเซิร์ฟเวอร์หลายๆ เครื่องแทน

ที่มา: บทความจาก dev.to “Why Servers Slow Down – CPU, RAM and the hidden cost of every request.”