- OpenAI ขยายโครงสร้างพื้นฐาน PostgreSQL ครั้งใหญ่เพื่อรองรับ ทราฟฟิกของ ChatGPT และ API ที่พุ่งสูงขึ้น โดยใช้ Azure PostgreSQL Flexible Server แบบเดี่ยวและรีดรีพลิกาประมาณ 50 ตัว เพื่อรองรับ QPS ระดับหลายล้าน
- ยังคงสถาปัตยกรรมที่เหมาะกับ เวิร์กโหลดที่เน้นการอ่าน พร้อมย้ายบางเวิร์กโหลดไปยัง Azure Cosmos DB เพื่อลดภาระฝั่งเขียน
- ปรับแต่งหลายด้าน เช่น การพูลการเชื่อมต่อด้วย PgBouncer, การล็อกแคช, การจำกัดอัตรา, การแยกเวิร์กโหลด เพื่อเพิ่มเสถียรภาพและปรับปรุงเวลาแฝง
- เพื่อก้าวข้าม ข้อจำกัดของโครงสร้างแบบ single primary จึงดำเนินการทั้งการตั้งค่าความพร้อมใช้งานสูง (HA), hot standby และการทดสอบ cascading replication ควบคู่กัน
- แนวทางนี้ช่วยให้บรรลุ ความพร้อมใช้งาน 99.999% และ ค่า p99 latency ระดับเลขสองหลักในหน่วยมิลลิวินาที พร้อมเปิดทางสู่การขยายในอนาคตด้วย PostgreSQL แบบชาร์ดดิ้ง หรือระบบแบบกระจาย
ภาพรวมการขยาย PostgreSQL
- PostgreSQL เป็นระบบข้อมูลหลักของ ChatGPT และ OpenAI API โดยในช่วง 1 ปีที่ผ่านมา ภาระงานเพิ่มขึ้นมากกว่า 10 เท่า
- รองรับคำขอจาก ผู้ใช้ 800 ล้านคน ด้วยอินสแตนซ์ primary เดี่ยวและรีดรีพลิกาประมาณ 50 ตัวที่กระจายอยู่ทั่วโลก
- ขณะยังคงโครงสร้างที่เน้นการอ่าน ก็ได้ย้ายบางเวิร์กโหลดไปยัง Azure Cosmos DB เพื่อ ลดภาระการเขียน
- ห้ามเพิ่มตารางใหม่ และเวิร์กโหลดใหม่จะถูกวางบนระบบที่ทำชาร์ดดิ้งได้เป็นค่าเริ่มต้น
ความท้าทายของโครงสร้าง single primary และการรับมือ
- โครงสร้างผู้เขียนเดี่ยวมีปัญหาเรื่อง ข้อจำกัดด้านการขยายการเขียน และ จุดล้มเหลวจุดเดียว (SPOF)
- ทราฟฟิกการอ่านถูกกระจายไปยังรีพลิกา ส่วนทราฟฟิกการเขียนย้ายเวิร์กโหลดที่ชาร์ดได้ไปยัง Cosmos DB
- ใช้การตั้งค่าความพร้อมใช้งานสูงผ่าน hot standby เพื่อรองรับการเลื่อนบทบาทอย่างรวดเร็วเมื่อเกิดเหตุขัดข้อง (failover)
- เมื่อ ภาระการอ่านพุ่งสูง เกิดปัญหา CPU เต็มจาก cache miss จำนวนมาก
- จึงนำกลไกการล็อกแคชมาใช้เพื่อป้องกันคิวรีซ้ำซ้อนกับคีย์เดียวกัน
การปรับแต่งคิวรีและทรัพยากร
- คิวรีแบบ multi-join ที่ซับซ้อน ใช้ CPU มากเกินไปจนทำให้บริการหน่วง
- มีการตรวจสอบ SQL ที่ ORM สร้างขึ้นซึ่งไม่มีประสิทธิภาพ และย้ายตรรกะ join ที่ซับซ้อนไปไว้ในชั้นแอปพลิเคชัน
- ใช้การตั้งค่า idle_in_transaction_session_timeout เพื่อป้องกันคิวรีที่ค้างว่างอยู่นาน
- เพื่อแก้ปัญหา “Noisy neighbor” จึงแยกทราฟฟิกไปยัง อินสแตนซ์ตามลำดับความสำคัญ
- เพื่อไม่ให้คำขอความสำคัญต่ำส่งผลกระทบต่อบริการความสำคัญสูง
การจัดการการเชื่อมต่อและการควบคุมโหลด
- เพื่อแก้ข้อจำกัด การเชื่อมต่อ 5,000 รายการ ของ Azure PostgreSQL จึงนำ PgBouncer มาใช้เป็นชั้นพร็อกซี
- จากการนำการเชื่อมต่อกลับมาใช้ซ้ำ ทำให้เวลาเชื่อมต่อเฉลี่ยลดลงจาก 50ms → 5ms
- เพื่อลดความหน่วงของเครือข่ายข้ามภูมิภาค จึงวางพร็อกซี ไคลเอนต์ และรีพลิกาไว้ในรีเจียนเดียวกัน
- ใช้ rate limiting ในระดับแอปพลิเคชัน พร็อกซี และคิวรี เพื่อป้องกันทราฟฟิกพุ่งอย่างฉับพลัน
- ปรับปรุงให้สามารถบล็อก query digest บางรายการได้แม้ในชั้น ORM
การจัดการรีพลิเคชันและการเปลี่ยนสคีมา
- เนื่องจาก primary ต้อง สตรีม WAL log ไปยังรีพลิกาทั้งหมด ภาระเครือข่ายจึงเพิ่มขึ้นเมื่อจำนวนรีพลิกาเพิ่มขึ้น
- ขณะนี้กำลังทดสอบ cascading replication ร่วมกับทีม Azure
- รีพลิกาตัวกลางจะส่งต่อ WAL ไปยังรีพลิการะดับล่าง ช่วยเปิดทางให้ขยายไปได้ เกิน 100 รีพลิกา
- ห้ามทำการเปลี่ยนสคีมาที่ก่อให้เกิด full table rewrite
- อนุญาตเฉพาะการเปลี่ยนแปลงแบบเบาภายใน timeout 5 วินาที และสามารถสร้างหรือลบดัชนีแบบพร้อมกันได้
- แม้ในขั้นตอน backfill ก็มีการใช้การจำกัดความเร็วอย่างเข้มงวด
ผลลัพธ์และแผนในอนาคต
- PostgreSQL รองรับ QPS ระดับหลายล้าน พร้อมทำได้ทั้ง latency ระดับหลายสิบมิลลิวินาทีที่ p99 และ ความพร้อมใช้งาน 99.999%
- ในช่วง 12 เดือนที่ผ่านมา มีเหตุการณ์ SEV-0 เพียงครั้งเดียวเท่านั้น (เกิดตอนเปิดตัว ChatGPT ImageGen)
- เวิร์กโหลดที่ยังเน้นการเขียนที่เหลืออยู่ก็กำลังทยอย ย้ายไปยัง Cosmos DB
- หลังจากทำ cascading replication เสร็จ จะเสริมทั้งความสามารถในการขยายรีพลิกาและความเสถียร
- ในอนาคตกำลังพิจารณาความเป็นไปได้ของ PostgreSQL แบบชาร์ดดิ้ง หรือ ระบบแบบกระจายทางเลือกอื่น
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ใน PostgreSQL ปัญหา คิวรีที่ idle อยู่นาน มักก่อปัญหาอยู่บ่อย ๆ
ในโค้ดเบสของบริษัทเรามีแพตเทิร์น “connect → เริ่ม transaction → ทำงาน → ถ้าสำเร็จค่อย commit” อยู่มาก
วิธีนี้ทำให้แม้จะยังไม่ได้ใช้ DB จริง ๆ ก็ยังคงยึด connection slot ไว้ตลอด จนสุดท้ายต้องเพิ่มจำนวนการเชื่อมต่อของ Postgres ไปถึงระดับหลายพัน
เลยเพิ่ม การตรวจสอบตอนคอมไพล์ ในโค้ด Rust เพื่อให้ถ้าเรียก
.awaitทั้งที่ยังถือ connection อยู่ภายใน async function คอมไพเลอร์จะเตือนทันทีแก้ไปมากกว่า 100 จุด แต่ผลคือทุกวันนี้รันโหลดเทสต์ด้วยพูล 32 ตัวแทนที่จะต้องใช้ 10,000 connections ก็ยังไม่ช้าลง
การลด idle timeout ก็เป็นวิธีหนึ่ง แต่การตรวจสอบแบบสแตติกเป็นทางแก้ที่แน่นอนกว่ามาก
บทความนี้ ผิวเผินเกินไป และเอาแต่พูดคีย์เวิร์ดแนว “เราทำ sharding แล้ว!” ซ้ำ ๆ
แทบไม่มีรายละเอียด และให้ความรู้สึกเหมือน ประโยคสำหรับ SEO
ใจความของบทความสรุปได้ประมาณว่า “writer เดี่ยวขยายไม่ออก เลยลดงานเขียนแล้วแยกงานอ่าน”
แทบไม่มีอะไรใหม่ และพูดถึงแค่วิธีที่ใช้กันทั่วไปอย่าง query optimization, sharding, read replica
เหตุผลที่ฉันชอบ Postgres คือ แค่ เพิ่ม CPU และดิสก์ ก็รับโหลดได้ถึงสเกลค่อนข้างใหญ่แล้ว
พอถึงจุดนั้นก็มีกำลังพอจะจ้างผู้เชี่ยวชาญด้าน sharding ได้
เพราะงั้นคำพูดที่ว่า “ถ้าจะ sharding ต้องออกจาก Postgres” ฟังดูแปลก ๆ
อย่างเช่น OpenAI ตอนนี้ก็ยัง ขาดทุนมหาศาล อยู่ และก็มีข่าวว่าพวกเขาอาจไม่แน่ว่าจะอยู่รอดถึงปี 2027 หรือไม่
เรื่อง การเปลี่ยน schema และ timeout นั้น ไม่ใช่แค่ตั้ง timeout อย่างเดียว
ถ้ารัน สคริปต์ที่คอยปิด transaction ที่ชนกันอัตโนมัติ ระหว่าง rollout schema ไปพร้อมกันจะมีประสิทธิภาพกว่ามาก
ถ้า Postgres มีฟีเจอร์นี้มาให้เลยก็คงดี — เพราะแทนที่จะปล่อยให้รอ heavy lock การยกเลิกบาง transaction จะคุ้มกว่ามาก
น่าสนใจที่นี่เป็นบทความแรกของบล็อก OpenAI Engineering
อยากเห็นเคสแบบนี้เพิ่มเติมในอนาคต
มีคนสงสัยเรื่องการตั้งค่า replication
เขาบอกว่ามี read replica 50 ตัวและ แทบไม่มี replication lag
แต่ในทางปฏิบัติ มีโอกาสสูงที่ replica บางตัวจะหน่วงเพราะ CPU หรือหน่วยความจำพุ่ง
ถ้าเป็นแบบนั้น primary เองก็อาจช้าลงจากการ รอส่ง WAL ได้
มีช่วงหนึ่งที่บอกว่า “ถ้าฟีเจอร์ใหม่ต้องใช้ตารางเพิ่ม จะเอาไปไว้ใน Azure CosmosDB แทน PostgreSQL”
หมายความว่าดูเหมือนจะคงระบบเดิมไว้ แล้วค่อยย้ายเฉพาะฟีเจอร์ใหม่ไปอีกฐานข้อมูล
เขาพูดว่า “เพิ่มขนาด instance” แต่ก็มีคนอยากรู้ว่าระดับไหน
ใช้ CPU·RAM อะไร เป็น instance แบบเดียวกับผู้ใช้ทั่วไป หรือเป็น ฮาร์ดแวร์แบบปรับแต่งพิเศษ
ตัวอย่างเช่น Azure Standard_E192ibds_v6 (96 คอร์, RAM 1.8TB, SSD 10TB, 3M IOPS)
ที่ใหญ่กว่านั้นก็มีรุ่นอย่าง Standard_M896ixds_24_v3 สำหรับ SAP HANA ที่ให้ 896 คอร์, หน่วยความจำ 32TB, เครือข่าย 185Gbps
พวกนี้ราคาประมาณ 175,000 ดอลลาร์ต่อเดือน แต่ OpenAI น่าจะได้ ส่วนลดก้อนใหญ่
ส่วนตัวแล้วฉันชอบใช้ VM ตระกูล HX176rs สำหรับงานเซิร์ฟเวอร์ฐานข้อมูลมากกว่า
เพราะมี HBM cache ทำให้ memory throughput สูงกว่ามาก และให้ประสิทธิภาพดีกว่า VM ทั่วไปในช่วงราคาใกล้กันมาก
การใช้ Azure PostgreSQL คู่กับ CosmosDB น่าจะมี ค่าใช้จ่ายมหาศาล
ถึงอย่างนั้นบทความนี้ก็ยังถือว่าเป็นหนึ่งในกรณี “การขยาย PostgreSQL ในโลกจริง” ที่ดูสมจริงที่สุด
เป็นแนวทางที่รันบน สภาพแวดล้อมคลาวด์มาตรฐาน โดยไม่ต้องแก้เคอร์เนลหรือแฮ็กซอร์สโค้ด จึงรู้สึกเข้าถึงได้