14 คะแนน โดย GN⁺ 2024-11-08 | 3 ความคิดเห็น | แชร์ทาง WhatsApp
  • recall เป็นบริการที่ให้บอตสำหรับการประชุมแก่บริษัทหลายร้อยแห่ง และดำเนินโครงสร้างพื้นฐานขนาดใหญ่บน AWS
  • เพื่อให้บริการมีประสิทธิภาพด้านต้นทุน จึงพยายามใช้ประโยชน์จากสมรรถนะของฮาร์ดแวร์ให้ได้มากที่สุด
  • ตลอดหลายปีที่ผ่านมา ความพร้อมใช้งานของ GPU จากผู้ให้บริการคลาวด์ไม่เสถียร จึงประมวลผลวิดีโอบน CPU แทน GPU
  • เมื่อลองทำโปรไฟล์บอตที่ใช้ headless Chromium พบว่าเวลาส่วนใหญ่ของ CPU ไม่ได้ถูกใช้ไปกับการประมวลผลวิดีโอ (encoding/decoding) แต่ถูกใช้ไปกับฟังก์ชันคัดลอกหน่วยความจำ __memmove_avx_unaligned_erms และ __memcpy_avx_unaligned_erms
    • memmove และ memcpy คือฟังก์ชันคัดลอกบล็อกหน่วยความจำใน C standard library (glibc)
    • memmove รองรับกรณีพิเศษบางอย่างที่เกี่ยวข้องกับการคัดลอกหน่วยความจำในช่วงที่ทับซ้อนกัน แต่ทั้งสองฟังก์ชันก็จัดอยู่ในกลุ่มฟังก์ชัน "คัดลอกหน่วยความจำ" ได้เหมือนกัน
    • suffix avx_unaligned_erms หมายถึงการปรับแต่งให้เหมาะกับระบบที่รองรับ Advanced Vector Extensions (AVX) และยังเหมาะกับการเข้าถึงหน่วยความจำที่ไม่จัดแนวด้วย
    • erms ย่อมาจาก Enhanced REP MOVSB/STOSB ซึ่งเป็นการปรับแต่งสำหรับการย้ายหน่วยความจำอย่างรวดเร็วบนโปรเซสเซอร์ Intel รุ่นใหม่ พูดง่าย ๆ คือหมายถึง "implementation ที่เร็วขึ้นสำหรับโปรเซสเซอร์บางประเภท"
  • จากผลการทำโปรไฟล์ พบว่าตัวที่เรียกใช้ฟังก์ชันเหล่านี้มากที่สุดคือ Python WebSocket client ที่รับข้อมูล
    • รองลงมาคือ implementation ของ WebSocket ใน Chromium ที่ใช้ส่งข้อมูล

ปัญหาของ WebSocket

  • ใช้ WebSocket server ภายในเครื่องเพื่อส่งข้อมูลวิดีโอดิบจากสภาพแวดล้อม JS ของ Chromium ไปยัง encoder
  • สตรีมวิดีโอดิบ 1080p 30fps ต้องใช้แบนด์วิดท์สูงกว่า 93MB ต่อวินาที
  • การใช้ WebSocket ทำให้เกิดต้นทุนการประมวลผลสูง โดยสาเหตุหลักคือ fragmentation และ masking
    • fragmentation: implementation ของ WebSocket ใน Chromium จะแยกข้อความที่มีขนาดเกิน 131KB ออกเป็นหลายเฟรม ทำให้เฟรมวิดีโอดิบขนาดมากกว่า 3MB ถูกแบ่งส่งเป็นเฟรมแยกมากกว่า 24 เฟรม
    • masking: ด้วยเหตุผลด้านความปลอดภัย WebSocket จะทำ masking กับทุกเฟรมที่ส่งจาก client ไป server ซึ่งกลายเป็น overhead ที่มีนัยสำคัญเมื่อข้อมูลมีขนาดเกิน 100MB ต่อวินาที

การมองหาทางเลือก

  • เนื่องจากใช้เพียง browser API แล้วทำสิ่งที่มีประสิทธิภาพสูงกว่า WebSocket ได้ยากมาก จึงตัดสินใจ fork Chromium เพื่อใส่ฟังก์ชันแบบกำหนดเอง
  • พิจารณาทางเลือก 3 แบบ: raw TCP/IP, Unix Domain Socket, Shared Memory
    • TCP/IP: แม้จะหลีกเลี่ยงปัญหา fragmentation/masking ของ WebSocket ได้ แต่ขนาดแพ็กเก็ตสูงสุดยังเล็ก จึงยังมีปัญหา fragmentation อยู่ และยังมี overhead จากการคัดลอกข้อมูลเข้าสู่ kernel space
    • Unix Domain Socket: ข้าม network stack ได้ทั้งหมด แต่ยังต้องคัดลอกข้อมูลระหว่าง user space กับ kernel space
    • Shared Memory: หน่วยความจำที่หลายโปรเซสเข้าถึงพร้อมกันได้ โดย Chromium เขียนลง shared memory ได้โดยตรง และ encoder ก็อ่านได้ทันทีโดยไม่ต้องคัดลอกระหว่างทาง

การทำ transmission บน shared memory

  • ใช้โครงสร้างแบบ ring buffer เพื่อให้อ่านและเขียนข้อมูลต่อเนื่องบน shared memory ได้
  • ข้อกำหนด: lock-free, multi-producer/single-consumer, ขนาดเฟรมแปรผัน, zero-copy read, เป็นมิตรกับ sandbox, และ low-latency signaling
  • มีการประเมิน implementation ของ ring buffer ที่มีอยู่แล้ว แต่ไม่พบตัวที่ตอบโจทย์ทั้งหมด จึงตัดสินใจทำเอง
  • เพื่อรองรับ zero-copy read จึงแยก pointer ออกเป็น 3 ตัวคือ write, peek, read
  • เพื่อความปลอดภัยด้านเธรด ใช้ atomic operation และใช้ named semaphore เพื่อแจ้งว่ามีข้อมูลใหม่หรือมีพื้นที่ว่างพร้อมใช้งาน
  • ด้วย implementation ของ ring buffer บน shared memory และการปรับแต่งอื่น ๆ ทำให้ลดการใช้ CPU ของบอตได้สูงสุดถึง 50% และสุดท้ายก็ลดค่าใช้จ่าย AWS ได้มากกว่า 1 ล้านดอลลาร์ต่อปี

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

 
GN⁺ 2024-11-08
ความคิดเห็นบน Hacker News
  • เป็นเรื่องราวแบบฉบับของสตาร์ทอัพที่เลือกทางลัดแบบ "ดีพอใช้" แล้วค่อยไปปรับแต่งทีหลัง

    • ที่บริษัทแห่งหนึ่งมีคลัสเตอร์ VM ที่ใช้ CPU สูง และใช้ profiler เพื่อหาวิธีปรับแต่ง
    • ลบข้อมูลเก่าและเพิ่มตัวกรองในคิวรีเพื่อลดการใช้ CPU
  • มีความเห็นว่าปริมาณแบนด์วิดท์ของข้อมูลวิดีโอดิบนั้นสูงจนน่าตกใจ

    • วิจารณ์การตัดสินใจออกแบบของ WebSockets ว่าไม่ได้คาดการณ์ปัญหาการใช้ CPU
  • มีความเห็นว่านี่ไม่ใช่ปัญหาของ AWS แต่เป็นปัญหาของการสิ้นเปลือง CPU cycle

    • WebSockets เกี่ยวข้องกับค่าใช้จ่ายด้านการส่งข้อมูลหรือ API gateway
  • ชี้ให้เห็นว่า MTU และ MSS ของเครือข่าย TCP/IP มีขนาดเล็กเมื่อเทียบกับขนาดเฟรมวิดีโอ

    • ระบุว่าทีมขาดความรู้ทางเทคนิคและควรจ้างนักพัฒนาเพิ่ม
  • มีความเห็นว่าสามารถใช้ Mojo ของ Chromium ได้โดยไม่ต้องกังวลกับโค้ดเฉพาะแต่ละแพลตฟอร์ม

    • และมองว่าการทำ ring buffer แบบคัสตอมก็ใช้ได้เช่นกัน
  • มีความเห็นว่าปัญหาไม่ใช่เรื่องเครือข่าย แต่เป็นการขาดความเข้าใจเกี่ยวกับวิดีโอ codec

    • บอกว่าไม่เข้าใจว่าทำไมถึงไม่ใช้โปรโตคอลสตรีมมิงวิดีโออย่าง RDP
  • ชื่นชมความโปร่งใส และอยากเห็นความโปร่งใสเรื่องราคาสินค้าด้วย

  • อธิบายว่าการ masking ของโปรโตคอล WebSocket เป็นความพยายามในการแก้ปัญหาคนกลาง

    • และบอกว่า RFC ที่เกี่ยวข้องนั้นคุ้มค่าแก่การอ่าน
  • ชี้ว่าวิธีส่งข้อมูลวิดีโอโดยไม่บีบอัดนั้นดูแปลก

    • บอกว่าไม่เข้าใจว่าทำไมถึงไม่ส่งสตรีมที่บีบอัดแล้ว
  • ระบุว่าแนวทางเริ่มต้นที่ส่งวิดีโอดิบผ่าน WebSocket นั้นน่าประหลาดใจ

    • และบอกว่าความไม่มีประสิทธิภาพก็ไม่ได้ขัดขวางการพัฒนาผลิตภัณฑ์
    • พร้อมตั้งข้อสงสัยว่าเหตุใดจึงใช้แนวทางที่ไม่คำนึงถึงปริมาณข้อมูล
 
ahwjdekf 2024-11-09
  • ดูเหมือนว่าในการพัฒนาผลิตภัณฑ์ แทบไม่ได้คำนึงถึงประสิทธิภาพเลย
  • สุดท้ายแล้วปัญหานี้ก็ลงเอยที่ประเด็นว่าจะทำ IPC กับข้อมูลปริมาณมหาศาลอย่างไร
  • ความต่างคือไม่ใช่ IPC แบบทั่วไป แต่เป็นการทำ IPC กับเบราว์เซอร์ Chrome
  • วิธีการภายในของเบราว์เซอร์ Chrome อาจไม่ง่ายนัก แต่เปิดเผยอยู่ จึงสามารถแก้ไขได้
  • ถ้าอย่างนั้นสุดท้ายก็เป็นปัญหาเรื่องการเลือก IPC

สรุปคือตั้งแต่แรกก็พัฒนากันมาผิดแล้วนี่นา..

 
ahwjdekf 2024-11-09

"แนวทางเริ่มต้นที่ส่งวิดีโอดิบผ่าน WebSocket นั้นน่าทึ่งจริง ๆ" เห็นด้วยกับคำพูดนี้