ขยายระบบจัดเก็บข้อมูลออนไลน์อย่างรวดเร็วเพื่อรองรับผู้ใช้ ChatGPT กว่า 1 พันล้านคน (ตอนที่ 2)
เบื้องหลังการปรับปรุง Azure Cosmos DB ใน Habitat ระบบจัดเก็บข้อมูลสำหรับแอปพลิเคชันของเรา เพื่อรองรับการเติบโตอย่างก้าวกระโดดในระดับที่ไม่เคยมีมาก่อน
ผลิตภัณฑ์ทั้งหมดของ OpenAI จำเป็นต้องเข้าถึงข้อมูลได้อย่างรวดเร็วและเชื่อถือได้ ซึ่งเป็นหน้าที่ของ Habitat แพลตฟอร์มจัดเก็บข้อมูลของเรา โดยระบบนี้ต้องตอบสนองผู้ใช้กว่า 1 พันล้านคนใน 40 ภูมิภาคทั่วโลกได้ภายในเวลาเพียงไม่กี่มิลลิวินาที โครงสร้างพื้นฐานของเราจึงต้องเผชิญกับความท้าทายครั้งใหญ่ นั่นคือการรองรับการเติบโตอย่างก้าวกระโดดและรูปแบบการใช้งานใหม่ๆ ขณะเดียวกันก็ต้องเพิ่มความเสถียร ประสิทธิภาพ และความรวดเร็วในการพัฒนาผลิตภัณฑ์อย่างต่อเนื่อง การรับมือกับความท้าทายนี้ทำให้เราต้องกลับมาทบทวนทั้งการออกแบบและแนวทางบริหารจัดการแพลตฟอร์มจัดเก็บข้อมูลออนไลน์ใหม่ เราต้องชั่งน้ำหนักข้อดีและข้อเสียของแนวทางต่างๆ อยู่เสมอ โดยให้ความสำคัญกับการทำให้ระบบมีเสถียรภาพเพียงพอสำหรับรองรับภาระงานสำคัญของผลิตภัณฑ์เป็นอันดับแรก จากนั้นจึงเพิ่มความเร็วให้ตอบสนองผู้ใช้ทั่วโลกได้อย่างมีประสิทธิภาพ และสุดท้ายคือทำให้ระบบสามารถรองรับการใช้งานในระดับมหาศาลได้อย่างคล่องตัว
บทความสองตอนนี้จะพาไปดูว่าเราพัฒนา Habitat จากไลบรารีฝั่งไคลเอนต์และฐานข้อมูลแบบเรียบง่าย ให้กลายเป็นแพลตฟอร์มจัดเก็บข้อมูลที่กระจายอยู่ทั่วโลกและรองรับข้อมูลมากกว่า 500 เพตะไบต์ได้อย่างไร โดยตอนที่ 1 เล่าถึงการพัฒนา Habitat จากไคลเอนต์ที่เขียนด้วย Python มาเป็นบริการ พร้อมเจาะลึกเทคนิคต่างๆ ที่ช่วยให้เราขยายขีดความสามารถของบริการที่พัฒนาด้วย Python ได้ไกลเกินกว่าที่หลายคนคิดว่าจะทำได้จริง
ในบทความตอนที่ 2 นี้ เราจะพาไปดูว่าเราขยายขีดความสามารถของ Azure Cosmos DB ซึ่งเป็นระบบจัดเก็บข้อมูลเบื้องหลัง Habitat ได้อย่างไร โดยเราได้ร่วมมืออย่างใกล้ชิดกับทีม Azure จนพัฒนาแนวทางการใช้คอนเทนเนอร์แบบหลายผู้เช่าที่ทั้งสองฝ่ายร่วมกันดูแล ซึ่งสามารถนำไปใช้งานได้จริงและรองรับการอ่านข้อมูลได้อย่างรวดเร็ว แม้ระบบจะมีขนาดใหญ่และกระจายอยู่ทั่วโลก
ภาพ 01 · Habitat คืออะไร
แพลตฟอร์มพื้นที่จัดเก็บออนไลน์
Habitat คือแพลตฟอร์มพื้นที่จัดเก็บออนไลน์ที่เราสร้างขึ้น เพื่อให้ผลิตภัณฑ์ของ OpenAI เข้าถึงข้อมูลที่จำเป็นได้อย่างรวดเร็วและเชื่อถือได้
- คำขอ
- การตอบกลับ
- การเปลี่ยนแปลง (CDC)
เมื่อบริษัทเติบโตขึ้น ทีมโครงสร้างพื้นฐานก็มักเปลี่ยนจากการดูแลระบบแบบผู้เช่ารายเดียวมาเป็นระบบแบบหลายผู้เช่า ในระบบแบบผู้เช่ารายเดียว ทีมพัฒนาผลิตภัณฑ์แต่ละส่วนจะดูแลระบบของตัวเอง ซึ่งช่วยจำกัดขอบเขตผลกระทบเมื่อเกิดปัญหา แบ่งหน้าที่ความรับผิดชอบได้ชัดเจน และแยกภาระงานออกจากกันได้ง่าย แต่เมื่อมีทีมและส่วนต่างๆ ของผลิตภัณฑ์เพิ่มขึ้น ค่าใช้จ่ายในการดูแลระบบลักษณะนี้ก็สูงขึ้นตามไปด้วย อีกทั้งแต่ละทีมยังต้องวางแผนขีดความสามารถในการรองรับภาระงานด้วยตัวเอง ซึ่งมักนำไปสู่การจัดสรรทรัพยากรเกินความจำเป็นเป็นจำนวนมาก
ระบบแบบหลายผู้เช่าจะรวมการดูแลระบบไว้ที่ทีมฐานข้อมูลส่วนกลาง ซึ่งมีความเชี่ยวชาญและประสบการณ์ในการจัดสรรทรัพยากรมากกว่า แต่แนวทางนี้ก็มีข้อเสีย เพราะเมื่อผู้เช่ารายใดรายหนึ่งใช้ทรัพยากรมากเกินไป ก็อาจทำให้ผู้เช่ารายอื่นที่ใช้ระบบร่วมกันได้รับผลกระทบ ปัญหานี้เรียกว่าการแย่งใช้ทรัพยากรระหว่างภาระงาน
ในการพัฒนา Habitat เราต้องชั่งน้ำหนักข้อดีและข้อเสียของแนวทางต่างๆ เพื่อสร้างระบบจัดเก็บข้อมูลที่มีเสถียรภาพ ใช้ทรัพยากรอย่างมีประสิทธิภาพ และรองรับการใช้งานในระดับใหญ่ได้ ปัจจุบัน Habitat ทำหน้าที่เป็นชั้นฐานข้อมูลแบบหลายผู้เช่าสำหรับผลิตภัณฑ์หลายตัวของ OpenAI แต่กว่าจะมาถึงจุดนี้ เราได้ลองปรับเปลี่ยนแนวทางมาแล้วหลายครั้ง ตั้งแต่การใช้คอนเทนเนอร์ Azure Cosmos DB ร่วมกันเพียงตัวเดียว ไปจนถึงการจัดเตรียมคอนเทนเนอร์เบื้องหลังแยกสำหรับแต่ละบริการ ก่อนจะกลับมาใช้คอนเทนเนอร์ร่วมกันเป็นค่าเริ่มต้นอีกครั้ง อย่างไรก็ตาม เรายังอยู่ในช่วงเริ่มต้นของการพัฒนาระบบแบบหลายผู้เช่าบน Habitat แม้ปัจจุบันจะรองรับการใช้งานได้หลากหลายรูปแบบ แต่เราก็ยังสามารถชะลอการลงทุนเพิ่มเติมในด้านนี้ออกไปได้ ด้วยการใช้ประโยชน์จากความสามารถพื้นฐานที่ Azure Cosmos DB มีให้อยู่แล้วให้มากที่สุด
ก่อนจะเล่าถึงเส้นทางการพัฒนา Azure Cosmos DB ของเรา มาทำความเข้าใจพื้นฐานบางอย่างกันก่อน
บัญชี Azure Cosmos DB จะกำหนดว่ามีคอนเทนเนอร์ใดบ้างและใช้นโยบายการทำสำเนาข้อมูลแบบใด
คอนเทนเนอร์แต่ละตัวจะได้รับการจัดสรรอัตราการประมวลผลตามที่กำหนดไว้ โดยวัดเป็นหน่วยคำขอต่อวินาที (RU/s)
ภายในคอนเทนเนอร์แต่ละตัว ระบบจะแบ่งข้อมูลออกเป็นส่วนๆ ตามคีย์พาร์ทิชันเชิงตรรกะที่ระบุไว้ โดยมีการกำหนดขีดจำกัดด้านพื้นที่จัดเก็บข้อมูลและอัตราการประมวลผลสำหรับคีย์แต่ละรายการไว้อย่างชัดเจนในเอกสาร
Azure Cosmos DB จะจัดการกระจายคีย์พาร์ทิชันเชิงตรรกะไปยังพาร์ทิชันทางกายภาพที่มีจำนวนน้อยกว่า โดยจะแบ่งพาร์ทิชันทางกายภาพออกเป็นหลายส่วนเมื่อปริมาณข้อมูลที่จัดเก็บเกินเกณฑ์ที่กำหนด หรือเมื่อคอนเทนเนอร์จำเป็นต้องมีพาร์ทิชันทางกายภาพเพิ่มขึ้นเพื่อรองรับอัตราการประมวลผลที่จัดสรรไว้
ตอนเริ่มต้น เราไม่ได้จำกัดปริมาณคำขอที่ไคลเอนต์ส่งเข้ามา แต่ปล่อยให้ Azure Cosmos DB ควบคุมโหลดผ่านขีดจำกัด 10,000 RU/s ต่อคีย์พาร์ทิชันเชิงตรรกะตามที่ระบุไว้ อีกทั้งยังใช้คอนเทนเนอร์เริ่มต้นเพียงตัวเดียวในแต่ละบัญชี Azure Cosmos DB วิธีนี้ใช้งานได้ค่อนข้างดีในช่วงแรก แต่เมื่อเวลาผ่านไปก็เริ่มพบปัญหาหลายอย่าง ดังนี้
ตอนที่เราออกแบบ API ในช่วงแรก เราเลือกให้ไคลเอนต์กำหนดคีย์พาร์ทิชันเชิงตรรกะเองได้โดยตรง แต่ผลที่ตามมาคือบริการและฟีเจอร์ต่างๆ มักเลือกใช้คีย์ซ้ำกัน โดยเฉพาะคีย์ที่ใช้กันทั่วไปอย่าง user_id และ workspace_id เมื่อการใช้งานหลายส่วนเลือกคีย์เดียวกัน ก็ต้องแบ่งขีดความสามารถในการประมวลผลภายใต้ข้อจำกัดของ Azure Cosmos DB ร่วมกัน ทำให้ระบบรองรับปริมาณงานรวมของผู้ใช้แต่ละรายได้น้อยลง
ก่อนที่เราจะเปลี่ยนมาใช้ Habitat และ Azure Cosmos DB ปัญหาหนึ่งที่พบเป็นประจำขณะขยายระบบ Postgres คือคำขอจำนวนมากจากองค์กรที่มีการใช้งานสูงผิดปกติ หรือจากคีย์ที่ถูกเรียกใช้บ่อยมาก ซึ่งอาจทำให้ฐานข้อมูลทั้งระบบล่มได้ เพราะผู้เช่ารายเดียวอาจสร้างภาระงานสูงเกินสัดส่วนที่ควรจะเป็น เราจึงต้องร่วมกันทุ่มเทความพยายามอย่างมากในการจัดเก็บข้อมูลของคีย์เหล่านี้ไว้ในแคช และเพิ่มกลไก lease สำหรับกรณีที่ไม่พบข้อมูลในแคช เพื่อป้องกันไม่ให้คำขอที่ต้องไปดึงข้อมูลจากฐานข้อมูลพร้อมกันสร้างภาระหนักจนระบบรับไม่ไหว
Figure 02a · Logical partition key limits
Different clients, the same partition key
แม้ Azure Cosmos DB จะกำหนดขีดจำกัดด้านขนาดข้อมูลและอัตราการประมวลผลสำหรับคีย์พาร์ทิชันเชิงตรรกะแต่ละรายการไว้ในเอกสาร แต่ระบบกลับบังคับใช้ขีดจำกัดเหล่านี้กับพาร์ทิชันทางกายภาพโดยรวม นั่นหมายความว่าพาร์ทิชันเชิงตรรกะแต่ละส่วนไม่สามารถใช้ขีดความสามารถได้เต็ม 10,000 RU/s เพราะต้องแบ่งทรัพยากรกับคีย์พาร์ทิชันเชิงตรรกะอื่นๆ ที่อยู่ในพาร์ทิชันทางกายภาพเดียวกัน
ด้วยเหตุนี้ เมื่อภาระงานหนึ่งใช้ทรัพยากรมากเกินไป ก็อาจส่งผลกระทบต่อคีย์พาร์ทิชันเชิงตรรกะอื่นๆ อีกจำนวนมาก แม้จะไม่มีความเกี่ยวข้องกันเลยก็ตาม ทำให้ภาระงานของฟีเจอร์เฉพาะกลุ่มบางอย่างไปรบกวนการทำงานหลักของระบบ เช่น การเข้าสู่ระบบและการสมัครใช้งาน
Figure 02b · Noisy neighbors
Different users, the same physical partition
พาร์ทิชันทางกายภาพแต่ละส่วนไม่ได้มีขีดจำกัดอัตราการประมวลผลที่ตายตัว แต่ขึ้นอยู่กับว่าคอนเทนเนอร์ Azure Cosmos DB ได้รับการจัดสรรอัตราการประมวลผลรวมไว้เท่าใด จากนั้นระบบจะแบ่งขีดความสามารถในการประมวลผลที่จัดสรรให้คอนเทนเนอร์นั้นไปยังพาร์ทิชันทางกายภาพแต่ละส่วนในสัดส่วนที่ใกล้เคียงกัน
เมื่อปริมาณข้อมูลเพิ่มขึ้น ระบบจะแบ่งพาร์ทิชันทางกายภาพออกเป็นหลายส่วน ทำให้จำนวนพาร์ทิชันเพิ่มขึ้น แต่ขีดความสามารถในการประมวลผลรวมที่จัดสรรไว้ยังเท่าเดิม ส่งผลให้แต่ละพาร์ทิชันรองรับอัตราการประมวลผลได้น้อยลงเมื่อมีข้อมูลเพิ่มขึ้น
ปัญหานี้ส่งผลกระทบเป็นพิเศษต่อการใช้งานที่ต้องจัดเก็บข้อมูลจำนวนมากในลักษณะคล้าย Blob เพราะเพียงแค่ข้อมูลที่จัดเก็บมีปริมาณเพิ่มขึ้น ระบบก็อาจรองรับภาระงานที่กำลังทำงานอยู่ได้น้อยลง ทั้งที่จำนวนคำขอต่อวินาทีและปริมาณการใช้งานไม่ได้เพิ่มขึ้นเลย
Figure 02C · Weak partitions
The limit falls below demand
A partition splits when it reaches its storage limit. Each child receives half the throughput capacity.
การใช้คอนเทนเนอร์แยกกันช่วยแก้ปัญหาขีดจำกัดของคีย์พาร์ทิชันและการแย่งใช้ทรัพยากรระหว่างภาระงานได้บางส่วน เพราะแต่ละคอนเทนเนอร์จะมีพาร์ทิชันทางกายภาพเป็นของตัวเอง ทำให้ปัญหาการแย่งใช้ทรัพยากรหรือการใช้คีย์พาร์ทิชันซ้ำกันเกิดขึ้นได้เฉพาะระหว่างภาระงานที่อยู่ภายในคอนเทนเนอร์เดียวกันเท่านั้น อย่างไรก็ตาม การสร้างคอนเทนเนอร์ใหม่แต่ละครั้งมีภาระในการดำเนินงานเพิ่มขึ้น เนื่องจากต้องวางแผนขีดความสามารถในการรองรับภาระงานแยกกันสำหรับแต่ละคอนเทนเนอร์ เราจึงต้องการสร้างคอนเทนเนอร์ใหม่เฉพาะเมื่อมีเหตุผลที่เหมาะสมในการแยกตามบริการหรือกรณีการใช้งาน
เราเริ่มแยกคอนเทนเนอร์ Azure Cosmos DB สำหรับการใช้งานใหม่ๆ ที่มีความสำคัญมากและต้องแยกทรัพยากรจากงานอื่นโดยเฉพาะ นอกจากนี้ เรายังพัฒนาสคริปต์ที่ช่วยป้องกันไม่ให้แต่ละพาร์ทิชันรองรับปริมาณงานได้น้อยลงเมื่อมีการแบ่งพาร์ทิชันเพิ่มขึ้น โดยปรับขีดความสามารถในการประมวลผลรวมของแต่ละคอนเทนเนอร์ให้เหมาะกับจำนวนพาร์ทิชันทางกายภาพ เมื่อใช้ทั้งสองแนวทางร่วมกัน เราก็สามารถหลีกเลี่ยงปัญหาเดิมได้เกือบทั้งหมด
เนื่องจากเราใช้คอนเทนเนอร์เริ่มต้นมาตั้งแต่แรก บริการสำคัญที่มีอยู่เดิมหลายส่วนจึงไม่สามารถย้ายไปใช้คอนเทนเนอร์อื่นได้โดยไม่ย้ายข้อมูลตามไปด้วย เราจึงมักแนะนำให้ทีมใช้คอนเทนเนอร์แยกสำหรับบริการใหม่หรือฟีเจอร์หลักที่เพิ่มเข้ามา เพื่อปกป้องบริการสำคัญที่ยังต้องพึ่งพาข้อมูลในคอนเทนเนอร์เริ่มต้นที่ใช้ร่วมกัน แต่เมื่อระบบขยายตัว ภาระที่ตกอยู่กับคอนเทนเนอร์เดิมก็เพิ่มขึ้น พร้อมกับปัญหาที่เกิดขึ้นในระบบที่ใช้งานจริงที่มีจำนวนมากขึ้น เราจึงเริ่มจัดเตรียมคอนเทนเนอร์แยกให้กับทุกบริการใหม่หรือฟีเจอร์ขนาดใหญ่ เพื่อป้องกันไม่ให้คอนเทนเนอร์เริ่มต้นต้องรองรับภาระงานเพิ่มเติม
วิธีนี้ช่วยให้เราหลีกเลี่ยงเหตุขัดข้องที่อาจทำให้ระบบทั้งหมดล่มได้หลายครั้ง เพราะแม้จะเกิดปัญหาขึ้น ผลกระทบก็จำกัดอยู่เพียงบางฟีเจอร์หรือบางบริการที่ทำงานได้ไม่เต็มที่ แต่ในที่สุด การต้องสร้างและจัดเตรียมคอนเทนเนอร์ใหม่จำนวนมากก็เพิ่มภาระในการดูแลระบบจนเริ่มส่งผลกระทบต่อเรา
ในคอนเทนเนอร์เริ่มต้นที่หลายบริการใช้ร่วมกัน แม้ภาระงานใหม่จะเพิ่มขึ้นจาก 0 เป็น 1 ล้านคำขอต่อวินาที (QPS) ก็แทบไม่ส่งผลต่อปริมาณการใช้งานรวมมากนัก แต่หากเป็นคอนเทนเนอร์ที่แยกไว้โดยเฉพาะ ภาระงานใหม่ที่เพิ่มขึ้นในระดับเดียวกันอาจทำให้ปริมาณงานสูงกว่าระดับการใช้งานเดิมที่มีเพียงการทดสอบภายในถึง 1,000 เท่า
เมื่อเราเปลี่ยนมาใช้คอนเทนเนอร์แยกสำหรับแต่ละบริการ ทีมต่างๆ ก็ต้องเตรียมจัดสรรทรัพยากรให้คอนเทนเนอร์รองรับปริมาณงานที่คาดว่าจะเกิดขึ้นเมื่อเปิดตัวผลิตภัณฑ์ แต่บ่อยครั้งทีมพัฒนาผลิตภัณฑ์กลับเปิดใช้ฟีเจอร์ในระบบจริงโดยลืมเพิ่มขีดความสามารถของคอนเทนเนอร์ไว้ล่วงหน้า ทำให้ในวันเปิดตัว เราต้องเร่งเพิ่มขีดความสามารถของคอนเทนเนอร์ในนาทีสุดท้ายไปพร้อมกับรับมือเหตุขัดข้องในห้องประสานงานแก้ไขปัญหา (SEV)
การรองรับภาระงานหลายประเภทไว้ในระบบเดียวกันถือเป็นข้อได้เปรียบสำคัญของระบบแบบหลายผู้เช่า แต่เมื่อเราเลือกใช้คอนเทนเนอร์แยกกันเพื่อป้องกันไม่ให้ภาระงานรบกวนกัน เราก็ต้องยอมเสียข้อได้เปรียบนี้ไป
Figure 03 · Lack of stable aggregate growth
The same workload, different headroom
1K RU/s during load testing → 1M RU/s at launch
เมื่อเวลาผ่านไป การติดตามปริมาณการใช้งานของคอนเทนเนอร์ที่แยกไว้เฉพาะแต่ละบริการก็จำเป็นต้องอาศัยความเข้าใจอย่างละเอียดเกี่ยวกับผลิตภัณฑ์ เพื่อให้รู้ว่าปริมาณการใช้งานจะเปลี่ยนแปลงหรือเพิ่มขึ้นเมื่อใด
เราสามารถสร้างสคริปต์พื้นฐานสำหรับส่วนควบคุมระบบ เพื่อเพิ่มอัตราการประมวลผลที่จัดสรรให้แต่ละคอนเทนเนอร์ตามแนวโน้มการเติบโตของปริมาณงานได้ แต่เมื่อปริมาณงานรวมไม่ได้เพิ่มขึ้นอย่างสม่ำเสมอเหมือนเดิม การปรับขีดความสามารถของแต่ละคอนเทนเนอร์ให้เหมาะสมจึงต้องอาศัยการมีส่วนร่วมในการวางแผนทรัพยากรจากทีมพัฒนาผลิตภัณฑ์แทบทุกทีมของ OpenAI
แนวทางนี้ไม่สามารถรองรับการขยายตัวขององค์กรได้อย่างมีประสิทธิภาพ เนื่องจากแต่ละทีมที่รับผิดชอบบริการมีความรอบคอบในการวางแผนและจัดสรรทรัพยากร Azure Cosmos DB แตกต่างกันมาก
ยิ่งองค์กรขยายตัว ปัญหาในการดูแลระบบเหล่านี้ก็ยิ่งรับมือได้ยาก เพราะเมื่อไม่มีทีมส่วนกลางคอยดูแลเรื่องการวางแผนโดยเฉพาะ แต่ละทีมก็ต้องวางแผนกันเอง และหลายทีมก็ทำได้ไม่ดีนัก สุดท้ายเราจึงหันกลับมาใช้ระบบแบบหลายผู้เช่าอีกครั้ง โดยทำงานร่วมกับทีม Azure อย่างใกล้ชิดเพื่อแก้ปัญหาที่เคยเกิดขึ้นกับระบบที่ใช้ทรัพยากรร่วมกัน
เราเริ่มจากจำกัดการใช้ทรัพยากรของคีย์ที่สร้างภาระงานสูงที่สุดก่อน เพื่อไม่ให้คีย์เหล่านั้นใช้ขีดความสามารถในการประมวลผลของพาร์ทิชันทางกายภาพจนหมด และกระทบต่อภาระงานอื่นที่ใช้ทรัพยากรร่วมกัน วิธีนี้ช่วยลดความเสี่ยงที่คีย์ซึ่งมีการใช้งานสูงเพียงคีย์เดียวจะสร้างปัญหาลุกลามไปทั่วทั้งระบบ
การจัดลำดับความสำคัญของคำขอด้วยกลไก QoS ช่วยป้องกันไม่ให้ภาระงานที่ประมวลผลแบบออฟไลน์ เช่น การเพิ่มข้อมูลจำนวนมากในครั้งเดียวหรือการดึงข้อมูลออกจากฐานข้อมูล ใช้ขีดความสามารถในการประมวลผลทั้งหมดของพาร์ทิชันทางกายภาพ โดยระบบจะกำหนดให้คำขอจากภาระงานเหล่านี้มีความสำคัญต่ำกว่าและถูกจำกัดอัตราการประมวลผลก่อน เพื่อไม่ให้คำขอแบบโต้ตอบที่มีความสำคัญสูงกว่าและให้บริการผู้ใช้โดยตรงได้รับผลกระทบจากการจำกัดอัตราการประมวลผล
Azure Cosmos DB มีโหมดไร้เซิร์ฟเวอร์ที่สามารถแก้ปัญหาอัตราการประมวลผลต่อพาร์ทิชันลดลงในโหมดที่จัดสรรทรัพยากรไว้ล่วงหน้าได้อยู่แล้ว แต่โหมดนี้มีข้อเสียสำคัญคือปรับขนาดระบบตามปริมาณการใช้พื้นที่จัดเก็บข้อมูลเท่านั้น และจำกัดอัตราการใช้ RU ไว้ที่ 5,000 RU/s ต่อพาร์ทิชันทางกายภาพ แม้จะช่วยแก้ปัญหาดังกล่าวได้ แต่ก็ทำให้เราไม่สามารถขยายขีดความสามารถของระบบเพื่อรองรับภาระงานที่ต้องใช้ RU สูงได้
ทีม Azure Cosmos DB ได้พัฒนาโหมดไร้เซิร์ฟเวอร์เวอร์ชันปรับปรุงใหม่ให้เรา โดยแต่ละพาร์ทิชันทางกายภาพสามารถเพิ่มอัตราการประมวลผลได้สูงสุดถึง 10,000 RU/s พร้อมเพิ่มกลไกแบ่งพาร์ทิชันตามปริมาณการใช้ RU นอกเหนือจากการแบ่งตามปริมาณการใช้พื้นที่จัดเก็บข้อมูล ทำให้เราไม่ต้องคอยติดตามการใช้งานและปรับเพิ่มขีดความสามารถของคอนเทนเนอร์ด้วยตนเองอีกต่อไป
การปรับปรุงเหล่านี้ทำให้เราสามารถกลับมาใช้คอนเทนเนอร์ร่วมกันเพียงตัวเดียวได้อีกครั้ง โดยช่วยลดความยุ่งยากในการวางแผนทรัพยากรของทีมพัฒนาผลิตภัณฑ์ลงอย่างมาก ทั้งก่อนเปิดตัวและระหว่างการใช้งานจริง ขณะเดียวกันก็ยังสามารถแยกภาระงานออกจากกันได้ นับตั้งแต่นั้นเป็นเวลาหลายเดือนแล้วที่เราไม่พบเหตุขัดข้องจากการจัดสรรทรัพยากรหรือปัญหาการแย่งใช้ทรัพยากรระหว่างภาระงานเลย แม้ว่าการพัฒนาผลิตภัณฑ์จะดำเนินไปอย่างรวดเร็วขึ้นก็ตาม
เมื่อบริษัทขยายตัวจนถึงระดับเดียวกับ OpenAI บริการที่ผู้ให้บริการคลาวด์ดูแลจัดการให้ก็ไม่อาจพึ่งพาการดูแลจากผู้ให้บริการเพียงฝ่ายเดียวได้เหมือนเดิม เพราะภาระงานจำนวนมากมีขนาดหรือลักษณะการใช้งานที่แตกต่างจากระบบทั่วไปบนโครงสร้างพื้นฐานของผู้ให้บริการคลาวด์ เมื่อ OpenAI กลายเป็นหนึ่งในผู้ใช้ Azure Cosmos DB รายใหญ่ที่สุด การดูแลระบบให้ทำงานได้อย่างราบรื่นจึงต้องอาศัยแนวทางใหม่ ทั้งการทดสอบร่วมกัน การใช้แดชบอร์ดร่วมกัน การมีช่องทางสื่อสารโดยตรงระหว่างทีมวิศวกรรม และการร่วมกันรับผิดชอบปัญหาที่เกิดขึ้นเฉพาะกับระบบขนาดใหญ่อย่างของเรา ปัจจุบัน บัญชี Azure Cosmos DB ที่ใหญ่ที่สุดของเราจัดเก็บข้อมูลหลายสิบเพตะไบต์ และรองรับคำขอมากกว่า 20 ล้านรายการต่อวินาที เท่าที่เราทราบ เรายังเป็นบริษัทเพียงแห่งเดียวที่ใช้งาน Azure Cosmos DB ในระดับนี้
เหตุขัดข้องที่เกิดขึ้นในภูมิภาคหนึ่งช่วงปลายปี 2567 ทำให้เราเข้าใจว่าทำไมการทำงานร่วมกันอย่างใกล้ชิดจึงจำเป็น ตอนนั้นเกิดไฟฟ้าดับในภูมิภาคหลักของ Azure ซึ่งเป็นที่ตั้งของบัญชี Azure Cosmos DB ขนาดใหญ่ที่สุดบัญชีหนึ่งของเรา เมื่อเราต้องสลับระบบไปใช้ภูมิภาคสำรอง ก็พบว่าบัญชีขนาดใหญ่ที่สุดของเราอาจใช้เวลาหลายชั่วโมงกว่าจะสลับระบบได้สำเร็จ และทั้งเราและทีม Azure Cosmos DB ต่างก็ไม่เคยทดสอบการสลับระบบในระดับนี้มาก่อน
ประมาณหนึ่งเดือนต่อมา ขณะที่เรากำลังสลับบัญชีเหล่านั้นกลับไปยังภูมิภาคเดิม ก็เกิดเหตุขัดข้องรุนแรงขึ้นอีกครั้ง เนื่องจากมีการเชื่อมต่อจำนวนมากหลั่งไหลไปยังภูมิภาคเดิมพร้อมกัน จนเกตเวย์ของ Azure Cosmos DB ในภูมิภาคนั้นรับภาระไม่ไหว สาเหตุเกิดจากลักษณะการทำงานบางอย่างของไคลเอนต์ Azure Cosmos DB ในโหมดเกตเวย์เมื่อมีการสลับระบบ ซึ่งทำให้ไคลเอนต์ทั้งหมดสร้างการเชื่อมต่อและส่งคำขอไปยังภูมิภาคเดิมทันที ทั้งที่มีพาร์ทิชันทางกายภาพเพียงบางส่วนเท่านั้นที่ย้ายกลับไปยังภูมิภาคดังกล่าวแล้ว
หลังเกิดเหตุขัดข้องแต่ละครั้ง ทั้ง OpenAI และ Azure ต่างดำเนินการตามกระบวนการรับมือเหตุขัดข้องของตนเอง โดยสามารถระบุสาเหตุที่แท้จริงได้หลายประการและนำแนวทางแก้ไขมาใช้แล้ว อย่างไรก็ตาม เหตุขัดข้องเหล่านี้สะท้อนให้เห็นถึงปัญหาเชิงระบบที่ใหญ่กว่านั้น นั่นคือความแตกต่างในวิธีดำเนินงานและทดสอบระบบของทีมเราและทีม Azure Cosmos DB ในช่วงแรก การใช้บริการที่ผู้ให้บริการคลาวด์ดูแลจัดการให้ช่วยให้เราดำเนินงานได้รวดเร็วและมุ่งเน้นเป้าหมายทางธุรกิจได้อย่างเต็มที่ แต่เมื่อระบบขยายตัวจนมีขนาดใหญ่มาก เราก็ไม่สามารถพึ่งพาการดูแลจากผู้ให้บริการเพียงฝ่ายเดียวได้อีกต่อไป และจำเป็นต้องทำงานร่วมกับผู้ให้บริการอย่างใกล้ชิดในทุกระดับ ตั้งแต่การออกแบบไปจนถึงการดำเนินงาน
ทุกวันนี้ ทีมวิศวกรรมของ Habitat และ Azure ทำงานร่วมกันอย่างใกล้ชิดในการดูแลระบบทุกส่วน ตั้งแต่บริการต่างๆ ของ Habitat ไปจนถึงระบบจัดเก็บข้อมูลทางกายภาพของ Azure Cosmos DB เรามีบัญชี Azure Cosmos DB สำหรับทดสอบโดยเฉพาะ ซึ่งมีขนาดเท่ากับระบบที่ใช้งานจริง แต่ไม่ได้ใช้ให้บริการจริง เพื่อให้สามารถทดสอบการเปลี่ยนแปลงต่างๆ ได้ ทั้งสองทีมยังช่วยกันทดสอบและปรับปรุง SDK พร้อมหาแนวทางที่ดีที่สุดในการเพิ่มขีดความสามารถและกำหนดขนาดทรัพยากรของบัญชี Azure Cosmos DB นอกจากนี้ เรายังติดต่อทีมวิศวกรรมของอีกฝ่ายได้โดยตรงผ่าน Microsoft Teams และสามารถส่งสัญญาณเรียกทีมให้เข้ามาช่วยแก้ปัญหาได้ทันทีโดยไม่ต้องผ่านขั้นตอนของฝ่ายสนับสนุนหลายระดับ
ตลอดปีที่ผ่านมา เราและทีม Azure ได้ร่วมกันปรับปรุง Azure Cosmos DB ในหลายด้าน เพื่อให้ส่วนควบคุมระบบและเกตเวย์รองรับการขยายระบบได้ดียิ่งขึ้น ทั้งการเพิ่มกลไกป้องกันโหลดที่สูงเกินไปและระบบแคชข้อมูลเมตาดาตาประเภทต่างๆ ภายในเกตเวย์ เพื่อลดภาระของพาร์ทิชันที่จัดเก็บข้อมูลเมตาดาตาของ Azure Cosmos DB นอกจากนี้ เรายังลดภาระจากกระบวนการ habitat-service ที่เขียนด้วย Python ซึ่งทำงานอยู่เป็นจำนวนมาก ด้วยการจัดการการเชื่อมต่อเป็นพูลและนำการเชื่อมต่อเดิมกลับมาใช้ซ้ำให้มากขึ้น รวมถึงจัดวางภาระงานไว้ในตำแหน่งเดียวกันเมื่อทำได้ และใช้ VPC แยกกันเพื่อไม่ให้ภาระงานที่ประมวลผลแบบออฟไลน์ส่งผลกระทบต่อภาระงานสำคัญ
ความร่วมมือด้านวิศวกรรมอย่างใกล้ชิดในระดับนี้มีความสำคัญอย่างยิ่งต่อการรักษาเสถียรภาพของ Azure Cosmos DB ที่เราใช้งานตลอดปีที่ผ่านมา ระบบที่มีขนาดใหญ่หรือมีความสำคัญมากย่อมต้องอาศัยความร่วมมือเช่นนี้ โดยทุกฝ่ายต้องก้าวข้ามการแบ่งแยกหน้าที่ความรับผิดชอบและทำงานร่วมกันแม้จะอยู่คนละองค์กร
ดังที่กล่าวไว้ในตอนที่ 1 แนวคิดหลักของเราเริ่มจากทำให้ระบบทำงานได้อย่างราบรื่น แล้วค่อยเพิ่มความเร็ว ก่อนจะหาทางลดต้นทุน กล่าวคือ เราให้ความสำคัญกับความเสถียรเป็นอันดับแรก ตามด้วยประสิทธิภาพและการใช้ทรัพยากรอย่างคุ้มค่า Habitat ได้กลายเป็นระบบโครงสร้างพื้นฐานที่ OpenAI ขาดไม่ได้ เราจึงต้องทำให้ระบบมีเสถียรภาพก่อน เมื่อถึงปี 2568 ระบบเริ่มทำงานได้อย่างมั่นคงมากขึ้น ขณะเดียวกัน OpenAI ก็ขยายบริการไปทั่วโลก ทำให้เวลาแฝงกลายเป็นอุปสรรคสำคัญต่อทั้งผู้ใช้และทีมพัฒนาผลิตภัณฑ์
ทรัพยากรสำหรับการประมวลผลและการจัดเก็บข้อมูลมักอยู่คนละภูมิภาค ทำให้ไม่สามารถหลีกเลี่ยงการส่งคำขอข้ามภูมิภาคได้
Figure 04 · Improving performance at a global scale
Global traffic
Compute and storage capacity were often located in different regions, making cross-region requests unavoidable.
ตำแหน่งทางภูมิศาสตร์ของระบบประมวลผลและจัดเก็บข้อมูลมีไว้เพื่อประกอบคำอธิบายเท่านั้น
เวลาแฝงของคำขอขึ้นอยู่กับทั้งภูมิภาคที่จัดเก็บข้อมูลและภูมิภาคที่ประมวลผลคำขอ จึงมีความแตกต่างกันอย่างมาก เพื่อเพิ่มประสิทธิภาพในการตอบสนองคำขอของ Habitat นักพัฒนาผลิตภัณฑ์ต้องอาศัยการแคชข้อมูลเพิ่มเติมฝั่งไคลเอนต์ การรวมคำขอเป็นชุด การลดจำนวนการอ่านและเขียนฐานข้อมูล รวมถึงการย้ายงานที่ไม่จำเป็นออกจากขั้นตอนที่มีผลต่อเวลาตอบสนอง แม้วิธีเหล่านี้จะทำให้เกิดแนวทางออกแบบผลิตภัณฑ์ที่น่าสนใจและช่วยให้ผลิตภัณฑ์บางส่วนยังทำงานได้ดีแม้ฐานข้อมูลมีปัญหา แต่ก็แลกมาด้วยความซับซ้อนที่เพิ่มขึ้นและการพัฒนาปรับปรุงที่ช้าลง นั่นหมายความว่า Habitat ยังไม่บรรลุเป้าหมายในการช่วยให้ทีมสร้างและปรับปรุงผลิตภัณฑ์ได้อย่างรวดเร็วโดยไม่ต้องกังวลกับรายละเอียดของฐานข้อมูล
เนื่องจากคำขอมากกว่า 90% ที่ Habitat ได้รับเป็นการอ่านข้อมูล เราจึงให้ความสำคัญกับการเพิ่มประสิทธิภาพด้านนี้เป็นอย่างมากในปี 2569 และพัฒนาแนวทางปรับปรุงระบบในหลายระดับ ดังนี้
เราจึงมีบัญชี Azure Cosmos DB หลายบัญชีกระจายอยู่ในภูมิภาคต่างๆ ของ Azure ทั่วโลกเพื่อรองรับผู้ใช้ที่มีข้อกำหนดด้านสถานที่จัดเก็บข้อมูล แม้ผู้ใช้จะไม่ได้มีข้อกำหนดว่าต้องเก็บข้อมูลไว้ที่ไหน การจัดเก็บข้อมูลให้อยู่ใกล้ผู้ใช้ก็ยังมีประโยชน์ เพราะช่วยให้ระบบตอบสนองได้รวดเร็วขึ้นและมอบประสบการณ์การใช้งานที่ดีขึ้น
แต่ในทางปฏิบัติ เรายังไม่สามารถจัดเก็บข้อมูลไว้ใกล้ผู้ใช้ได้อย่างทั่วถึง โดยส่วนใหญ่ทำได้เฉพาะกรณีที่ต้องปฏิบัติตามข้อกำหนดด้านสถานที่จัดเก็บข้อมูล เพราะแต่ละภูมิภาคมีทรัพยากรของระบบคลาวด์จำกัด ประกอบกับข้อมูลของเรามีปริมาณมหาศาล ทำให้หลายภูมิภาคไม่สามารถรองรับพื้นที่จัดเก็บข้อมูลที่จำเป็นสำหรับปริมาณการใช้งานของผู้ใช้ในภูมิภาคนั้นได้
เมื่อศูนย์ข้อมูลในบางภูมิภาคมีข้อจำกัดด้านพื้นที่ กำลังไฟฟ้า หรือการระบายความร้อน บางครั้งเราต้องตัดสินใจว่าจะใช้ทรัพยากรที่มีอยู่เพื่อจัดเก็บข้อมูลไว้ใกล้กับระบบประมวลผล ทำให้ Habitat ตอบสนองได้เร็วขึ้น หรือจะนำทรัพยากรเหล่านั้นไปเพิ่มกำลังประมวลผลเพื่อรองรับการใช้งาน โดยยอมให้ระบบต้องส่งคำขอเข้าถึงข้อมูลไปยังภูมิภาคที่ไกลกว่าเดิม
ดังนั้น การตัดสินใจว่าจะจัดวางทรัพยากรไว้ที่ใดจึงมักต้องชั่งน้ำหนักระหว่างสองปัจจัย ได้แก่ ก) การลดเวลาแฝงให้กับผลิตภัณฑ์และกลุ่มผู้ใช้ต่างๆ และ ข) ปริมาณทรัพยากรที่มีอยู่สำหรับการจัดเก็บและประมวลผลข้อมูล
สำหรับงานที่ต้องตอบสนองอย่างรวดเร็วเป็นพิเศษ เช่น การเข้าถึงข้อมูลเมตาดาตาสำหรับการยืนยันตัวตนที่ต้องใช้กับทุกคำขอ เราลดระยะเวลาในการรับส่งข้อมูลไปกลับ (RTT) ระหว่างระบบประมวลผลกับ Habitat ด้วยการใช้บัญชี Azure Cosmos DB ที่สำเนาข้อมูลไปยังภูมิภาคสำรองหลายแห่ง โดยบางบัญชีมีการสำเนาข้อมูลครอบคลุมทั้ง 40 ภูมิภาคของ Azure ที่เราให้บริการ ส่วนบางบัญชีสำเนาข้อมูลไปยังอย่างน้อยหนึ่งภูมิภาคในแต่ละทวีป
เราจำเป็นต้องพัฒนาระบบจัดการการย้ายข้อมูลและกำหนดเส้นทางภายใน Habitat ให้ทำงานได้โดยที่ผู้ใช้ระบบไม่ต้องจัดการเองและเร็วกว่าที่ตั้งใจไว้ เพื่อให้สามารถย้ายชุดข้อมูลระหว่างบัญชีที่มีรูปแบบการสำเนาข้อมูลแตกต่างกันได้
อย่างไรก็ตาม วิธีนี้ก็ยังติดข้อจำกัดด้านทรัพยากรอยู่ดี จึงใช้ได้กับชุดข้อมูลที่คัดเลือกมาเพียงไม่กี่ชุด
ภาระงานส่วนใหญ่ของ Habitat เป็นการอ่านข้อมูล โดยแอปพลิเคชันต้องดึงข้อมูลการตั้งค่า สถานะ และคุณสมบัติต่างๆ อยู่ตลอดเวลา อีกทั้งคำขอจำนวนมากยังเป็นการเข้าถึงข้อมูลเพียงไม่กี่ประเภทที่ถูกเรียกใช้ซ้ำบ่อยๆ แม้ข้อมูลเหล่านี้จะมีสัดส่วนค่อนข้างน้อยเมื่อเทียบกับข้อมูลทั้งหมดก็ตาม ด้วยเหตุนี้ Habitat จึงเหมาะอย่างยิ่งกับการใช้ระบบแคชแบบกระจาย แม้การใช้แคชจะช่วยเพิ่มประสิทธิภาพของระบบที่ทำงานภายในภูมิภาคเดียวอยู่แล้ว แต่เมื่อมีการทำงานข้ามภูมิภาค ประโยชน์ที่ได้รับก็ยิ่งมากขึ้น เพราะแคชช่วยลดผลกระทบจากเวลาแฝงในการรับส่งข้อมูลข้ามภูมิภาคได้
เราได้พัฒนา Habitat ให้มีระบบแคชแบบกระจายที่ช่วยลดการเรียกข้อมูลจากฐานข้อมูลหลัก โดยเก็บสำเนาของออบเจ็กต์และข้อมูลความสัมพันธ์ที่เพิ่งมีการเข้าถึงไว้บนเซิร์ฟเวอร์ Valkey ซึ่งอยู่ใกล้กับจุดประมวลผลคำขอของผู้ใช้ในโครงสร้างพื้นฐานของเรา โดยทั่วไป ระบบแคชลักษณะนี้จะกำหนดระยะเวลาหมดอายุของข้อมูล (TTL) เพื่อหาจุดสมดุลระหว่างโอกาสที่จะพบข้อมูลในแคชกับความเสี่ยงที่ข้อมูลจะไม่เป็นปัจจุบัน หากตั้งเวลาไว้สั้น ข้อมูลเก่าก็จะค้างอยู่ในแคชไม่นาน แต่ระบบต้องดึงข้อมูลใหม่บ่อยขึ้นเพราะข้อมูลหมดอายุเร็ว ทำให้แคชช่วยเพิ่มประสิทธิภาพได้น้อยลง แต่ถ้าตั้งเวลาไว้นานขึ้น ระบบก็มีโอกาสพบข้อมูลในแคชมากขึ้น ทว่าอาจส่งข้อมูลเก่ากลับไปให้ผู้ใช้เป็นเวลานาน ส่งผลให้ประสบการณ์การใช้งานแย่ลงและผลิตภัณฑ์อาจทำงานไม่เป็นไปตามที่คาดไว้
อีกแนวทางหนึ่งคือ เมื่อแอปพลิเคชันเขียนข้อมูลใหม่ลงในฐานข้อมูล ก็สั่งให้ข้อมูลเดิมในแคชใช้ไม่ได้ไปพร้อมกัน วิธีนี้ช่วยลดโอกาสที่ระบบจะนำข้อมูลเก่ามาใช้ได้มาก แต่การทำให้ทุกอย่างทำงานสอดคล้องกันอย่างถูกต้องนั้นค่อนข้างยาก เพราะหากขั้นตอนใดขั้นตอนหนึ่งทำงานไม่สำเร็จ ข้อมูลเก่าก็อาจยังค้างอยู่ในแคชได้ ยิ่งระบบทำงานข้ามหลายภูมิภาค ปัญหาก็ยิ่งซับซ้อน เพราะเครือข่ายระหว่างภูมิภาคมีความน่าเชื่อถือน้อยกว่า และแคชอาจพยายามดึงข้อมูลใหม่ก่อนที่ฐานข้อมูลจะสำเนาข้อมูลล่าสุดไปถึงภูมิภาคนั้น การกำหนด TTL เพิ่มเติมช่วยจำกัดระยะเวลาที่ข้อมูลเก่าจะค้างอยู่ในแคชได้ แต่ก็ยังต้องเลือกระหว่างการให้ข้อมูลหมดอายุเร็วกับการเพิ่มโอกาสพบข้อมูลในแคชเหมือนเดิม
เราได้พัฒนาวิธีจัดการข้อมูลเก่าในแคชให้มีประสิทธิภาพมากขึ้น โดยใช้แนวทางคล้ายกับระบบ TAO ของ Meta แคชที่ผสานอยู่ใน Habitat ใช้กลไกการตรวจจับการเปลี่ยนแปลงของข้อมูล (CDC) ผ่านฟีดการเปลี่ยนแปลงข้อมูลของ Azure Cosmos DB เพื่อส่งคำสั่งให้แคชทั่วโลกเลิกใช้ข้อมูลเดิมภายในไม่กี่วินาที วิธีนี้ช่วยให้ระบบพบข้อมูลในแคชได้บ่อย ขณะเดียวกันก็ลดปัญหาข้อมูลไม่เป็นปัจจุบัน เมื่อข้อมูลต้นทางมีการอัปเดต บริการในโครงสร้างพื้นฐานของเราจะรับข้อมูลการเปลี่ยนแปลงจากฟีดดังกล่าว แล้วสั่งให้แคชในแต่ละภูมิภาคเลิกใช้ข้อมูลเดิม เมื่อมีการอ่านข้อมูลนั้นอีกครั้ง ระบบจะไม่พบข้อมูลที่ใช้ได้ในแคช จึงดึงข้อมูลเวอร์ชันล่าสุดมาเก็บไว้แทน
เรายังลดเวลาแฝงได้อย่างมากด้วยการเขียนโค้ดของบริการ Habitat ใหม่ด้วยภาษา Rust ซึ่งทำงานได้อย่างมีประสิทธิภาพมากกว่า Python ที่ใช้เดิม จึงช่วยลดภาระการประมวลผลส่วนเกินภายในตัวบริการได้
การปรับปรุงทั้งหมดนี้ช่วยลดเวลาในการอ่านข้อมูลที่ค่า p50 โดยรวมทั่วโลกจากประมาณ 120 มิลลิวินาที เหลือประมาณ 10 มิลลิวินาที หรือเร็วขึ้น 12 เท่านับตั้งแต่เราเริ่มมุ่งเน้นการเพิ่มประสิทธิภาพเมื่อต้นปีนี้
Figure 05 · Improving performance at a global scale
p50 latency for reads
Three major design changes improved read latency
แม้การใช้แคชจะช่วยลดเวลาในการตอบสนองของระบบโดยรวมได้อย่างมาก แต่คำขอบางรายการที่ใช้เวลานานที่สุดก็ยังต้องดึงข้อมูลที่ไม่มีอยู่ในแคชจากระบบจัดเก็บข้อมูลเบื้องหลัง ซึ่งมักอยู่ในภูมิภาคที่ห่างไกลออกไป เมื่อเรามีทรัพยากรพร้อมใช้งานมากขึ้นและปรับปรุงประสิทธิภาพการจัดเก็บข้อมูลได้ดีขึ้น เราจึงวางแผนแก้ปัญหาที่ต้นเหตุด้วยการจัดเก็บข้อมูลไว้ใกล้กับจุดที่จะมีการเรียกใช้ตั้งแต่แรก
ระบบตรวจจับการเปลี่ยนแปลงของข้อมูล (CDC) ที่มีเสถียรภาพและรองรับการขยายตัวได้ ไม่ได้มีความสำคัญแค่กับระบบแคชของ Habitat เท่านั้น แต่ยังช่วยส่งต่อการเปลี่ยนแปลงของฐานข้อมูลไปยังระบบปลายทางอื่นๆ ด้วย ในแต่ละวินาที ระบบตรวจจับการเปลี่ยนแปลงของข้อมูลได้หลายล้านรายการจากคอนเทนเนอร์หลายพันตัวและพาร์ทิชันภายในคอนเทนเนอร์อีกหลายล้านส่วน ก่อนส่งข้อมูลเหล่านี้ผ่าน Kafka กว่าร้อยหัวข้อ เพื่อนำไปใช้กับดัชนีรองที่อัปเดตข้อมูลให้สอดคล้องกันในภายหลัง ระบบรับส่งข้อมูลระหว่างแหล่งจัดเก็บ กระบวนการวิเคราะห์ข้อมูลแบบออฟไลน์ และฟีเจอร์อื่นๆ ของผลิตภัณฑ์ที่ทำงานแบบเรียลไทม์ เมื่อโครงสร้างพื้นฐานเบื้องหลังของเราขยายตัวไปทั่วโลก การติดตามการเปลี่ยนแปลงของข้อมูลแต่ละแถวก็ยิ่งซับซ้อนขึ้น หากไคลเอนต์ต้องการลงทะเบียนฟังก์ชันให้ทำงานทุกครั้งที่ข้อมูลประเภทของตนมีการเปลี่ยนแปลง ก็ต้องจัดการหลายเรื่องด้วยตัวเอง เริ่มจากตรวจสอบว่าข้อมูลอยู่ในบัญชีและคอนเทนเนอร์ใดของ Azure Cosmos DB จากนั้นต้องค้นหาว่าบริการ CDC ที่ทำงานอยู่ในแต่ละภูมิภาคและติดตามคอนเทนเนอร์เหล่านั้นคือชุดใด รวมถึงต้องปรับขีดความสามารถของกลุ่มเวิร์กเกอร์ CDC, Kafka และระบบที่รับข้อมูลไปประมวลผลให้เหมาะสมด้วย แพลตฟอร์ม CDC ของเราจึงมีเป้าหมายที่จะจัดการความซับซ้อนทั้งหมดนี้แทนนักพัฒนาผลิตภัณฑ์ โดยมีอินเทอร์เฟซที่ใช้งานง่าย ให้ไคลเอนต์เพียงลงทะเบียนฟังก์ชันที่ต้องการให้เรียกใช้เมื่อข้อมูลแต่ละแถวมีการเปลี่ยนแปลง ส่วนเราจะดูแลทั้งการเชื่อมต่อส่วนต่างๆ ของระบบและการปรับขีดความสามารถให้รองรับปริมาณงานที่เพิ่มขึ้น
เรามีส่วนควบคุมระบบภายในที่คอยตรวจสอบว่าคอนเทนเนอร์ทั้งหมดที่จำเป็นได้รับการติดตามการเปลี่ยนแปลงของข้อมูลอย่างครบถ้วน พร้อมเลือกภูมิภาคของ Azure Cosmos DB ที่เหมาะสำหรับอ่านข้อมูล และกระจายงานให้เวิร์กเกอร์หลายพันตัวในภูมิภาคต่างๆ ทั่วโลก เราเลือกอ่านข้อมูลจากภูมิภาคที่มีสำเนาข้อมูล และลดระดับความสำคัญของคำขออ่านฟีดการเปลี่ยนแปลงข้อมูล เพื่อไม่ให้งานเบื้องหลังเหล่านี้รบกวนการทำงานของ Habitat ที่ต้องตอบสนองคำขออย่างรวดเร็ว เมื่อระบบมีขนาดใหญ่ถึงระดับนี้ ปัญหาต่างๆ ก็เกิดขึ้นได้ตลอด ไม่ว่าจะเป็นเวิร์กเกอร์หยุดทำงาน คอนเทนเนอร์ขัดข้อง ระบบจัดเก็บข้อมูล lease ทำงานผิดพลาด การตั้งค่าระบบไม่ถูกต้อง หรือส่งข้อมูลไปยังปลายทางไม่สำเร็จ เราจึงปรับปรุงวิธีดูแลเวิร์กเกอร์ CDC ตลอดวงจรการทำงาน รวมถึงการจัดการ lease ให้มีความทนทานต่อข้อผิดพลาดมากขึ้น พร้อมแยกสตรีมข้อมูลออกจากกันเพื่อไม่ให้ปัญหาของสตรีมหนึ่งกระทบสตรีมอื่น และเพิ่มมาตรการป้องกันความผิดพลาดระหว่างการเปลี่ยนการตั้งค่าหรือปล่อยอัปเดตระบบ เรายังใช้คิวสำหรับเก็บข้อความที่ส่งไม่สำเร็จ เพื่อป้องกันไม่ให้รายการที่ส่งไปยังปลายทางไม่สำเร็จอย่างถาวรขัดขวางการประมวลผลรายการถัดไป หากเกิดเหตุขัดข้องในภูมิภาคใด เราก็สามารถสลับไปอ่านข้อมูลจากภูมิภาคอื่นของ Azure Cosmos DB ได้ นอกจากนี้ เรายังปรับปรุง SDK สำหรับ CDC ของ Azure ให้จัดการการบันทึกความคืบหน้าได้อย่างมีประสิทธิภาพมากขึ้น ด้วยการรวบรวมข้อมูลจุดบันทึกไว้ในหน่วยความจำก่อน แล้วจึงเขียนลงระบบจัดเก็บเป็นระยะ
แม้การทำงานของ Azure Cosmos DB ภายใน Habitat จะซับซ้อน แต่สิ่งที่เราต้องการมาตลอดคือให้นักพัฒนาผลิตภัณฑ์สร้างและปรับปรุงผลิตภัณฑ์ได้รวดเร็ว โดยไม่ต้องคอยจัดการรายละเอียดทางเทคนิคของโครงสร้างพื้นฐาน ซึ่งเป็นแนวคิดเดียวกับที่เราใช้พัฒนาแพลตฟอร์ม CDC
แม้จะมีทีมงานเพียงไม่กี่คน แต่เราก็สามารถรองรับการเติบโตอย่างรวดเร็วของแพลตฟอร์มจัดเก็บข้อมูลได้ด้วยการออกแบบ API สำหรับจัดเก็บข้อมูลให้มีเฉพาะความสามารถที่จำเป็น ขยายขีดความสามารถของบริการที่เขียนด้วย Python อย่างต่อเนื่อง และให้ความสำคัญกับการแก้ปัญหาทางวิศวกรรมที่เร่งด่วนที่สุดก่อน เราเริ่มจากการทำให้ระบบมีเสถียรภาพเพียงพอสำหรับรองรับภาระงานสำคัญของผลิตภัณฑ์ จากนั้นจึงเพิ่มประสิทธิภาพการอ่านข้อมูลสำหรับผู้ใช้ทั่วโลก และสุดท้ายคือปรับปรุงการดำเนินงานให้มีประสิทธิภาพเมื่อระบบขยายตัวในระดับมหาศาล แนวทางนี้ช่วยให้เรารองรับการเติบโตอย่างรวดเร็วและการใช้งานรูปแบบใหม่ๆ พร้อมยกระดับความเสถียร ประสิทธิภาพ และความรวดเร็วในการพัฒนาผลิตภัณฑ์ไปด้วย
เพื่อขยายขีดความสามารถของ Habitat และระบบจัดเก็บข้อมูลการสนทนาให้รองรับผู้ใช้อีกพันล้านคน เราจำเป็นต้องแก้ปัญหาความยุ่งยากในการสำเนาข้อมูลไปยังส่วนต่างๆ ของโครงสร้างพื้นฐาน ซึ่งจะยิ่งท้าทายมากขึ้นเมื่อระบบขยายตัว ด้วยเหตุนี้ เราจึงเริ่มพัฒนาระบบจัดเก็บข้อมูลออนไลน์ของเราเองที่รองรับข้อมูลระดับเอกซะไบต์ โดยออกแบบให้เหมาะกับข้อมูลประเภทที่มีขนาดใหญ่ของ Habitat โดยเฉพาะ ระบบนี้ยังอยู่ระหว่างการพัฒนาและผสานแกนหลักของ RocksDB Cloud จาก Rockset เข้ากับกลไกการสำเนาข้อมูลที่ใช้ Raft โดยใช้รูปแบบการจัดเก็บข้อมูลแบบเอกสารเช่นเดียวกับ Azure Cosmos DB แต่เลือกใช้สถาปัตยกรรมที่แยกระบบจัดเก็บข้อมูลออกจากส่วนประมวลผลและการสำเนาข้อมูลในระดับกายภาพ เพื่อลดปริมาณพื้นที่จัดเก็บข้อมูลแบบแฟลชที่ต้องใช้ โดยต้องแลกกับความสามารถในการรองรับจำนวนคำขอต่อวินาทีสูงสุดที่ลดลง
หากคุณอยากมีส่วนร่วมในการพัฒนาโครงสร้างพื้นฐานด้านข้อมูลในระดับแนวหน้าของเทคโนโลยี โปรดดูตำแหน่งงานที่เราเปิดรับสมัคร


