SSD Nodes Learn Hosting plans →
คู่มือ Matt Connorโดย Matt Connor

วิธีตั้งค่า OLLAMA_NUM_PARALLEL และ OLLAMA_MAX_QUEUE

ทำความเข้าใจการทำงานของ OLLAMA_NUM_PARALLEL และ OLLAMA_MAX_QUEUE เพื่อจัดการคิวคำขอและข้อผิดพลาด HTTP 503 พร้อมคำอธิบายว่าทำไมการเพิ่มช่องประมวลผลขนานจึงกินหน่วยความจำเครื่องเพิ่มขึ้น

เกิดอะไรขึ้นกับคำขอที่สองของ Ollama ในขณะที่คำขอแรกกำลังสร้างผลลัพธ์

การทำงานพร้อมกัน (concurrency) ของ Ollama ถูกกำหนดโดยตัวแปรสภาพแวดล้อม (environment variables) 3 ตัว โดยค่าเริ่มต้นคือโมเดลที่โหลดอยู่หนึ่งตัวจะให้บริการได้ทีละหนึ่งคำขอเท่านั้น คำขอที่สองจะไม่ถูกปฏิเสธและจะไม่ได้รับคำตอบที่ไม่สมบูรณ์ แต่จะรออยู่ในคิวจนกว่าจะมีช่องว่างว่างลง จากนั้นจึงจะประมวลผลด้วยความเร็วปกติ

คำขอที่เข้ามามีผลลัพธ์ที่เป็นไปได้ 3 รูปแบบ คือ เริ่มต้นประมวลผลทันทีในช่องว่างที่ว่างอยู่, รออยู่ในคิว, หรือคิวเต็มแล้วเซิร์ฟเวอร์ปฏิเสธด้วย HTTP 503 ผลลัพธ์ที่คุณได้รับจะถูกตัดสินโดย OLLAMA_NUM_PARALLEL, OLLAMA_MAX_QUEUE และ OLLAMA_MAX_LOADED_MODELS มีข้อควรระวังหนึ่งประการในรุ่นปัจจุบัน ณ เดือนตุลาคม 2026 คือสถานะ 503 จะใช้กับคำขอที่เข้ามาในขณะที่โมเดลยังต้องถูกโหลดเข้าหน่วยความจำเท่านั้น Ollama จะไม่ปฏิเสธคำขอสำหรับโมเดลที่โหลดอยู่แล้ว โดยคำขอนั้นจะรอช่องว่างนานเท่าที่จำเป็น

ค่าเริ่มต้นมีความปลอดภัยและเป็นสาเหตุที่ผู้ใช้คนที่สองมักรายงานว่าเซิร์ฟเวอร์ "ค้าง" ทั้งที่ไม่มีส่วนใดเสียหาย การเพิ่มช่องว่างทำได้โดยการแก้ไขบรรทัดคำสั่งเพียงสองบรรทัด ส่วนที่ส่งผลกระทบคือหน่วยความจำ ช่องว่างแบบขนาน (parallel slot) แต่ละช่องต้องการ key/value cache (KV cache) ของตนเอง ซึ่งเป็นบล็อกหน่วยความจำที่โมเดลใช้เก็บโทเค็นที่ประมวลผลไปแล้ว หากคุณเพิ่มช่องว่างโดยไม่เพิ่ม VRAM (หน่วยความจำวิดีโอบน GPU) จะทำให้การตอบสนองที่ช้ากลายเป็นการโหลดล้มเหลว สำหรับเซิร์ฟเวอร์ที่ใช้ CPU เพียงอย่างเดียว แคชดังกล่าวจะถูกดึงมาจาก RAM ของระบบแทน

การควบคุมของ OLLAMA_NUM_PARALLEL, OLLAMA_MAX_QUEUE และ OLLAMA_MAX_LOADED_MODELS

นี่คือค่าเริ่มต้นใน Ollama เวอร์ชันปัจจุบัน ณ เดือนตุลาคม 2026 โปรดตรวจสอบค่าของคุณเองแทนการเชื่อตัวเลขในที่นี้ โดยดูจากบรรทัด log ที่แสดงไว้ด้านล่าง

  • OLLAMA_NUM_PARALLEL คือจำนวนคำขอที่โมเดลหนึ่งตัวที่โหลดอยู่จะประมวลผลพร้อมกัน ค่าเริ่มต้นคือ 1 ซึ่งหมายความว่าคำขอจะถูกให้บริการทีละรายการ
  • OLLAMA_MAX_LOADED_MODELS คือจำนวนโมเดลที่แตกต่างกันที่จะคงอยู่ในหน่วยความจำพร้อมกัน ค่าเริ่มต้นคือ 0 ซึ่งหมายความว่า Ollama จะเป็นผู้เลือก: โดยกำหนดให้มีโมเดลได้ 3 ตัวต่อ GPU หนึ่งตัว และ 3 ตัวสำหรับเครื่องที่ไม่มี GPU
  • OLLAMA_MAX_QUEUE คือจำนวนคำขอที่สามารถรอคิวเพื่อจัดตารางเวลา ซึ่งในทางปฏิบัติหมายถึงการรอให้โมเดลถูกโหลดขึ้นมา ค่าเริ่มต้นคือ 512 คำขอที่เข้ามาในขณะที่คิวเต็มจะถูกปฏิเสธทันที คำขอสำหรับโมเดลที่โหลดอยู่แล้วจะข้ามคิวนี้ไปและรอช่องว่างแทน ซึ่งการรอในส่วนนี้ไม่มีการจำกัดจำนวน ผู้ดูแล Ollama ติดตามเรื่องนี้ในฐานะคำขอฟีเจอร์ (issue #7758) ซึ่งยังคงเปิดอยู่ ณ เดือนตุลาคม 2026

หน่วยความจำที่ใช้ในกรณีเลวร้ายที่สุดคือผลคูณของสองค่าแรก หากมีโมเดลที่โหลดอยู่ 2 ตัวและแต่ละตัวมี 4 ช่อง จะเท่ากับการจัดสรรช่อง KV cache ทั้งหมด 8 ช่องที่ต้องอยู่ในหน่วยความจำพร้อมกัน และ Ollama จะพยายามตอบสนองตามนั้น สำหรับเครื่องที่มี GPU ตัวเดียว โดยทั่วไปแล้วการเก็บโมเดลไว้เพียงตัวเดียวแล้วเพิ่มจำนวนช่องให้โมเดลนั้นจะดีกว่า เพราะการคำนวณจะยังคงอยู่ในระดับที่คุณสามารถคิดตามได้ง่าย

เหตุผลที่ทุก parallel slot ต้องใช้ VRAM

เมื่อ Ollama โหลดโมเดล มันจะเปิดกระบวนการ runner แยกออกมา โดยมีอาร์กิวเมนต์สองตัวที่สำคัญในที่นี้คือ -c ซึ่งเป็นบริบททั้งหมดที่ runner จัดสรร KV cache ไว้ให้ และ -np คือจำนวนลำดับงานแบบขนาน Ollama จะตั้งค่า -c ให้เท่ากับความยาวบริบทต่อคำขอของคุณคูณด้วยจำนวน slot จากนั้น runner จะแบ่งพื้นที่ทั้งหมดนั้นให้แต่ละ slot เท่าๆ กัน เพื่อให้แต่ละคำขอยังคงได้รับความยาวบริบทตามที่คุณต้องการ

นั่นคือข้อจำกัดทั้งหมด และเป็นเหตุผลว่าทำไมการทำงานแบบขนานจึงไม่มีค่าใช้จ่าย การเพิ่มจากหนึ่ง slot เป็นสี่ slot หมายถึงการต้องการ KV cache เพิ่มขึ้นสี่เท่าที่ความยาวบริบทต่อคำขอเท่าเดิม ไม่มีข้อมูลใดถูกแชร์ระหว่าง slot และส่วนแบ่งของ slot ที่ว่างอยู่ก็ไม่สามารถนำไปให้ slot ที่กำลังทำงานอยู่ยืมใช้ได้ เนื่องจากมีการแบ่งพื้นที่คงที่ไว้ตั้งแต่ตอนที่ runner เริ่มทำงาน บน GPU หน่วยความจำนี้คือ VRAM ส่วนบนเซิร์ฟเวอร์ที่ใช้ CPU เท่านั้น หน่วยความจำนี้คือ system RAM และการคูณด้วยจำนวนเท่าเดิมก็ยังคงมีผลเช่นเดียวกัน

คุณสามารถตรวจสอบตัวเลขจริงแทนตัวเลขที่คุณตั้งใจจะกำหนดได้ดังนี้:

journalctl -u ollama --no-pager -n 500 | grep "starting llama-server"

บรรทัดนั้นจะแสดงบรรทัดคำสั่งของ runner ทั้งหมด รวมถึง -c และ -np หาก -np ยังคงเป็น 1 หลังจากที่คุณตั้งค่าตัวแปรแล้ว อาจเกิดจากสองสาเหตุ สาเหตุแรกคือตัวโมเดลเอง Ollama จำกัดสถาปัตยกรรมโมเดลบางประเภทให้ใช้ได้เพียงหนึ่ง slot ไม่ว่าคุณจะตั้งค่าไว้อย่างไรก็ตาม และจะบันทึก model architecture does not currently support parallel requests ลงใน log เมื่อเกิดกรณีนี้ ณ เดือนตุลาคม 2026 รายการดังกล่าวรวมถึงตระกูล Qwen 3.5, Qwen3-VL, Qwen3-Next, LFM2 และ Nemotron-H ส่วนโมเดลประเภท embedding จะได้รับเพียงหนึ่ง slot เสมอ ให้รัน journalctl -u ollama --no-pager | grep "does not currently support parallel" เพื่อตรวจสอบ หากไม่มีคำเตือนดังกล่าวปรากฏขึ้น แสดงว่าการตั้งค่าของคุณส่งไปไม่ถึงเซิร์ฟเวอร์ ซึ่งส่วนถัดไปจะอธิบายถึงสาเหตุนี้

หากน้ำหนักของโมเดลรวมกับ KV cache ไม่สามารถบรรจุลงใน VRAM ได้ Ollama จะย้ายบางเลเยอร์ไปไว้ใน system RAM และเลเยอร์เหล่านั้นจะทำงานบน CPU ซึ่งเลเยอร์ที่ทำงานบน CPU จะช้ากว่าเลเยอร์บน GPU มาก ส่งผลให้ทุกคำขอทำงานช้าลง รวมถึงคำขอเดียวที่คุณเริ่มต้นไว้ด้วย ดังนั้นการเพิ่มการทำงานแบบขนานอาจลด throughput แทนที่จะเพิ่มขึ้น หากโมเดลมีขนาดใหญ่พอ น้ำหนักของโมเดลเพียงอย่างเดียวก็เป็นตัวตัดสินก่อนที่จะเริ่มคำนวณจำนวน slot ด้วยซ้ำ ซึ่งเป็นเหตุผลว่าทำไม การ self-host โมเดลขนาดเท่ากับ Kimi K3 จึงเป็นการสนทนาเกี่ยวกับจำนวนการ์ดที่คุณมี มากกว่าจำนวน slot ที่คุณตั้งค่าไว้

ollama ps

คอลัมน์ PROCESSOR จะแสดงค่า 100% GPU เมื่อทุกอย่างบรรจุลงในหน่วยความจำได้พอดี การแบ่งส่วนเช่น 35%/65% CPU/GPU หมายความว่าโมเดลบางส่วนกำลังทำงานอยู่บน CPU คอลัมน์ SIZE รวม KV cache ไว้ด้วย ดังนั้นมันจะเพิ่มขึ้นเมื่อคุณเพิ่มจำนวน slot และโหลดโมเดลใหม่ ให้เพิ่ม OLLAMA_NUM_PARALLEL, รีสตาร์ท, ส่งคำขอหนึ่งรายการ แล้วรัน ollama ps อีกครั้ง นั่นคือต้นทุนหน่วยความจำจากการเปลี่ยนแปลงของคุณ ซึ่งเป็นการวัดผลจริงไม่ใช่การคาดเดา หากการวัดผลระบุว่าโมเดลไม่สามารถบรรจุลงได้อีกต่อไป โปรดจำไว้ว่าน้ำหนักของโมเดลคืออีกครึ่งหนึ่งของงบประมาณหน่วยความจำเดียวกัน และ การเปลี่ยนจาก fp16 ไปเป็น build แบบ q8 หรือ q4 มักจะช่วยคืนพื้นที่ VRAM ได้มากกว่าต้นทุนของ slot ที่คุณพยายามจะเพิ่ม

ความยาวบริบทและจำนวน slot จะคูณกัน ดังนั้นจึงต้องเลือกไปพร้อมกัน บริบทขนาดใหญ่ที่มีสี่ slot เท่ากับบริบทขนาดใหญ่สี่ชุด หากคุณกำลังปรับแต่ง หน้าต่างบริบท num_ctx สำหรับโมเดลของคุณ ให้เปลี่ยนทีละค่า มิฉะนั้นคุณจะไม่ทราบว่าค่าใดเป็นตัวที่ทำให้การ์ดหน่วยความจำเต็ม

วิธีการตั้งค่าตัวแปรเหล่านี้ให้คงอยู่หลังการรีบูต

บน Linux นั้น Ollama ทำงานในรูปแบบของ systemd service การรัน export OLLAMA_NUM_PARALLEL=4 ใน shell ของคุณจะไม่ส่งผลใดๆ เนื่องจาก systemd เริ่มต้น service ด้วยสภาพแวดล้อมของตัวเองและไม่เห็นค่าใน shell ของคุณ ให้ใช้ไฟล์ drop-in แทน

sudo systemctl edit ollama.service

เพิ่มข้อความนี้ลงในโปรแกรมแก้ไขที่เปิดขึ้นมา:

[Service]
Environment="OLLAMA_NUM_PARALLEL=4"
Environment="OLLAMA_MAX_LOADED_MODELS=1"
Environment="OLLAMA_MAX_QUEUE=32"

จากนั้นทำการโหลดใหม่และรีสตาร์ท:

sudo systemctl daemon-reload
sudo systemctl restart ollama
systemctl show ollama --property=Environment

systemctl show จะแสดงสิ่งที่ systemd ส่งให้กับกระบวนการทำงาน หากตัวแปรของคุณไม่ปรากฏที่นั่น แสดงว่าไฟล์ drop-in ไม่ถูกบันทึกหรือข้ามขั้นตอน daemon-reload ไป ให้ตรวจสอบจากฝั่งของเซิร์ฟเวอร์ด้วยเช่นกัน:

journalctl -u ollama --no-pager | grep "server config" | tail -1

Ollama จะบันทึกสภาพแวดล้อมทั้งหมดของตนเองไว้ใน log เมื่อเริ่มต้นทำงานในบรรทัดที่มีข้อความว่า server config แผนผังดังกล่าวจะแสดงสิ่งที่เซิร์ฟเวอร์อ่านได้จริง และเป็นวิธีที่เร็วที่สุดในการยุติข้อโต้แย้งว่าตัวแปรมีผลหรือไม่ โดยจะแสดงค่าที่คุณตั้งไว้ ไม่ใช่จำนวน slot ที่โมเดลนั้นได้รับจริง สำหรับข้อมูลดังกล่าว ให้ดูที่ค่า -np ในบรรทัด runner ด้านบน

โมเดลที่โหลดอยู่แล้วจะคงจำนวน slot ที่เริ่มต้นไว้ เนื่องจากค่านั้นถูกกำหนดตายตัวในกระบวนการ runner ตั้งแต่ตอนเปิดใช้งาน การรีสตาร์ทข้างต้นจะยกเลิกการโหลดทุกอย่าง ดังนั้นคำขอถัดไปจะโหลดโมเดลใหม่ด้วยการตั้งค่าใหม่และใช้เวลาโหลดหนึ่งครั้ง ส่วนระยะเวลาที่โมเดลจะยังคงอยู่ในหน่วยความจำหลังจากนั้นเป็นการควบคุมแยกต่างหาก ซึ่งครอบคลุมอยู่ใน การคงโมเดล Ollama ไว้ในหน่วยความจำระหว่างคำขอ

ลักษณะของสถานะ served, queued และ refused จากมุมมองของไคลเอนต์

ส่งคำขอหลายรายการพร้อมกันและจับเวลา คำสั่งนี้จะรัน streaming requests จำนวน 8 รายการแบบขนาน พร้อมแสดงสถานะและเวลาที่ใช้สำหรับแต่ละรายการ:

for i in $(seq 1 8); do
  curl -s -o /dev/null \
    -w "req$i http=%{http_code} ttfb=%{time_starttransfer}s total=%{time_total}s\n" \
    http://127.0.0.1:11434/api/generate \
    -d '{"model":"llama3.2:3b","prompt":"Explain what a KV cache is.","stream":true}' &
done
wait

ttfb คือเวลาจนกว่าจะได้รับไบต์แรกของสตรีม ซึ่งใกล้เคียงกับเวลาที่ใช้ในการสร้างโทเค็นแรก (TTFT) เนื่องจากข้อมูลส่วนแรกที่สตรีมออกมาจะมีโทเค็นแรกอยู่ด้วย

Served in parallel (ให้บริการแบบขนาน): ทุกคำขอจะรายงานค่า ttfb ที่ใกล้เคียงกัน และค่า total จะเพิ่มขึ้นพร้อมกันทั้งหมด GPU จะถูกแชร์ระหว่างสล็อตที่กำลังทำงานอยู่ ดังนั้นคำตอบแต่ละรายการจะช้ากว่าการรันเพียงลำพัง แต่จะมีจำนวนคำตอบที่เสร็จสิ้นต่อนาทีมากขึ้น นี่คือสภาวะที่คุณได้รับเมื่อเพิ่มค่า OLLAMA_NUM_PARALLEL

Queued (อยู่ในคิว): คำขอแรกๆ จะได้รับคำตอบอย่างรวดเร็ว ส่วนคำขอหลังๆ จะแสดงค่า ttfb ที่สูงตามด้วยการสร้างข้อความตามปกติ ช่วงเวลาที่รอคือการรอในคิว ไม่ใช่การประมวลผลของโมเดล ผู้ใช้ที่ดูหน้าต่างแชทจะเห็นการหยุดชะงักที่ว่างเปล่านานๆ แล้วจึงเห็นข้อความปรากฏขึ้นด้วยความเร็วปกติ รูปแบบที่เริ่มช้าแล้วเร็วเช่นนี้คือลักษณะเฉพาะของคิว ไม่ใช่การที่ GPU ทำงานหนักเกินไป

Refused (ถูกปฏิเสธ): ไคลเอนต์จะได้รับ http=503 แทบจะทันที โดยมีเนื้อหาตอบกลับคือ:

{"error":"server busy, please try again.  maximum pending requests exceeded"}

ข้อความดังกล่าวหมายความว่าคิวการจัดตารางเวลาเต็มในขณะที่คำขอส่งเข้ามา ไม่ได้ระบุถึงสถานะของ VRAM หรือตัวโมเดลแต่อย่างใด ในซอฟต์แวร์รุ่นปัจจุบัน คิวดังกล่าวจะเก็บเฉพาะคำขอที่โมเดลยังไม่ได้ถูกโหลดขึ้นหน่วยความจำเท่านั้น หากโมเดลถูกโหลดไว้แล้วในขณะที่คุณรันลูปข้างต้น ทุกคำขอจะส่งสถานะ 200 กลับมาเสมอไม่ว่าคุณจะตั้งค่า OLLAMA_MAX_QUEUE ไว้ต่ำเพียงใดก็ตาม อาการล้นของคิวจะแสดงออกมาเป็นค่า ttfb ที่นานขึ้นแทน

ข้อจำกัดที่ควรทราบ: Ollama ไม่ได้เปิดเผยความลึกของคิว ollama ps และ endpoint /api/ps จะรายงานเฉพาะโมเดลที่ถูกโหลดอยู่ ไม่ใช่จำนวนคำขอที่กำลังรอคิว ดังนั้นคุณต้องวัดขนาดคิวจากฝั่งไคลเอนต์โดยการสังเกตเวลาจนกว่าจะได้รับไบต์แรก หรือนับจำนวนการตอบกลับสถานะ 503 จากระบบที่อยู่หน้า Ollama อีกชั้นหนึ่ง

เหตุผลที่การตั้งค่า MAX_QUEUE ให้มีขนาดเล็กลงมักเป็นทางเลือกที่ดีกว่า

คิวขนาด 512 ฟังดูเหมือนจะเพียงพอ แต่ในทางปฏิบัติสำหรับช่องประมวลผลเดียว (single slot) นั้นแทบไม่มีประโยชน์เลย คำขอที่ 300 จะต้องรอให้คำขอก่อนหน้าประมวลผลเสร็จสิ้นถึง 299 รายการ ซึ่งในกรณีที่ดีที่สุดก็ยังต้องใช้เวลาหลายนาที HTTP client ทุกตัวจะยอมแพ้ไปก่อนหน้านั้นนานแล้ว ส่งผลให้ผู้เรียกใช้งานพบกับข้อผิดพลาด client side timeout ซึ่งไม่ได้บอกข้อมูลอะไรเกี่ยวกับสาเหตุที่แท้จริง และระบบตรวจสอบ (monitoring) ของคุณก็ไม่ได้รับสัญญาณใดๆ เพื่อแจ้งเตือน

การลดขนาดคิวจะเปลี่ยนสถานการณ์ที่ล้นระบบให้กลายเป็นการตอบกลับด้วย 503 ทันที แต่จะเกิดขึ้นเฉพาะกับคำขอที่กำลังรอโหลดโมเดลเท่านั้น เช่น ช่วงที่มีคำขอเข้ามาพร้อมกันจำนวนมากหลังจากรีสตาร์ทหรือในระหว่างที่มีการสลับโมเดล ณ เดือนตุลาคม 2026 คำขอที่ส่งไปยังโมเดลที่โหลดอยู่แล้วจะข้าม OLLAMA_MAX_QUEUE และรอช่องว่างโดยไม่มีการจำกัด ดังนั้นการลดขนาดคิวจึงไม่ช่วยลดระยะเวลารอคอยบนเซิร์ฟเวอร์ที่มีงานยุ่งและมีโมเดลค้างอยู่ในหน่วยความจำเพียงโมเดลเดียว หากต้องการให้ระบบปฏิเสธคำขออย่างรวดเร็วในกรณีดังกล่าว ให้จำกัดจำนวน concurrency ไว้ที่หน้า Ollama ตามที่อธิบายไว้ในหัวข้อถัดไป การตอบกลับด้วย 503 มีประโยชน์เพราะ reverse proxy สามารถลองส่งคำขอใหม่ได้, client สามารถรอจังหวะส่งใหม่ (back off), แดชบอร์ดสามารถนับจำนวนข้อผิดพลาดได้ และผู้ดูแลระบบสามารถอ่านค่าได้ คุณควรคำนวณค่าจำกัดนี้จากการวัดผลด้วยตนเอง หากการสร้างข้อความ (generation) ใช้เวลาประมาณ 10 วินาทีและ client ของคุณรอได้ 60 วินาที แสดงว่าจะมีคำขอประมาณ 6 รายการต่อหนึ่งช่องประมวลผลที่สามารถดำเนินการเสร็จสิ้นภายในช่วงเวลานั้น การปล่อยให้มีคำขอรอเกินกว่านั้นจะทำให้เกิดเพียงแค่ timeout เท่านั้น

เมื่อใดที่ควรใช้คิวหน้า Ollama

คิวในตัวของ Ollama ทำงานแบบเข้าก่อนออกก่อน (FIFO) และไม่ทราบว่าใครเป็นผู้เรียกใช้งาน สำหรับแอปพลิเคชันเดียวที่ติดต่อกับเซิร์ฟเวอร์เดียว วิธีนี้เพียงพอแล้ว และการเพิ่มโครงสร้างพื้นฐานเข้าไปจะเพิ่มจุดที่อาจเกิดความล้มเหลวโดยไม่จำเป็น คุณควรพิจารณาเพิ่มระบบคิวไว้ด้านหน้าเมื่อเข้าเงื่อนไขต่อไปนี้:

  • คุณต้องการจัดลำดับความสำคัญ: การแชทโต้ตอบไม่ควรต้องรอต่อคิวหลังงานสรุปผลแบบกลุ่ม (batch summarisation) เนื่องจากคิวของ Ollama ไม่มีการจัดลำดับความสำคัญ งานแบบกลุ่มจึงต้องถูกพักไว้ภายนอกและค่อยๆ ป้อนเข้าสู่ระบบ
  • คุณต้องการความยุติธรรม: ไคลเอนต์รายเดียวอาจยึดครองทุกช่องสัญญาณและทำให้คำขออื่นๆ ต้องรอต่อคิวอยู่เบื้องหลัง ส่งผลให้ผู้ใช้อื่นต้องรอหรือได้รับข้อผิดพลาด 503 หากคำขอของพวกเขาจำเป็นต้องโหลดโมเดลใหม่
  • คุณต้องการจำกัดเวลารอ: Ollama จะพักคำขอสำหรับโมเดลที่โหลดไว้แล้วไว้อย่างไม่มีกำหนด ดังนั้นขีดจำกัดที่เชื่อถือได้เพียงอย่างเดียวคือขีดจำกัดที่คุณกำหนดไว้ที่ด้านหน้า
  • คุณต้องการให้งานยังคงอยู่หลังการรีสตาร์ท: คิวจะอยู่ในหน่วยความจำของเซิร์ฟเวอร์ หากรีสตาร์ท Ollama คำขอที่รออยู่ทั้งหมดจะหายไป
  • คุณต้องการระบบลองใหม่ (retry) พร้อมกลไก backoff ที่บันทึกไว้ในที่ที่คุณสามารถตรวจสอบได้ในภายหลัง

วิธีที่เบาที่สุดคือการใช้ reverse proxy ใน nginx คุณสามารถใช้ limit_conn เพื่อจำกัดจำนวนการเชื่อมต่อพร้อมกัน และ limit_req เพื่อจำกัดอัตราการส่งคำขอต่อไคลเอนต์ ดังนั้นคำขอที่เกินขีดจำกัดจะถูกปฏิเสธที่ตัว proxy และไม่ส่งต่อไปยัง Ollama ส่วนวิธีที่หนักกว่าคือการใช้ job queue ร่วมกับฐานข้อมูลไว้หน้า worker ที่ทำหน้าที่เรียก Ollama ซึ่งเป็นสิ่งที่คุณต้องการเมื่อคำขอจำเป็นต้องคงอยู่แม้มีการรีสตาร์ทกระบวนการ การคำนวณขนาดระบบสำหรับ traffic จริงเป็นเรื่องเฉพาะตัว: การวางแผนโฮสต์ LLM ด้วยตนเองสำหรับผู้ใช้พร้อมกัน จะอธิบายถึงการคำนวณ และ การรัน Ollama บน VPS จะครอบคลุมถึงการติดตั้งพื้นฐานที่ตัวแปรเหล่านี้อ้างอิงถึง

เมื่อคำตอบที่ตรงไปตรงมาคือการใช้เซิร์ฟเวอร์อื่น

มีขีดจำกัดที่คุณไม่สามารถปรับแต่งเพื่อก้าวข้ามไปได้ Ollama จะแบ่ง KV cache ออกเป็นช่องสัญญาณที่มีขนาดเท่ากันและคงที่เมื่อโหลดโมเดล หน่วยความจำของช่องสัญญาณที่ว่างอยู่ไม่สามารถนำไปใช้โดยช่องสัญญาณที่กำลังทำงานอยู่ได้ และจำนวนช่องสัญญาณไม่สามารถเปลี่ยนแปลงได้หากไม่ทำการ unload โมเดลก่อน การออกแบบนี้เหมาะสมสำหรับผู้ใช้คนเดียว ทีมขนาดเล็ก หรือ coding agent

เซิร์ฟเวอร์ที่สร้างขึ้นเพื่อรองรับผู้ใช้จำนวนมากพร้อมกันทำงานแตกต่างออกไป โดยจะจัดสรร KV cache เป็นหน้าหน่วยความจำขนาดเล็กตามความต้องการ และเพิ่มคำขอที่เข้ามาใหม่เข้าไปใน batch ที่กำลังประมวลผลอยู่ ดังนั้นหน่วยความจำจะถูกใช้ตามความต้องการจริงแทนที่จะถูกแบ่งไว้อย่างตายตัว หากเป้าหมายของคุณคือการรองรับผู้ใช้จำนวนมากพร้อมกันบน GPU หนึ่งตัว ความแตกต่างทางสถาปัตยกรรมนี้มีความสำคัญมากกว่าค่าใดๆ ของ OLLAMA_NUM_PARALLEL การเปรียบเทียบระหว่าง Ollama และ vLLM คือจุดที่คุณควรพิจารณาเพื่อตัดสินใจเรื่องนี้ อย่างไรก็ตาม อย่าเปลี่ยนเพียงเพราะหลักการ เนื่องจากเซิร์ฟเวอร์ที่แตกต่างกันหมายถึงภาระในการดูแลรักษาที่เพิ่มขึ้น และหากปริมาณการใช้งานของคุณมีเพียงไม่กี่คน พฤติกรรมการทำงานแบบ built-in ก็เป็นคำตอบที่ถูกต้องแล้ว หากคำถามที่แท้จริงคือคุณควรเรียกใช้ model server ด้วยตัวเองหรือไม่ การเปรียบเทียบระหว่างการใช้บริการ private AI server แบบที่ต้องขอใบเสนอราคา กับการสร้าง stack เดียวกันบน GPU ที่เช่ามา จะช่วยแนะนำขั้นตอนการตัดสินใจ รวมถึงกรณีที่การใช้ API เป็นทางเลือกที่คุ้มค่ากว่า

วัดปริมาณงานและเวลาจนถึงโทเค็นแรกของคุณเอง

ตัวเลขจำนวนโทเค็นต่อวินาทีที่เผยแพร่อยู่ทั่วไปนั้นมาจาก GPU, โมเดล, การทำ quantisation, ความยาวบริบท และ prompt ของผู้อื่น ซึ่งไม่มีสิ่งใดตรงกับของคุณ ดังนั้นให้ถือว่าตัวเลขเหล่านั้นเป็นเพียงแนวทางคร่าวๆ และให้วัดผลจากเครื่องที่อยู่ตรงหน้าคุณแทน

Ollama จะส่งคืนค่าเวลาไว้ในออบเจกต์ JSON สุดท้ายของทุกการตอบกลับ โดย eval_count คือจำนวนโทเค็นที่สร้างขึ้น และ eval_duration คือเวลาที่ใช้ในการสร้างโทเค็นเหล่านั้นในหน่วยนาโนวินาที

sudo apt install -y jq
curl -s http://127.0.0.1:11434/api/generate \
  -d '{"model":"llama3.2:3b","prompt":"Explain what a KV cache is.","stream":false}' \
  | jq '{prompt_eval_count, eval_count, eval_duration, tokens_per_second: (.eval_count / (.eval_duration / 1000000000))}'

ให้รันคำสั่งดังกล่าวด้วย 1 slot จากนั้นรันอีกครั้งด้วยระดับ concurrency ที่คุณคาดการณ์ไว้จริง แล้วเปรียบเทียบตัวเลขสองค่าที่เป็นตัวตัดสินว่าผู้ใช้งานจะพึงพอใจหรือไม่ ได้แก่ เวลาจนถึงโทเค็นแรก (time to first token) และจำนวนโทเค็นต่อวินาทีต่อคำขอ (tokens per second per request) ปริมาณงานต่อคำขอจะลดลงเสมอเมื่อมีการเพิ่มจำนวน slot คำถามคือมันลดลงเกินกว่าที่ผู้ใช้งานของคุณจะยอมรับได้หรือไม่ การวัดจำนวนโทเค็นต่อวินาทีบน LLM ในเครื่อง ครอบคลุมวิธีการดังกล่าวในรายละเอียดเพิ่มเติม รวมถึงวิธีรักษาค่า prompt ให้คงที่ระหว่างการทดสอบแต่ละครั้ง

Public endpoint ที่มีคิวขนาดใหญ่เป็นเป้าหมายของการโจมตีแบบ Denial of Service

การตั้งค่า OLLAMA_HOST=0.0.0.0:11434 จะทำให้ API เปิดใช้งานบนทุก interface และ Ollama ไม่มีระบบยืนยันตัวตนในตัว หากใช้ค่าคิวเริ่มต้น endpoint ที่เปิดสาธารณะจะยอมรับคำขอที่รอโหลดโมเดลได้สูงสุดถึง 512 รายการจากใครก็ตามที่พบ endpoint นี้ สำหรับโมเดลที่โหลดอยู่แล้ว ระบบจะถือค้างทุกคำขอที่เชื่อมต่อเข้ามาโดยไม่มีการจำกัด การทำให้เซิร์ฟเวอร์ติดขัดในลักษณะนี้แทบไม่มีต้นทุนสำหรับผู้โจมตี ไม่ว่าจะเป็นการส่ง prompt ยาวๆ โดยไม่ต้องล็อกอิน ไม่มีอัตราจำกัด และไม่มีค่าใช้จ่าย ส่งผลให้ผู้ใช้งานจริงของคุณได้รับข้อความตอบกลับ 503 หรือต้องรอเป็นเวลานาน ในขณะที่เครื่องต้องทำงานหนักตลอดเวลา

ควรให้ listener ทำงานบน loopback เท่านั้นและเข้าถึงผ่าน SSH tunnel หรือเครือข่ายส่วนตัว หรือวางระบบยืนยันตัวตนและจำกัดอัตราการเข้าถึงไว้ด้านหน้า การรักษาความปลอดภัยให้กับ Ollama API endpoint ครอบคลุมทั้งสองวิธีนี้ หลังจากดำเนินการดังกล่าวแล้วจึงค่อยปรับแต่งคิว เนื่องจากขนาดของคิวเป็นเพียงการตั้งค่าความจุและไม่ได้ช่วยป้องกันสิ่งใดเลย

FAQ

ทำไมคำขอที่สองของฉันถึงต้องรอให้คำขอแรกของ Ollama ทำงานเสร็จก่อน?

เพราะ OLLAMA_NUM_PARALLEL มีค่าเริ่มต้นเป็น 1 ทำให้โมเดลที่โหลดอยู่ประมวลผลได้ทีละหนึ่งคำขอ ส่วนคำขอที่เหลือจะเข้าคิวรอตามลำดับ คำขอที่รออยู่จะค้างการเชื่อมต่อ HTTP ไว้และไม่ส่งข้อมูลใดๆ จนกว่าจะมีช่องว่างว่างลง ซึ่งในมุมมองของไคลเอนต์จะมีลักษณะเหมือนโมเดลทำงานช้า จุดสังเกตคือรูปแบบของเวลา: หากมีการหยุดชะงักนานแล้วข้อความค่อยปรากฏออกมาด้วยความเร็วเต็มที่ แสดงว่าอยู่ในคิว แต่ถ้าข้อความค่อยๆ ไหลออกมาตั้งแต่ token แรก แสดงว่าโมเดลทำงานช้า ให้เพิ่มจำนวนช่องว่าง (slot) ด้วยการตั้งค่า systemd drop-in แล้วรีสตาร์ทเซอร์วิส จากนั้นให้ตรวจสอบค่า -np ในบรรทัด runner เพราะสถาปัตยกรรมโมเดลบางประเภทถูกจำกัดไว้ที่ 1 ช่องว่างเสมอไม่ว่าคุณจะตั้งค่าไว้อย่างไรก็ตาม

ข้อความ "server busy, please try again. maximum pending requests exceeded" หมายความว่าอย่างไร?

นี่คือข้อผิดพลาดเมื่อคิวของ Ollama เต็ม ซึ่งจะตอบกลับด้วย HTTP status 503 จำนวนคำขอที่รอการจัดตารางเวลา หรือรอให้โมเดลโหลดขึ้นหน่วยความจำ ได้ถึงขีดจำกัด OLLAMA_MAX_QUEUE ซึ่งมีค่าเริ่มต้นเป็น 512 ทำให้คำขอใหม่ล่าสุดถูกปฏิเสธแทนที่จะถูกเพิ่มเข้าไปในคิว ทั้งนี้คำขอที่ส่งไปยังโมเดลที่โหลดอยู่แล้วจะไม่ถูกนับรวมในขีดจำกัดนี้ คุณจะพบข้อผิดพลาดนี้บ่อยในช่วงที่มีคำขอเข้ามาพร้อมกันจำนวนมากตอนเริ่มต้นระบบ หรือระหว่างที่มีการสลับโมเดล นี่ไม่ใช่ข้อผิดพลาดเกี่ยวกับหน่วยความจำและไม่ใช่ข้อผิดพลาดของตัวโมเดล การเพิ่มขนาดคิวเพียงแค่ทำให้ผู้เรียกต้องรอนานขึ้นก่อนที่จะถูกปฏิเสธเหมือนเดิม ดังนั้นวิธีแก้ไขที่แท้จริงคือการเพิ่มจำนวนช่องว่างหากคุณมี VRAM เพียงพอ, ลดภาระงานที่เข้ามา หรือใช้ระบบคิวหน้าเซิร์ฟเวอร์ที่สามารถลองส่งคำขอใหม่และจัดลำดับความสำคัญได้

การเพิ่ม OLLAMA_NUM_PARALLEL ทำให้ Ollama ทำงานเร็วขึ้นหรือไม่?

ไม่ การตั้งค่านี้ช่วยให้คำขอจำนวนมากขึ้นทำงานพร้อมกันได้ แต่ละคำขอจะทำงานช้าลงกว่าการทำงานเพียงลำพังเพราะต้องแบ่งทรัพยากร GPU กัน นอกจากนี้ยังเป็นการคูณจำนวน KV cache เนื่องจาก Ollama จะเริ่ม runner ด้วย context รวมเท่ากับความยาว context ของคุณคูณด้วยจำนวนช่องว่าง หากผลลัพธ์ไม่สามารถบรรจุใน VRAM ได้ Ollama จะผลัก layer ไปยัง CPU และทำให้ทุกคำขอทำงานช้าลง รวมถึงคำขอเดียวที่ไม่มีการแข่งขันกันด้วย ให้ตรวจสอบ ollama ps หลังจากเปลี่ยนค่าและยืนยันว่าคอลัมน์ PROCESSOR ยังคงแสดงค่าเป็น 100% GPU

ฉันจำเป็นต้องรีสตาร์ท Ollama หลังจากเปลี่ยนตัวแปรเหล่านี้หรือไม่?

ใช่ เซิร์ฟเวอร์จะอ่านค่าเหล่านี้ตอนเริ่มต้นระบบ และโมเดลที่กำลังทำงานอยู่จะคงจำนวนช่องว่างที่กำหนดไว้ในกระบวนการ runner ตั้งแต่ตอนที่เริ่มทำงาน ให้แก้ไขไฟล์ drop-in ด้วย sudo systemctl edit ollama.service จากนั้นรัน sudo systemctl daemon-reload และ sudo systemctl restart ollama ยืนยันผลด้วย systemctl show ollama --property=Environment แล้วตรวจสอบบรรทัด server config ใน journalctl -u ollama ซึ่งจะแสดงรายการ environment ที่เซิร์ฟเวอร์โหลดใช้งานจริง

ฉันควรตั้งค่าจำนวนช่องว่างขนาน (parallel slots) ไว้เท่าใด?

ให้เริ่มที่ 1 แล้วค่อยๆ เพิ่มขึ้นทีละขั้น หลังจากแต่ละขั้นตอน ให้รีสตาร์ท Ollama ส่งคำขอหนึ่งรายการเพื่อโหลดโมเดล และรัน ollama ps ให้หยุดที่ค่าสุดท้ายที่ PROCESSOR ยังคงแสดงค่าเป็น 100% GPU และคอลัมน์ SIZE ยังมีพื้นที่เหลือเพียงพอสำหรับ context ที่ยาวที่สุดที่คุณให้บริการ จากนั้นให้วัดเวลาจนถึง token แรกและความเร็วในการประมวลผล (tokens per second) ที่การตั้งค่านั้นภายใต้สภาวะการใช้งานจริงของคุณ และลดลงหนึ่งขั้นหากความเร็วต่อคำขอต่ำกว่าระดับที่ผู้ใช้ของคุณยอมรับได้

#ollama#concurrency#vram#queueing#self-hosted-llm