vLLM คืออะไร และทำไม throughput ถึงกระโดดเมื่อย้ายมาใช้

โดย vLLM Bangkok9 นาที
Read in English

ถ้าคุณเคยย้ายโมเดลมาใช้ vLLM แล้วเห็น throughput เพิ่มขึ้นหลายเท่าโดยไม่ได้แตะตัวโมเดลเลย บทความนี้อธิบายว่ามันมาจากไหน

มีสองแนวคิดที่ทำงานหลัก

1. คอขวดคือ KV cache ไม่ใช่การคำนวณ

ตอนโมเดลสร้างข้อความ มันจะเก็บ KV cache — attention key และ value ของทุก token ที่ผ่านมา — เพื่อไม่ต้องคำนวณ prefix ใหม่ทั้งหมดในทุก token ที่สร้าง cache นี้ใหญ่ และโตขึ้นทุกครั้งที่สร้าง token เพิ่ม

วิธีเก็บแบบตรงไปตรงมาคือจองหน่วยความจำ GPU เป็นบล็อกต่อเนื่องหนึ่งก้อนต่อหนึ่ง request โดยจองเผื่อความยาวสูงสุดที่ request นั้นอาจสร้างได้ และนั่นคือจุดที่ความสูญเปล่าอยู่:

  • request ที่อนุญาตไว้ 2,048 token แต่หยุดที่ 100 เท่ากับจองไว้มากกว่าที่ใช้จริง 20 เท่า
  • หน่วยความจำที่จองแล้วไม่ได้ใช้ ให้ request อื่นยืมไม่ได้
  • คุณต้องออกแบบทั้งเซิร์ฟเวอร์เผื่อกรณีแย่สุด ทำให้ concurrency ต่ำอยู่ตลอด

ทีมส่วนใหญ่เจอปัญหานี้ในรูป “GPU ยังมีหน่วยความจำว่างเยอะ แต่พอเพิ่ม concurrency แล้ว out-of-memory”

2. PagedAttention: มองหน่วยความจำ GPU แบบ virtual memory

ไอเดียหลักของ vLLM ยืมมาจากระบบปฏิบัติการ แทนที่จะจองพื้นที่ต่อเนื่องก้อนเดียวต่อ request มันแบ่ง KV cache เป็น บล็อก ขนาดคงที่ แล้วใช้ block table แมปตำแหน่ง token เชิงตรรกะของแต่ละ request ไปยังบล็อกจริงที่อยู่ตรงไหนของหน่วยความจำก็ได้

ผลที่ตามมาเห็นได้ทันที:

  • แทบไม่มี internal fragmentation request ใช้บล็อกไปเรื่อย ๆ ตามที่สร้างจริง ไม่ใช่จองล่วงหน้า ความสูญเปล่าเหลืออย่างมากแค่บล็อกที่ยังเติมไม่เต็มหนึ่งบล็อกต่อ sequence
  • การแชร์แทบไม่มีต้นทุน request สองอันที่มี prefix เดียวกัน — system prompt ร่วม, few-shot preamble, เอกสาร RAG — สามารถชี้ไปที่บล็อกจริง เดียวกัน แทนที่จะเก็บสองชุด สำหรับงานที่มี prefix ยาวคงที่ แค่ข้อนี้ก็ช่วยได้มาก
  • concurrency สูงขึ้น ใส่ request ได้มากขึ้นบนการ์ดใบเดิม ซึ่งคือที่มาจริง ๆ ของตัวเลข throughput

ชื่อก็มาจากตรงนี้ตรง ๆ: paging ที่เอามาใช้กับ attention

3. Continuous batching: เลิกรอ request ที่ช้าที่สุด

แนวคิดที่สองเป็นเรื่องการจัดคิว static batching แบบดั้งเดิมจะรวบ request N อัน รันพร้อมกัน แล้วคืนผลเมื่อครบทั้ง N เสร็จ ในเมื่อความยาวการสร้างต่างกันมาก batch จึงเดินด้วยความเร็วของตัวที่ช้าที่สุด และ GPU ก็นั่งว่างในช่องที่เสร็จไปแล้ว

Continuous batching ทำงานที่ระดับ iteration แทน หลังจบ decoding step แต่ละครั้ง scheduler สามารถเอา sequence ที่เสร็จแล้วออกและรับตัวที่รออยู่เข้ามาได้ทันที batch จึงถูกเติมต่อเนื่อง แทนที่จะรอให้หมดแล้วค่อยเติมใหม่

สำหรับทราฟฟิกที่ปนกัน — บาง request อยากได้ 20 token บางอันอยากได้ 2,000 — นี่คือความต่างระหว่าง GPU ที่ทำงานอยู่กับ GPU ที่นั่งรอ

แล้วในทางปฏิบัติหมายความว่าอย่างไร

มีข้อสรุปบางอย่างที่ควรเข้าใจก่อนจะไปจูนอะไร

throughput กับ latency เป็นลูกบิด ไม่ใช่ค่าคงที่คู่กัน sequence ที่รันพร้อมกันมากขึ้น = token ต่อวินาทีรวมสูงขึ้น และ latency ต่อ request สูงขึ้น ต้องตัดสินใจว่าโปรดักต์ของคุณจ่ายเงินเพื่ออะไรกันแน่

prefix ร่วมที่ยาวคุ้มค่าที่จะออกแบบเผื่อ ถ้าทุก request แบก system prompt เดียวกัน 800 token การแชร์ prefix กำลังทำงานให้คุณอยู่จริง ๆ รักษาส่วนที่ใช้ร่วมกันให้เหมือนกันระดับไบต์และวางไว้ข้างหน้า — การใส่ timestamp รายคำขอไว้ตำแหน่งแรกทำลายการแชร์นี้ไปเงียบ ๆ

--max-model-len คือการตัดสินใจเรื่องหน่วยความจำ มันกำหนดขอบเขต KV cache ต่อ sequence และจึงกำหนดว่ากี่ sequence จะอยู่พร้อมกันได้ การตั้งไว้เท่าค่าสูงสุดของโมเดล “เผื่อไว้ก่อน” คือการตัด concurrency ของตัวเองแบบเงียบ ๆ

จับตาดู preemption เมื่อหน่วยความจำหมด vLLM จะ preempt แล้วค่อยคำนวณใหม่หรือ swap sequence กลับมา ตัวเลข preemption ที่ไต่ขึ้นใน metrics แปลว่าคุณรับงานเกินตัว — นั่นคือสัญญาณให้ลด concurrency หรือเพิ่มหน่วยความจำ ก่อนที่ latency พุ่งจะไปโผล่เป็นคำร้องเรียนจากผู้ใช้

สำหรับงานภาษาไทยโดยเฉพาะ

มีรายละเอียดหนึ่งที่ทีมในบ้านเรามักสะดุด: ภาษาไทย tokenize ได้ไม่ดีในโมเดล multilingual ส่วนใหญ่ ภาษาไทยไม่มีช่องว่างระหว่างคำ และ tokenizer ที่เทรนด้วยภาษาอังกฤษเป็นหลักมักออกมาเป็นหนึ่ง token ต่อหนึ่งอักขระหรือต่อกลุ่มสั้น ๆ prompt ภาษาไทยจึงกิน token มากกว่าคำแปลภาษาอังกฤษที่ความหมายเท่ากันอย่างเห็นได้ชัด

และมันกระทบทุกอย่างที่เล่ามาข้างบนโดยตรง — token ต่อ request มากขึ้น แปลว่า KV cache ต่อ request มากขึ้น แปลว่า sequence ที่รันพร้อมกันได้บนการ์ดใบเดิมน้อยลง ถ้าคุณตั้งงบหน่วยความจำ GPU จาก benchmark ภาษาอังกฤษแต่เสิร์ฟทราฟฟิกภาษาไทย วัดจำนวน token จริงของคุณก่อนกำหนดขนาด deployment

อ่านต่อ

  • repository ของ vLLM และเอกสารประกอบ
  • เปเปอร์ PagedAttention: Efficient Memory Management for Large Language Model Serving with PagedAttention
  • และในวันที่ 6 กันยายน ถาม maintainer ได้โดยตรงที่ vLLM Bangkok Day — คนที่เขียนมันเอง

แท็ก

  • vllm
  • inference
  • พื้นฐาน

บทความอื่น

6 นาที

vLLM Bangkok Day: ผู้สร้าง vLLM กำลังจะมากรุงเทพฯ

วันที่ 6 กันยายน 2569 ทีมผู้สร้าง vLLM จะมากรุงเทพฯ พร้อมกับหนึ่งบ่ายเต็มของ การพูดคุยเรื่อง inference บนงานจริง เคสจากทีมไทย และการพบปะสร้างเครือข่าย เข้าร่วมฟรี — นี่คือสิ่งที่จะได้เจอ

  • งานอีเวนต์
  • คอมมูนิตี้