44 คะแนน โดย darjeeling 2026-01-23 | 2 ความคิดเห็น | แชร์ทาง WhatsApp

สรุป:

  • OpenAI กำลังรองรับหลายล้าน QPS และผู้ใช้ 800 ล้านคนด้วย Primary เพียงตัวเดียวและ Read Replica ราว 50 ตัว (Azure Flexible Server)
  • เพื่อกระจายภาระการเขียน เวิร์กโหลดที่สามารถทำชาร์ดดิ้งได้ถูกย้ายไปยัง Azure Cosmos DB และมีการปรับแต่งการเขียนในระดับแอปพลิเคชันด้วยวิธีอย่าง 'Lazy Write'
  • มีการนำ PgBouncer มาใช้เพื่อลดเวลาแฝงของการเชื่อมต่อจาก 50ms เหลือ 5ms และได้ติดตั้งกลไก Cache Locking เพื่อป้องกันพายุ cache miss
  • รับประกันความเสถียรด้วยการตัดคิวรี join ที่ซับซ้อน การตั้ง timeout ที่เข้มงวดสำหรับการเปลี่ยนสคีมาไม่เกิน 5 วินาที และการแยกเวิร์กโหลดตามลำดับความสำคัญของทราฟฟิก

สรุปแบบละเอียด:
1. ภูมิหลังและสถานะสถาปัตยกรรม
ทราฟฟิก PostgreSQL ของ OpenAI เพิ่มขึ้นมากกว่า 10 เท่าในช่วง 1 ปีที่ผ่านมา และปัจจุบันรองรับผู้ใช้ 800 ล้านคนกับหลายล้าน QPS (จำนวนคิวรีต่อวินาที) ได้แล้ว ที่น่าทึ่งคือระบบขนาดนี้ทำงานอยู่บนโครงสร้างที่มี Primary เพียงตัวเดียว และ Read Replica ประมาณ 50 ตัวที่กระจายอยู่ทั่วโลก เพื่อป้องกันไม่ให้รอยร้าวของการออกแบบยุคแรกขยายตัว OpenAI ได้ทำการปรับแต่งครั้งใหญ่ทั้งในชั้นอินฟราสตรักเจอร์และชั้นแอปพลิเคชัน

2. การแก้คอขวดหลักและกลยุทธ์การปรับแต่ง

  • การกระจายภาระการเขียน (Write):

    • โครงสร้าง Writer เดียวของ PostgreSQL มีข้อจำกัดด้านการขยายระบบ และยังมีปัญหา write amplification จาก MVCC (การควบคุมการทำงานพร้อมกันแบบหลายเวอร์ชัน)
    • แนวทางแก้คือย้ายเวิร์กโหลดที่เน้นการเขียนและสามารถแบ่งแบบชาร์ดดิ้งในแนวนอนได้ไปยังระบบอย่าง Azure Cosmos DB
    • สำหรับ PostgreSQL เดิม มีการห้ามสร้างตารางใหม่ พร้อมทั้งลดภาระของ Primary ให้เหลือน้อยที่สุดผ่านการแก้บั๊กในแอปพลิเคชันและการนำ Lazy Write มาใช้ (หน่วงการเขียนเพื่อทำให้ทราฟฟิกที่พุ่งสูงราบเรียบลง)
  • การปรับแต่งคิวรีและการจัดการ ORM:

    • ในอดีตเคยมีกรณีที่คิวรีซึ่ง join 12 ตารางทำให้เกิดเหตุขัดข้องระดับ SEV ดังนั้นจึงหลีกเลี่ยง multi-join ที่ซับซ้อนและแยกตรรกะไปไว้ในแอปพลิเคชันแทน
    • มีการตรวจสอบคิวรีที่ ORM สร้างขึ้นซึ่งไม่มีประสิทธิภาพอย่างต่อเนื่อง และใช้การตั้งค่า idle_in_transaction_session_timeout เพื่อไม่ให้คิวรีที่ค้างเฉยไปบล็อก Autovacuum
  • Connection Pooling (PgBouncer):

    • เพื่อป้องกันข้อจำกัดด้านจำนวนการเชื่อมต่อของ Azure PostgreSQL (5,000 การเชื่อมต่อ) และการถาโถมของการเชื่อมต่อ จึงได้ติดตั้ง PgBouncer เป็นชั้นพร็อกซี
    • ใช้โหมด transaction/statement pooling เพื่อเพิ่มการนำการเชื่อมต่อกลับมาใช้ซ้ำ และลดเวลาเชื่อมต่อเฉลี่ย จาก 50ms เหลือ 5ms
  • การป้องกัน cache miss (Cache Locking):

    • เพื่อป้องกันปัญหา Thundering Herd ที่คำขอจำนวนมากแห่เข้าหา DB พร้อมกันเมื่อแคชหมดอายุ จึงได้นำกลไก cache lock (leasing) มาใช้
    • เมื่อเกิด cache miss กับคีย์ใดคีย์หนึ่ง จะมีเพียงคำขอเดียวที่ได้สิทธิ์เข้าถึง DB (lock) เพื่อรีเฟรชข้อมูล ส่วนคำขออื่นจะรออยู่ ทำให้สามารถกันภาระที่ถาโถมใส่ DB ได้

3. นโยบายด้านความเสถียรและการปฏิบัติการ

  • การบรรเทาจุดล้มเหลวเพียงจุดเดียว (SPOF): แม้ Primary จะล่ม คำขออ่านก็ยังประมวลผลผ่าน Replica ได้ ทำให้ลดระดับความรุนแรงของเหตุขัดข้องลง ขณะเดียวกัน Primary ทำงานในโหมด High Availability (HA) โดยคง Hot Standby ไว้เพื่อให้ failover ได้อย่างรวดเร็ว
  • การแยกเวิร์กโหลด: เพื่อป้องกันปัญหา 'Noisy Neighbor' ทราฟฟิกจะถูกส่งไปยังอินสแตนซ์ที่แยกกันตามระดับความสำคัญ (Low/High Priority)
  • การจัดการสคีมาอย่างเข้มงวด: การเปลี่ยนแปลงที่ทำให้เกิดการเขียนตารางใหม่ทั้งก้อน (Full Table Rewrite) ถูกห้าม และเมื่อต้องเปลี่ยนสคีมา จะใช้ timeout ที่เข้มงวด 5 วินาที เพื่อป้องกันความหน่วงของบริการ

4. แผนในอนาคต (The Road Ahead)
แม้โครงสร้างปัจจุบันจะมีความสามารถในการขยายระบบเพียงพอแล้ว แต่เพื่อรองรับการเพิ่มจำนวน Read Replica ในอนาคต ขณะนี้กำลังทดสอบ Cascading Replication ซึ่งเปลี่ยนจากโครงสร้างที่ Primary ส่ง WAL ไปยัง Replica ทุกตัว มาเป็นการให้ Replica ชั้นกลางส่ง WAL ต่อไปยังชั้นล่าง ในระยะยาวยังมีการพิจารณาเรื่องชาร์ดดิ้งของ PostgreSQL เองด้วย

2 ความคิดเห็น

 
jaemkim 2026-01-26

สรุปการถกเถียงบน Hacker News: https://news.ycombinator.com/item?id=46725300

ความยิ่งใหญ่ของอินสแตนซ์เดี่ยว: หลายคนมองว่าการรองรับทราฟฟิกระดับ 800 ล้านผู้ใช้ด้วย Postgres (Write) เพียงตัวเดียวโดยไม่ทำ sharding เป็นการยืนยันอีกครั้งว่า “เซิร์ฟเวอร์ DB เครื่องใหญ่ยังคงเป็นมิตรของเรา (Big DB servers are your friend)” และแสดงให้เห็นว่าการขยายแนวตั้ง (Vertical Scaling) ยังใช้ได้ผลจริง

ความย้อนแย้งของ sharding vs refactoring: สำหรับช่วงที่บทความบอกว่า “ไม่ได้เลือก sharding เพราะการ refactor แอปเดิมซับซ้อนเกินไป” ก็มีทั้งมุกเหน็บและคำวิจารณ์ทำนองว่า “บริษัทที่ขาย AI สำหรับเขียนโค้ดกลับบอกว่า refactor ยากเกินเลยทำไม่ได้ ฟังดูชวนประชดดี” (ขณะเดียวกันก็มีคนปกป้องว่าหากคำนึงถึงความซับซ้อนด้านปฏิบัติการและต้นทุนการย้ายระบบที่ sharding จะนำมา การตัดสินใจนี้ก็สมเหตุสมผล)

ความน่าเสียดายเรื่องความลึกทางเทคนิค: มีบางส่วนวิจารณ์ว่าบทความค่อนข้างพูดในระดับกว้าง ๆ เช่น caching และ connection pooling ทำให้ขาดรายละเอียดเชิงวิศวกรรมที่เป็นรูปธรรม จนดู “เหมือนบทความประชาสัมพันธ์”

ประเด็นเกี่ยวกับ Rust: ในคอมเมนต์ยังมีการแชร์เทคนิคที่ใช้การตรวจสอบตอนคอมไพล์ของ Rust เพื่อป้องกันปัญหา 'Idle Transaction' ตั้งแต่ต้นทาง ทำให้เกิดการถกเถียงเชิงเทคนิคที่ลึกขึ้น แม้จะเป็นประเด็นที่แยกจากเนื้อหาหลักก็ตาม

 
jaemkim 2026-01-26

โดยส่วนตัวแล้ว ผมสนใจส่วนที่นำโครงสร้างอย่าง Cascading Replication มาใช้ หรือก้าวข้ามข้อจำกัดทางเทคนิคด้วยการปฏิบัติการจริง เกี่ยวกับเรื่องนี้ผมได้เรียบเรียงความคิดของตัวเองไว้ยาวกว่านี้ใน Facebook ครับ https://www.facebook.com/share/p/1Kp8V917bL/