วิธีที่แคชของ Roblox รองรับ 1.38 พันล้าน QPS เกินขีดจำกัดของ Redis
การรับมือกับการเพิ่มขึ้นของทราฟฟิก 10 เท่าด้วยความน่าเชื่อถือและประสิทธิภาพ

ในสภาพแวดล้อมการเล่นเกมที่รองรับผู้เล่นจำนวนมากของ Roblox ผู้ใช้จะอ่านและเขียนข้อมูลในปริมาณและความเร็วที่สูงจนรูปแบบการแคชมาตรฐานไม่สามารถรองรับได้ ผู้ใช้อาจไม่สังเกตเห็นความล่าช้า 200 มิลลิวินาทีบนหน้าเว็บมาตรฐานที่มีการเก็บข้อมูลแบบคงที่ไว้ในแคช แต่ความล่าช้า 200 มิลลิวินาทีในการดึงข้อมูลการโต้ตอบหรือข้อมูลเมตาดาต้าของเซิร์ฟเวอร์บน Roblox อาจทำให้การเล่นเกมหยุดชะงักและทำลายโลกจำลองของเกมได้ Roblox ดำเนินการบนระบบนิเวศของข้อมูลที่ไม่สามารถคาดการณ์ได้ มีความเร็วสูง และมีอายุสั้น ซึ่งต้องดึงข้อมูลกลับมาภายในไม่กี่มิลลิวินาทีเพื่อรักษาความสมจริงของเกม
ชั้นแคชของเราถูกออกแบบมาเพื่อทำหน้าที่เป็นตัวดูดซับแรงกระแทกขนาดใหญ่ระหว่างผู้ใช้หลายล้านคนพร้อมกันกับการจัดเก็บข้อมูลถาวรของเรา มันสามารถรองรับปริมาณการใช้งานสูงสุดถึง 1.38 พันล้านคำขอต่อวินาที (QPS) โดยคลัสเตอร์เชิงตรรกะเดียวสามารถรองรับได้ถึง 100 ล้าน QPS ในโพสต์นี้ เราจะเปิดเผยเบื้องหลังวิธีการที่เราออกแบบสถาปัตยกรรมบริการแคชแบบสหพันธ์ (federated caching service) เพื่อรองรับปริมาณงานมหาศาลเกินขีดจำกัดของโหนด Redis® พร้อมทั้งรับมือกับการเพิ่มขึ้นของปริมาณการเข้าใช้งานถึง 10 เท่าอย่างที่ไม่เคยเกิดขึ้นมาก่อนบนคลัสเตอร์ที่ใหญ่ที่สุดของเรา

ขยายขีดจำกัดอุตสาหกรรมเพื่อตอบสนองความต้องการที่เพิ่มขึ้นอย่างต่อเนื่อง
ที่ Roblox บริการแคชชิ่งของเราถูกสร้างขึ้นบนเทคโนโลยี Redis® และหนึ่งคลัสเตอร์ของ Redis® มีศักยภาพในการรองรับได้ถึง 1,000 โหนด อย่างไรก็ตาม ขีดจำกัดที่ได้รับการยอมรับจากประสบการณ์จริงและอุตสาหกรรมนั้นต่ำกว่ามาก—อยู่ที่ประมาณ 400–500 โหนด1 เนื่องจากโปรโตคอล Gossip แบบกระจายศูนย์ของ Redis® ซึ่งใช้การสื่อสารระหว่างโหนดเพื่อแชร์ข้อมูลด้านสุขภาพ สถานะ และการแมปข้อมูลไปยังชาร์ท ในกลุ่มที่มีโหนดมากกว่าสองสามร้อยโหนดขึ้นไป การสื่อสารจากโปรโตคอล Gossip จะเริ่มใช้ทรัพยากร CPU และเครือข่ายเป็นจำนวนมาก โหนดแต่ละตัวต้องประมวลผลการอัปเดตสถานะจากจำนวนเพื่อนร่วมงานที่เพิ่มขึ้นเรื่อย ๆ ซึ่งทำให้ทรัพยากรถูกดึงไปใช้จากงานหลักในการให้บริการข้อมูลที่มีความหน่วงต่ำ การควบคุมนี้อาจนำไปสู่ความไม่เสถียรและประสิทธิภาพที่ไม่สามารถคาดการณ์ได้ ซึ่งเป็นเหตุผลที่ผู้ให้บริการคลาวด์ที่มีการจัดการกำหนดขีดจำกัดของโหนด มันเป็นขีดจำกัดทางปฏิบัติที่ไม่สามารถละเมิดได้โดยไม่กระทบต่อความน่าเชื่อถือ
ขีดจำกัดแบบคลัสเตอร์เดี่ยวที่ใช้ในทางปฏิบัตินี้ไม่เพียงพอที่จะรองรับแพลตฟอร์มที่ทำงานในระดับเดียวกับ Roblox ซึ่งบริการแบ็กเอนด์ที่ใหญ่ที่สุดต้องการ QPS มากกว่า 100 ล้านครั้งต่อวินาทีจากคลัสเตอร์ Redis® ตรรกะหนึ่งของเราในช่วงเวลาสูงสุด เพิ่มขึ้นจาก 10 ล้านครั้งต่อวินาทีภายในระยะเวลาเพียงสามเดือน
เราได้นำสถาปัตยกรรมแบบสหพันธ์มาใช้เพื่อเอาชนะข้อจำกัดทางสถาปัตยกรรมนี้ โดยวางพร็อกซีแบบรีเวิร์สของไคลเอนต์ไว้ด้านหน้าของคลัสเตอร์ Redis® ขนาดเล็กและอิสระหลายคลัสเตอร์ เราใช้ขีดจำกัด 400 โหนดต่อคลัสเตอร์เพื่อให้มั่นใจในประสิทธิภาพที่คาดการณ์ได้
จากมุมมองของแอปพลิเคชันและบริการนับพันของเรา ไคลเอนต์รีเวิร์สพร็อกซีจะนำเสนอคลัสเตอร์ที่แตกต่างกันเหล่านี้เป็นบริการแคชเดียวที่รวมเป็นหนึ่งเดียวและสามารถปรับขนาดได้ การรวมกลุ่มนี้ช่วยให้เราสามารถขยายระบบในแนวนอนได้เกือบไม่จำกัดเพียงแค่เพิ่มคลัสเตอร์เข้าไปในกลุ่มที่รวมกัน โดยไม่ต้องกังวลกับข้อจำกัดของโปรโตคอล Gossip เลย วันนี้ การติดตั้งแคชแบบเดี่ยวที่ใหญ่ที่สุดของเราประกอบด้วยโหนด Redis® มากกว่า 6,000 โหนด ซึ่งได้รับการสนับสนุนโดยคลัสเตอร์ Redis® อิสระมากกว่า 15 คลัสเตอร์—ขนาดนี้สามารถทำได้เพียงด้วยรูปแบบการรวมศูนย์แบบสหพันธ์นี้เท่านั้น

กระบวนการย้ายข้อมูลสามขั้นตอน
การเปลี่ยนจากโครงสร้างแบบดั้งเดิมไปสู่สถาปัตยกรรมแบบสหพันธ์ในขณะที่ต้องจัดการคลัสเตอร์การผลิตที่ใช้งานอยู่หลายร้อยคลัสเตอร์นั้นถือเป็นภารกิจสำคัญอย่างยิ่ง เมื่อถึงสิ้นปี 2024 คลัสเตอร์จำนวนมากเหล่านี้ได้เข้าใกล้ขีดจำกัด 400 โหนดของเราแล้ว ทำให้การเปลี่ยนไปใช้โมเดลที่มีความจุสูงขึ้นเป็นเรื่องเร่งด่วน ความท้าทายหลักคืออินสแตนซ์ Redis® มาตรฐานทำงานแยกจากกันโดยสิ้นเชิงและไม่มีความสามารถในการรับรู้คลัสเตอร์อื่นโดยธรรมชาติ จึงจำเป็นต้องใช้วิธีเฉพาะในการจำลองข้อมูลระหว่างการย้าย
เพื่อแก้ไขปัญหานี้ เราได้พัฒนาขั้นตอนการเปลี่ยนแปลงระบบแบบโปร่งใสสามขั้นตอน ซึ่งออกแบบมาเพื่อเปลี่ยนผ่านบริการโดยไม่มีการมีส่วนร่วมของลูกค้าหรือการเปลี่ยนแปลงด้านแอปพลิเคชัน
กระบวนการทำงานด้านการย้ายข้อมูล
- การเขียนแบบคู่: เราได้กำหนดค่าพร็อกซีแบบย้อนกลับของไคลเอนต์ให้ทำการเขียนแบบคู่ โดยส่งข้อมูลขาเข้าไปยังทั้งคลัสเตอร์ต้นฉบับและปลายทางแบบสหพันธ์ใหม่พร้อมกัน
- ความเท่าเทียมและการสลับการอ่าน: เมื่อกระบวนการเขียนคู่ได้เติมข้อมูลที่เหมือนกันลงในคลัสเตอร์ใหม่แล้ว เนื่องจากข้อมูลทั้งหมดถูกกำหนดระยะเวลาการใช้งาน (TTL) เราจึงเปลี่ยนการรับส่งข้อมูลการอ่านจากคลัสเตอร์เดิมไปยังสถาปัตยกรรมแบบสหพันธ์ใหม่
- การยกเลิกการใช้งาน: หลังจากยืนยันความเสถียรของคลัสเตอร์ใหม่แล้ว เราได้หยุดการดำเนินการเขียนทั้งหมดไปยังคลัสเตอร์เดิมและปลดระวางคลัสเตอร์เดิม
เราประสบความสำเร็จในการย้ายบริการที่สำคัญที่สุดของเราเข้าสู่โมเดลแบบสหพันธ์ที่รองรับโหนดมากกว่า 6,000 โหนด ซึ่งเกินขีดจำกัดของคลัสเตอร์ Redis® เดี่ยวอย่างมาก
การจัดการการเติบโตอย่างรวดเร็วของ Grow a Garden
เริ่มตั้งแต่เดือนเมษายน 2025 เราเผชิญกับความท้าทายด้านขีดความสามารถในระดับที่บริการเพียงไม่กี่แห่งเคยประสบมาก่อน สาเหตุหลักมาจากความสำเร็จอย่างล้นหลามของโครงการ Grow a Garden ภายในเวลาเพียงไม่กี่สัปดาห์หลังเปิดตัว Grow a Garden ไม่เพียงแต่ทำลายสถิติของ Roblox เท่านั้น แต่ยังทำลายสถิติของอุตสาหกรรมเกมสำหรับจำนวนผู้เล่นพร้อมกัน (CCU) ตลอดกาลอีกด้วย ในเวลาเพียงสามเดือน จำนวนผู้เล่นของเกมได้ทะลุสถิติ CCU ของเกมเดียวที่เคยทำได้ไว้ที่ 2.8 ล้านผู้เล่น ไปสู่จุดสูงสุดเกิน 21 ล้านผู้เล่น การเติบโตอย่างรุนแรงนี้ทำให้ปริมาณการเข้าชมเพิ่มขึ้นถึง 10 เท่าไปยังคลัสเตอร์ Redis® ที่ใหญ่ที่สุดของเรา และเพิ่มขึ้น 3 เท่าไปยังระบบแคชทั้งหมด
Roblox ดำเนินการระบบแคชของเราบนเครื่องเซิร์ฟเวอร์ทางกายภาพในศูนย์ข้อมูลของเราเอง และการเติบโตที่ไม่เคยเกิดขึ้นมาก่อนนี้ไม่ได้เป็นส่วนหนึ่งของแผนความจุระยะยาวของเรา ในการรอดชีวิตจากคลื่นลูกนี้และรักษาความเสถียรของแพลตฟอร์มไว้ เราจำเป็นต้องปรับปรุงประสิทธิภาพของระบบที่มีอยู่ของเราอย่างรุนแรงในขณะที่ให้ความสำคัญกับความน่าเชื่อถือเป็นอันดับแรก
การเพิ่มประสิทธิภาพในช่วงที่มีการเพิ่มขึ้นอย่างรวดเร็ว
ก่อนอื่น เราจำเป็นต้องระบุคอขวดที่มีผลกระทบมากที่สุดในระบบของเรา เพื่อที่เราจะได้จัดลำดับความสำคัญในการทำงานเพื่อเพิ่มประสิทธิภาพ Roblox Caching ทำงานบนฮาร์ดแวร์สองกลุ่มที่แตกต่างกัน: กลุ่มหนึ่งสำหรับโหนดแบ็กเอนด์ Redis® และอีกกลุ่มหนึ่งสำหรับ Envoy กอง Redis® ของเราส่วนใหญ่ถูกจำกัดด้วยหน่วยความจำ ในขณะที่พร็อกซีฝั่งไคลเอนต์ถูกจำกัดด้วยพลังการประมวลผล
สำหรับกลุ่ม Redis® ที่ใช้หน่วยความจำของเรา เราได้นำนโยบายการจัดตารางเวลาใหม่มาใช้เพื่อปรับสมดุลการใช้งานหน่วยความจำในกลุ่มเครื่องกายภาพของเราให้ดียิ่งขึ้น นอกจากนี้ เรายังได้ปรับขนาดคอนเทนเนอร์ให้เหมาะสมเพื่อลดการกระจายตัวของหน่วยความจำ
เพื่อปรับปรุงการใช้ CPU ให้ดีขึ้น เราได้ดำเนินการปรับปรุงระบบแคชของเราสองประการที่สำคัญ:
- การปรับขนาดอัตโนมัติของพร็อกซีไคลเอนต์: เราได้ปรับนโยบายการปรับขนาดอัตโนมัติสำหรับกลุ่มพร็อกซีไคลเอนต์ที่มีข้อจำกัดด้านคอมพิวต์ของเรา โดยการลดค่าความเบี่ยงเบนที่อนุญาตจากเป้าหมาย CPU เราสามารถเพิ่มการใช้งาน CPU เฉลี่ยสำหรับงานต่างๆ ได้ โดยไม่เปลี่ยนเกณฑ์การปรับขนาดขึ้น
- การตรวจสอบสุขภาพของคลัสเตอร์ภายใน: เราได้ปรับปรุงการตรวจสอบสุขภาพภายในเพื่อลดการส่งสัญญาณที่ไม่จำเป็น โดยคงช่วงเวลาการตรวจจับเดิมไว้และประหยัดทรัพยากรการประมวลผล
การเปลี่ยนแปลงเหล่านี้ส่งผลให้การใช้งาน CPU ดีขึ้นเกือบ 10% ในที่สุด เราได้นำเวิร์กโหลดที่แตกต่างกันอย่างมากทั้งสองนี้มาจัดวางไว้ในกลุ่มเครื่องเดียวกัน โดยใช้การแยกในระดับคอนเทนเนอร์ cgroup ซึ่งช่วยลดความต้องการด้านความจุโดยรวมของเราลงได้ 25%
วิศวกรรมเพื่อความน่าเชื่อถือที่ไม่สั่นคลอน
ความน่าเชื่อถือยังคงเป็นสิ่งสำคัญอันดับหนึ่งของเรา แม้ในขณะที่เรากำลังเร่งตอบสนองความต้องการที่พุ่งสูงเป็นประวัติการณ์
การสังเกตการณ์แบบครบวงจร
เราเริ่มต้นด้วยการมุ่งเน้นทำความเข้าใจถึงข้อผิดพลาดที่อาจเกิดขึ้น โดยลงทุนอย่างมากในชุดเครื่องมือการสังเกตการณ์ของเรา เพื่อการตรวจสอบสุขภาพของระบบแคชแบบครอบคลุมและครบวงจร ตั้งแต่ต้นทางถึงปลายทาง ด้วยการติดตามความสำเร็จของเซิร์ฟเวอร์และข้อผิดพลาดที่เกิดขึ้นฝั่งไคลเอนต์ตลอดวงจรชีวิตของคำขอ เราสามารถตรวจจับและวินิจฉัยปัญหาได้อย่างรวดเร็ว มักจะสามารถป้องกันผลกระทบต่อผู้ใช้ได้ล่วงหน้า ตัวอย่างเช่น เราได้เพิ่มการตรวจจับคีย์ร้อน ซึ่งทำการสุ่มตัวอย่างการรับส่งข้อมูลแบบเรียลไทม์เพื่อระบุข้อมูลที่ถูกเข้าถึงมากเกินไปและสร้างภาระให้กับชั้นแคช เมื่อระบบตรวจพบคีย์ร้อน เราจะดำเนินการจำกัดปริมาณการรับส่งข้อมูลไปยังคีย์เหล่านั้นทั้งฝั่งเซิร์ฟเวอร์และฝั่งไคลเอนต์ล่วงหน้า เพื่อป้องกันระบบทำงานเกินกำลัง
การจัดการความล้มเหลว
ในระบบกระจายขนาดนี้ การล้มเหลวบางส่วนอาจเกิดขึ้นได้เป็นครั้งคราว เราได้ออกแบบระบบของเราให้สามารถรับมือกับการล้มเหลวเหล่านี้ได้อย่างราบรื่น และลดผลกระทบที่อาจเกิดขึ้นให้น้อยที่สุด
- ความล้มเหลวบางส่วนในคำขอแบบกลุ่ม: เราได้ปรับโครงสร้างระบบใหม่เพื่อรองรับความล้มเหลวบางส่วนในคำขอแบบกลุ่ม ก่อนหน้านี้ หากคำขอใดคำขอหนึ่งในกลุ่มที่แบ่งส่วนล้มเหลว จะทำให้ทั้งกลุ่มล้มเหลวไปด้วย แต่ตอนนี้คำขอสามารถสำเร็จได้แม้ว่าจะมีการดึงข้อมูลบางคีย์ไม่สำเร็จก็ตาม
- การลดปัญหาการอุดตันที่จุดเริ่มต้น: ระบบแคชถูกคาดหวังให้ทำงานได้อย่างรวดเร็ว แม้แต่การชะลอตัวของเครือข่ายเพียงเล็กน้อยก็สามารถทำให้คำขอสะสมและหมดเวลาได้ ซึ่งเป็นปรากฏการณ์ที่เรียกว่าการอุดตันที่จุดเริ่มต้น เราได้นำกลไกการลองใหม่แบบชาญฉลาดและกลยุทธ์การจัดการการเชื่อมต่อแบบพูลมาใช้ทั้งในชั้นไคลเอนต์และพร็อกซี เพื่อป้องกันไม่ให้คำขอที่ช้าเพียงหนึ่งรายการส่งผลกระทบต่อคำขออื่นๆ
- การฉีดข้อบกพร่องและความล่าช้า: เพื่อทดสอบความทนทานต่อความล้มเหลว เราทำการฉีดข้อบกพร่องที่ควบคุมได้ (เช่น การหยุดทำงานของโหนด การหยุดทำงานของแร็ก ความล่าช้าของเครือข่าย ข้อผิดพลาดของ API) เข้าสู่ระบบผลิตเป็นประจำโดยใช้เฟรมเวิร์กการฉีดข้อบกพร่องของเรา ด้วยการวิเคราะห์พฤติกรรมของระบบภายใต้เงื่อนไขเหล่านี้ เราสามารถระบุและแก้ไขจุดอ่อนได้อย่างเชิงรุก เพื่อให้มั่นใจในความน่าเชื่อถืออย่างต่อเนื่อง
ความยืดหยุ่นของฝั่งลูกค้า
เพื่อป้องกันไม่ให้ระบบแคชของเราถูกท่วมท้นจากปริมาณการเข้าชมที่เพิ่มขึ้นอย่างกะทันหัน เราได้ดำเนินการความทนทานต่อความล้มเหลวของฝั่งไคลเอนต์ที่แข็งแกร่ง กลไกนี้ทำงานในระดับแอปพลิเคชัน เพื่อให้แน่ใจว่าไม่มีบริการใดบริการหนึ่งสามารถครอบครองทรัพยากรแคชได้ทั้งหมด
- การจำกัดอัตราสำหรับการควบคุมการไหล: ลูกค้าของเรามีขีดจำกัดในการส่งข้อมูลขาออกทั้งหมด เพื่อให้มั่นใจว่าไม่ส่งคำขอมากกว่าที่บริการแบ็กเอนด์สามารถรองรับได้ คำขอจะถูกจำกัดความเร็วเมื่อเกินขีดจำกัดนี้ ซึ่งช่วยป้องกันไม่ให้บริการถูกใช้งานเกินขีดความสามารถ
- กลไกการลองใหม่และการหมดเวลา: ไลบรารีลูกค้าของเราใช้กลไกการลองใหม่ที่ปรับแต่งอย่างรอบคอบ รวมถึงการหมดเวลาและงบประมาณการลองใหม่ เพื่อป้องกันปัญหาการโจมตีพร้อมกัน (thundering herd) ซึ่งจะช่วยจำกัดผลกระทบที่อาจเกิดขึ้น ปลดปล่อยทรัพยากร และปรับปรุงการตอบสนองของระบบโดยรวม โดยการป้องกันการค้างอย่างไม่มีกำหนดและการลองใหม่พร้อมกันที่อาจทำให้ระบบล่ม

อนาคตของการแคชใน Roblox
การเดินทางของระบบแคชของ Roblox เริ่มต้นด้วยคลัสเตอร์ Redis® แบบ bare-metal ที่จัดการโดยตรงโดยเจ้าของแอปพลิเคชันแต่ละราย จากนั้นย้ายไปยังคลัสเตอร์ Memcached ที่จัดการโดยทีมแคชของเรา และสุดท้ายเปลี่ยนไปใช้โมเดล Redis®-as-a-service ซึ่งคลัสเตอร์ Redis® ถูกจัดเตรียมเป็นบริการที่มีการจัดการ แม้ว่าโมเดลนี้จะพิสูจน์แล้วว่ามีประสิทธิภาพสูงมากในระดับปัจจุบันของเรา แต่เราตระหนักถึงข้อจำกัดในด้านประสิทธิภาพการให้บริการและการแยกทรัพยากรสำหรับแพลตฟอร์มที่มีความพลวัตสูงเช่น Roblox
เมื่อแพลตฟอร์มยังคงเติบโตต่อไป เราวางแผนที่จะลงทุนอย่างมีนัยสำคัญในบริการแคชแบบมัลติเทนแนนท์รุ่นถัดไปที่สร้างขึ้นบน ValKey สถาปัตยกรรมนี้ได้รับการออกแบบมาเพื่อลดต้นทุนอย่างมากโดยการแชร์ทรัพยากรที่ใช้ร่วมกันผ่านมัลติเทนแนนท์ ในขณะที่ยังคงรับประกันการแยกข้อมูล ทรัพยากร และความล้มเหลวสำหรับแต่ละเทนแนนท์ เป้าหมายของเราคือการเพิ่มประสิทธิภาพ ความสามารถในการขยายตัว ความน่าเชื่อถือ และความคุ้มค่าของโครงสร้างพื้นฐานแคชของเราอย่างมาก เพื่อตอบสนองความต้องการของประสบการณ์ที่เพิ่มมากขึ้นบน Roblox
คำขอบคุณ:
ความสำเร็จนี้เป็นผลจากความร่วมมือของทุกคน ขอขอบคุณสมาชิกทีมท่านอื่นที่มีส่วนร่วมอย่างมีนัยสำคัญ ได้แก่ อุตการ์ช ซิงห์, คาร์ธิก รามาจันทราน, วีเนชา กาซิเรดดี้, เวจิ ฮู และเลออน เกา
1AWS จำกัด ElasticCache ไว้ที่ 500 โหนด
*Redis เป็นเครื่องหมายการค้าของ Redis Labs Ltd. สงวนสิทธิ์ทั้งหมดในเครื่องหมายการค้านี้ให้กับ Redis Labs Ltd.


