28 คะแนน โดย GN⁺ 2025-05-05 | 4 ความคิดเห็น | แชร์ทาง WhatsApp
  • Discord ต้องการก้าวข้ามข้อจำกัดของโครงสร้างพื้นฐานการค้นหาเดิมที่อิงกับ Elasticsearch จึง ออกแบบสถาปัตยกรรมใหม่ทั้งหมดบน Kubernetes และปรับปรุงทั้งประสิทธิภาพและความเสถียรของการทำดัชนีข้อความอย่างก้าวกระโดด
  • คิว Redis แบบเดิมมีความเสี่ยงต่อการสูญหายของข้อความ แต่เมื่อ เปลี่ยนมาใช้ PubSub จึงรับประกันการส่งต่อข้อความได้อย่างเสถียร พร้อมทั้งแยกจัดการข้อความตามคลัสเตอร์/ดัชนีเพื่อประมวลผลได้อย่างมีประสิทธิภาพ
  • มีการนำสถาปัตยกรรม "cell" มาใช้ เพื่อกระจายงานไปยัง คลัสเตอร์ Elasticsearch ขนาดเล็กจำนวนมาก แก้ปัญหาโหนดโอเวอร์โหลดและปัญหาที่ไม่สามารถอัปเดตได้
  • ข้อความ DM ส่วนตัวและข้อความในเซิร์ฟเวอร์ (guild) ถูก ทำดัชนีแยกกันคนละ cell และกลายเป็นรากฐานของ ฟีเจอร์ค้นหา DM ทั้งหมด ที่เพิ่งเปิดตัว
  • สำหรับคอมมูนิตี้ขนาดใหญ่มาก (BFGs) ใช้ cell เฉพาะทางและดัชนีแบบหลาย shard เพื่อให้ ขยายระบบได้เกินข้อจำกัดจำนวนข้อความสูงสุดของ Lucene

ข้อจำกัดของโครงสร้างพื้นฐานเดิม

  • คิวข้อความที่ใช้ Redis มีคอขวดเมื่อโหนด Elasticsearch ขัดข้อง และมีความเป็นไปได้ที่ข้อความจะสูญหาย
  • คลัสเตอร์ขนาดใหญ่ (200+ โหนด) มีอัตราความล้มเหลวของการทำดัชนีทั้งระบบสูงถึง 40% จากความขัดข้องของโหนดเพียงตัวเดียว
  • ดัชนีที่ชนข้อจำกัด MAX_DOCS ของ Lucene (2 พันล้านข้อความ) จะ ทำให้การทำดัชนีหยุดลงโดยสมบูรณ์
  • ด้วยความที่ระบบเก่ามาก แม้แต่การแพตช์ log4shell ก็ทำได้ก็ต่อเมื่อต้องปิดระบบทั้งหมดก่อน

กลยุทธ์ในการแก้ปัญหา

สร้างใหม่บน Kubernetes

  • ใช้ Elastic Kubernetes Operator (ECK) เพื่อทำงานอัตโนมัติในการดูแลคลัสเตอร์ Elasticsearch
  • ทำให้ rolling restart รวมถึงการอัปเกรด OS และซอฟต์แวร์สามารถทำได้อย่างปลอดภัย

กระจายคลัสเตอร์ด้วยสถาปัตยกรรม “cell”

  • แทนที่จะใช้คลัสเตอร์เดี่ยวขนาดใหญ่แบบเดิม ก็เปลี่ยนมาเป็น หลายคลัสเตอร์ขนาดเล็กที่รวมกันเป็นหนึ่ง cell
  • ภายในแต่ละ cell จะ จำกัดจำนวนดัชนี และคุมขนาด shard ไว้ที่ 50GB และไม่เกิน 200 ล้านข้อความ
  • ช่วย เพิ่มประสิทธิภาพทั้งการทำดัชนีและการ query และลดภาระในการรักษาสถานะของคลัสเตอร์

คิวข้อความบน PubSub

  • การเปลี่ยนจาก Redis → PubSub ทำให้ สามารถคงคิวไว้ได้โดยไม่สูญหายของข้อความ
  • กำลังขยายการใช้ PubSub ไปยังฟังก์ชันอื่น ๆ ด้วย (เช่น การตั้งเวลา job)

การทำ batch indexing แยกตามคลัสเตอร์

  • ข้อความที่รับจาก PubSub จะถูก แยกตามคลัสเตอร์และดัชนีเป้าหมาย ก่อนส่งเป็น task แยกเพื่อประมวลผลแบบขนาน
  • สร้างโครงสร้างกระจายการประมวลผลข้อความด้วย tokio task + channel ของ Rust

การปรับปรุงความสามารถในการค้นหา

การค้นหา DM ตามผู้ใช้

  • เดิมที DM ถูกทำดัชนีในระดับช่องทาง จึง ค้นหา DM ทั้งหมดได้อย่างไม่มีประสิทธิภาพ
  • ตอนนี้ ทำดัชนีข้อความ DM แบบซ้ำลงในดัชนีรายผู้ใช้ ทำให้ค้นหา DM ทั้งหมดได้ในครั้งเดียว

รองรับ BFG (Big Freaking Guilds)

  • นำดัชนีแบบหลาย shard มาใช้สำหรับคอมมูนิตี้ขนาดใหญ่มากที่เกินข้อจำกัดจำนวนข้อความของ Lucene
  • BFG จะถูก ประมวลผลด้วยโครงสร้างหลาย primary shard บน Elasticsearch cell เฉพาะทาง
  • ทำดัชนีซ้ำทั้งในดัชนีเดิมและดัชนีใหม่พร้อมกัน ก่อนค่อย ๆ ย้ายเป้าหมายของการ query ไปยังระบบใหม่

ผลลัพธ์

  • ทำดัชนีข้อความระดับหลายล้านล้านข้อความ และมี throughput ในการทำดัชนีเพิ่มขึ้น 2 เท่า เมื่อเทียบกับเดิม
  • ความเร็วตอบสนองของ query: ค่าเฉลี่ย 500ms → 100ms, p99 จาก 1s → ต่ำกว่า 500ms
  • ขณะนี้ดูแล คลัสเตอร์มากกว่า 40 ชุดและดัชนีหลายพันรายการ
  • การอัปเกรดคลัสเตอร์และ rolling restart ถูก ทำให้เป็นอัตโนมัติทั้งหมดและไม่มี downtime ของบริการ

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

 
mhj5730 2025-05-08

ที่ทำงานนี้ไปพร้อมกับการให้บริการจริงได้ด้วย... น่านับถือจริง ๆ ครับ

 
ethanhur 2025-05-08

วิศวกรรมของ Discord เป็นแบบอย่างที่ดีเสมอเลย น่าอิจฉาจังครับ

 
jujumilk3 2025-05-07

นึกว่า pubsub คืออะไร ที่แท้ก็เป็น IaaS ที่ GCP ให้บริการนี่เอง

https://cloud.google.com/pubsub?hl=en

 
mssmss 2025-05-05

น่าประทับใจมาก ทั้งการยกเครื่องใหม่เพื่อแก้ปัญหาด้วย