SSD Nodes Learn 🎉 VPS $5.50/महिन्यापासून
मार्गदर्शक Matt Connorद्वारे Matt Connor · अपडेटेड 2026-08-13

self-hosted LLM 5 वापरकर्त्यांवर धीमा का होतो?

एक वापरकर्ता ठीक, पण पाच जणांवर वेग का कमी होतो? Ollama चा parallel requests default 1 आहे; batching, KV cache, prefill आणि queue depth ही खरी कारणे समजा.

अधिक वापरकर्ते जोडल्यावर self-hosted LLM धीमा का होतो?

5 concurrent वापरकर्त्यांवर self-hosted LLM अडखळतो, कारण सर्व्हर अजूनही एका वेळी फक्त एक उत्तर तयार करत आहे आणि उरलेले चार वापरकर्ते रांगेत थांबले आहेत. Ollama च्या दस्तऐवजांमध्ये default स्पष्टपणे दिलेला आहे: OLLAMA_NUM_PARALLEL म्हणजे “प्रत्येक model एकाच वेळी प्रक्रिया करणार्‍या parallel requests ची कमाल संख्या; default 1.” काहीही बिघडलेले नाही. तुमच्या पाचपैकी चार वापरकर्ते आपली पाळी येण्याची वाट पाहत आहेत.

यावरील उपाय सहसा मोठा server घेणे हा नसतो. अनेक requests ना त्याच forward pass मध्ये model मधून process करणारे serving engine आणि त्या वेळी सर्व वापरकर्त्यांचे conversation context ठेवण्यासाठी पुरेशी अतिरिक्त memory आवश्यक असते. या दोन्ही बाबी महत्त्वाच्या आहेत. प्रत्यक्ष कमाल मर्यादा दुसरी बाब ठरवते.

प्रत्येक विनंतीतून जाणारे दोन टप्पे

Prefill संपूर्ण prompt एकाच वेळी वाचतो आणि त्यासाठी attention cache तयार करतो. Prompt मधील प्रत्येक token model मधून एकत्रितपणे जातो. त्यामुळे prefill हा एक मोठा matrix multiply असतो आणि त्याची मर्यादा arithmetic throughput मुळे ठरते. त्यानंतर decode उत्तर एकावेळी एक token लिहितो. प्रत्येक token साठी model चे संपूर्ण weights पुन्हा memory मधून वाचावे लागतात, तर त्या एका token वर होणारी arithmetic खूपच कमी असते. त्यामुळे decode ची मर्यादा memory bandwidth मुळे ठरते.

हीच असममितता batching उपयुक्त ठरण्याचे मुख्य कारण आहे. एका वापरकर्त्यासाठी decoding करताना प्रत्येक token साठी, उदाहरणार्थ, 5 GB weights वाचले जातात आणि बहुतेक arithmetic units निष्क्रिय राहतात. दुसरी request जोडल्यावर engine तेच 5 GB एकदाच वाचतो आणि त्यावरून दोन tokens ची गणना करतो. दुसऱ्या वापरकर्त्यासाठी लागणारा अतिरिक्त वेळ जवळजवळ नगण्य असतो. Requests काटेकोरपणे एकामागोमाग एक serve केल्यास हा लाभ मिळत नाही.

वापरकर्त्याला जाणवणारा अनुभव दोन संख्यांनी स्पष्ट करता येतो. TTFT (time to first token) म्हणजे queue wait आणि prefill यांची एकत्रित वेळ. ITL (inter-token latency) म्हणजे stream केलेल्या tokens मधील अंतर; हे decode मुळे ठरते. Slow server बहुतेक वेळा या दोन्हीपैकी एका बाबतीत slow असतो. त्यावरील उपाय एकसारखे नसतात.

सर्वांत संथ उत्तराची static batching मध्ये सर्वांना प्रतीक्षा करावी लागते

Static batching ही साधी पद्धत आहे. application code मध्ये requests स्वतः गटबद्ध केल्यास हीच पद्धत वापरली जाते. engine N requests जमा करतो, त्या एकत्र चालवतो आणि गटातील सर्वांत दीर्घ generation पूर्ण होईपर्यंत प्रत्येक slot व्यापून ठेवतो.

1,200 token चा summary मागणारा एक user चार एक-ओळींची उत्तरे batch मध्ये अडकवतो, कारण गटातील सर्वांत संथ सदस्य पूर्ण होईपर्यंत batch कोणताही slot मोकळा करत नाही.

यामुळे दोन खर्च होतात. पूर्ण झालेल्या sequences असे slots व्यापून ठेवतात ज्यातून कोणतेही उपयुक्त compute होत नाही. त्यामुळे output lengths बदलत असताना effective throughput कमी होते; chat मध्ये output lengths मध्ये मोठा फरक असतो. Batch तयार झाल्यानंतर फक्त एक step उशिरा आलेल्या request ला prefill सुरू करण्यापूर्वी संपूर्ण batch रिकामा होईपर्यंत प्रतीक्षा करावी लागते. त्यामुळे तिचा TTFT दुसऱ्या user च्या मोठ्या उत्तरावर अवलंबून राहतो.

Continuous batching प्रत्येक token वर requests स्वीकारते आणि पूर्ण झालेल्या requests काढून टाकते

Continuous batching एका decoding step च्या स्तरावर scheduling करते. प्रत्येक step नंतर scheduler नुकतेच stop token निर्माण केलेले sequences काढून टाकतो आणि प्रतीक्षेत असलेल्या requests रिकाम्या slots मध्ये स्वीकारतो. Step 40 ला समाप्त होणारा reply त्याच step 40 ला आपला slot मोकळा करतो; batch संपेपर्यंत थांबत नाही.

ही काही विशेष किंवा दुर्मीळ पद्धत नाही. llama-server मध्ये -cb, --cont-batching चे दस्तऐवजीकरण "continuous batching (a.k.a dynamic batching) सक्षम करायचे की नाही (default: enabled)" असे केले आहे आणि vLLM ची रचना याच संकल्पनेवर आधारित आहे. Ollama समांतर requests देखील serve करते. Default configuration ही संख्या फक्त one पर्यंत मर्यादित करते. त्यामुळे अनेकांना त्यांच्या hardware वर concurrency चालू शकत नाही असे वाटते, प्रत्यक्षात नकार त्यांच्या configuration ने दिलेला असतो.

Published continuous batching results सामान्यतः अशा datacenter cards वर मोजले जातात ज्यांच्याकडे spare compute तसेच cache साठी tens of gigabytes memory असते. त्या results ची प्रवृत्ती तुमच्या box वरही लागू होते. मात्र त्यांचे प्रमाण लागू होत नाही. याचे कारण खालील memory section मध्ये स्पष्ट केले आहे.

Prefill आणि decode एकाच compute साठी स्पर्धा करतात

चार replies stream होत असताना नवीन request आल्यास, त्याचा prompt आधी prefill करावा लागतो. Prefill साठी compute मोठ्या प्रमाणात लागतो. Scheduler ने त्या prefill साठी स्वतंत्र step दिल्यास, त्या काळात चारही streaming users ना एकही token मिळत नाही. मोठ्या prompt मुळे प्रत्येक उघड्या window मध्ये हा थांबा स्पष्टपणे जाणवतो. दुसरा कोणी send दाबताच server मध्ये अडथळा येतो असे म्हणताना लोक याच stutter बद्दल बोलतात.

Chunked prefill मोठ्या prompt चे तुकडे करते आणि प्रत्येक तुकडा सुरू असलेल्या decode प्रमाणेच त्याच step मध्ये मिसळते. vLLM च्या tuning guide मध्ये हा tradeoff थेट सांगितला आहे: कमी chunk budgets मुळे "ITL चांगला मिळतो, कारण decode धीमा करणारे prefills कमी असतात", तर जास्त values मुळे "TTFT चांगला मिळतो, कारण batch मध्ये अधिक prefill tokens process करता येतात". तुम्ही कोणाचा अनुभव सुरक्षित ठेवायचा हे ठरवत आहात: reply सुरू होण्याची वाट पाहणाऱ्या व्यक्तीचा, की text stream होताना पाहणाऱ्या लोकांचा.

यामुळे होणारा परिणाम prompt च्या length वर अवलंबून असतो. 6,000 token चा prompt आणि 200 token चे उत्तर असल्यास, 200 decode steps च्या तुलनेत 6,000 tokens चे prefill काम करावे लागते. Retrieval-augmented chat आणि मोठे system prompts दोन्ही तुम्हाला या परिस्थितीत नेतात. त्यामुळे prefill ही किरकोळ बाब राहत नाही; वापरकर्ते ज्याची वाट पाहतात तेच ते बनते. मोठा भाग पुन्हा पुन्हा येत असल्यास prefix caching मदत करते: vLLM --enable-prefix-caching उपलब्ध करून देते. त्यामुळे प्रत्येक request साठी shared prompt prefix पुन्हा compute करण्याऐवजी त्याचा cache पुन्हा वापरला जातो.

सर्वप्रथम KV cache ची मेमरी संपते

प्रत्येक सक्रिय संभाषणातील प्रत्येक token मॉडेलच्या प्रत्येक layer मध्ये एक key vector आणि एक value vector ठेवतो. यालाच KV cache (key/value cache) म्हणतात. प्रत्येक नवीन token साठी संपूर्ण prompt पुन्हा मोजण्याची गरज टाळता येते, कारण ही cache decode प्रक्रियेला आवश्यक माहिती देते. प्रत्येक token साठी तिचा आकार मॉडेलच्या रचनेनुसार निश्चित असतो: 2 (एक key आणि एक value) गुणिले layer ची संख्या, गुणिले key/value heads ची संख्या, गुणिले head dimension, गुणिले प्रत्येक value साठी bytes. हे आकडे मॉडेलच्या config.json मधून वाचा.

हा हिशोब एकदा करा. त्यानंतर कमाल मर्यादा स्पष्ट होते. 36 layers, 8 key/value heads आणि 128 head dimension असलेल्या सामान्य 8B मॉडेलमध्ये cache 16-bit मध्ये ठेवली, तर प्रत्येक token साठी 2 36 8 128 2 bytes लागतात. हे 147,456 bytes, म्हणजे सुमारे 144 KiB आहे. त्यामुळे 8,192 tokens असलेल्या एका संभाषणासाठी cache ला सुमारे 1.2 GB लागतो. अशा पाच संभाषणांसाठी weights व्यतिरिक्त सुमारे 6 GB लागतात. किती users बसू शकतात याचे खरे उत्तर हेच आहे.

Concurrency मुळे context चे प्रमाण वाढते आणि tools हे स्पष्टपणे दाखवतात. Ollama च्या FAQ मध्ये असे म्हटले आहे: "एखाद्या model साठी parallel request processing केल्यास parallel requests च्या संख्येइतका context size वाढतो. उदाहरणार्थ, 4 parallel requests साठी 2K context वापरल्यास 8K context आणि अतिरिक्त memory allocation लागते." आवश्यक RAM हे OLLAMA_NUM_PARALLEL ला OLLAMA_CONTEXT_LENGTH ने गुणल्यावर मिळणाऱ्या प्रमाणानुसार वाढते. llama-server मध्ये -c द्वारे मागितलेला context -np slots मध्ये वाटला जातो. त्यामुळे slot count स्वतःहून वाढवल्यास प्रत्येक request मध्ये ठेवता येणारा context कमी होतो. अंदाज न बांधता startup log मधून प्रत्येक slot साठीचा context वाचा.

vLLM त्याऐवजी मेमरी आधीच allocate करते. --gpu-memory-utilization (default 0.92) म्हणजे "model executor साठी वापरायच्या GPU memory चा अंश". Weights वजा केल्यानंतर उरलेली मेमरी paged KV pool बनते. हा pool कमी पडल्यावर request fail न करता scheduler एखादी request evict करतो:

WARNING 05-09 00:49:33 scheduler.py:1057] Sequence group 0 is preempted by PreemptionMode.RECOMPUTE mode because there is not enough KV cache space.

vLLM च्या V1 engine मध्ये preemption mode चे default मूल्य RECOMPUTE आहे. त्यामुळे evict केलेल्या request ची cache टाकून दिली जाते आणि request पुन्हा स्वीकारली गेल्यावर तिचे prefill पुन्हा केले जाते. हे काम दोनदा होते. Documentation मध्ये असा इशारा दिला आहे की "preemption आणि recomputation मुळे end-to-end latency वर विपरीत परिणाम होऊ शकतो". तुमची average latency चांगली दिसत असताना एखाद्या दुर्दैवी user ला इतरांपेक्षा खूप जास्त वेळ का थांबावे लागले, याचे हे log line सर्वात स्पष्ट स्पष्टीकरण देते. एकत्रित count log करण्यासाठी disable_log_stats=False सेट करा किंवा vLLM उपलब्ध करून देत असलेल्या Prometheus metrics मधून preemption counter वाचा.

2, 5 आणि 20 समकालीन वापरकर्त्यांवर काय बदलते

दोन वापरकर्ते. अतिरिक्त cache असलेल्या GPU वर याचा परिणाम जवळजवळ जाणवत नाही, कारण दुसरा decode stream पहिल्या stream सोबतच चालतो आणि त्यासाठी फारच कमी अतिरिक्त वेळ लागतो. 4 ते 8 GB RAM असलेल्या केवळ CPU वर चालणाऱ्या VPS मध्ये हे विनामूल्य नसते: दोन्ही streams समान काही vCPU आणि समान RAM bandwidth सामायिक करतात. त्यामुळे प्रत्येक वापरकर्त्याला साधारणपणे निम्मा tokens per second मिळतो आणि तुलनेने कमी असलेल्या memory budget वर cache ची मागणी दुप्पट होते.

पाच वापरकर्ते. येथे default settings अपुऱ्या पडतात आणि सुरुवात queue च्या समस्येपासून होते. OLLAMA_NUM_PARALLEL 1 वर असल्यास, एखाद्याने लांब उत्तर मागितले की चार जण त्याची प्रतीक्षा करतात. मात्र त्यांची पाळी आल्यावर प्रत्येकाला नेहमीचा वेग मिळतो. Parallel count वाढवल्यावर समस्येचे स्वरूप बदलते: प्रत्येकी 8K context असलेल्या पाच slots साठी 40K tokens चा cache आवश्यक असतो. तो VRAM मध्ये बसत नसेल, तर engine layers system RAM मध्ये offload करते. तो RAM मध्येही बसत नसेल, तर मशीन swap वापरते आणि tokens per second झपाट्याने कमी होतो.

वीस वापरकर्ते. Chat UI मध्ये वीस माणसे असणे म्हणजे साधारणपणे वीस समकालीन requests असणे नाही. Hardware खरेदी करण्यापूर्वी समजून घेण्याची ही सर्वात महत्त्वाची बाब आहे. एखादी व्यक्ती reply वाचते आणि पुढील turn साठी 20 ते 60 seconds विचार करते. त्यामुळे तिच्या session चा बहुतांश वेळ idle असतो. मात्र वीस agents किंवा वीस document summarisation jobs म्हणजे idle time नसलेले वीस वास्तविक streams. अशा परिस्थितीसाठी वेगळ्या क्षमतेची मशीन आवश्यक असते.

तुमचे वापरकर्ते concurrent आहेत की फक्त logged in आहेत?

तुम्ही कोणतेही sizing करण्यापूर्वी प्रत्यक्ष सुरू असलेल्या requests ची संख्या ठरवा. गणित साधे आहे: सुरू असलेल्या requests ची संख्या = वापरकर्त्यांची संख्या × प्रत्येक turn साठी generation ला लागणारे seconds ÷ दोन turns मधील seconds.

  1. प्रथम तुमचा स्वतःचा single-stream speed मोजा; prefill आणि decode दोन्ही मोजा. दुसऱ्याच्या card वरील आकडा वापरू नका: तुमच्या स्वतःच्या box वर tokens per second मोजा आणि मिळालेला आकडा वापरा.
  2. Duty cycle चा अंदाज घ्या. 20 chat users, प्रत्येक turn साठी generation चे 12 seconds आणि प्रत्येक 90 seconds ला एक turn असल्यास, 20 * 12 / 90 म्हणजे सुमारे 2.7 requests सुरू असतील.
  3. Slot count त्या संख्येपेक्षा थोडा जास्त ठेवा. त्यानंतर memory शी त्याची पडताळणी करा: slots × प्रत्येक request साठी आवश्यक context हा तुमच्याकडे प्रत्यक्ष उपलब्ध असलेल्या cache tokens मध्ये बसला पाहिजे.
  4. Queue लहान ठेवा, जेणेकरून मर्यादा ओलांडल्यास failure जलद आणि स्पष्टपणे दिसेल.

उपलब्ध cache tokens = weights लोड केल्यानंतर उरलेली free memory ÷ वरील section मधील per-token cost. 16-bit मध्ये 8B model चालवणाऱ्या 24 GB card वर weights साठी सुमारे 16 GB वापरले जातात. Default utilisation मध्ये usable cache सुमारे 6 GB उरतो. यामध्ये साधारणपणे पाच 8K conversations बसतात. अधिक conversations बसवण्यासाठी प्रत्येक request चा context लहान करा किंवा cache 8-bit मध्ये साठवा (llama-server साठी --cache-type-k q8_0 लागते). दोन्ही पर्याय काहीतरी त्याग करून concurrency वाढवतात. Hardware साठी पैसे खर्च करण्यापूर्वी या trade-off चे प्रामाणिक विश्लेषण वाचणे उपयुक्त ठरेल: GPU VPS API tokens च्या तुलनेत break even कुठे होते ते पहा.

Ollama चे डीफॉल्ट पुरेसे नसतात तेव्हा

parallel count service unit मधून वाढवा, कारण shell export systemd-managed daemon पर्यंत पोहोचणार नाही.

sudo systemctl edit ollama.service
[Service]
Environment="OLLAMA_NUM_PARALLEL=4"
Environment="OLLAMA_CONTEXT_LENGTH=8192"
Environment="OLLAMA_MAX_QUEUE=64"
sudo systemctl daemon-reload
sudo systemctl restart ollama
systemctl show ollama --property=Environment
ollama ps

systemctl show ने तुम्ही नुकतेच सेट केलेले तीन variables दाखवले पाहिजेत. तसे न झाल्यास drop-in जतन झालेले नाही आणि त्यानंतर केलेल्या कोणत्याही कृतीचा उपयोग होणार नाही. ollama ps नंतर loaded model ची size दाखवते. ही size केवळ weights पेक्षा मोठी असते, कारण 8,192 tokens चे चार slots असल्यास त्यांच्यासोबत 32,768 tokens cache साठी राखीव ठेवले जातात. तुम्हाला संपूर्ण model GPU वर अपेक्षित असताना PROCESSOR column मध्ये model चा काही भाग CPU वर दाखवत असल्यास, card वर उपलब्ध उरलेल्या memory पेक्षा तुम्ही अधिक cache मागितला आहे. या दोन संख्यांपैकी एक कमी करा.

queue च्या default कडे पुन्हा लक्ष देणे आवश्यक आहे. Ollama OLLAMA_MAX_QUEUE पर्यंत requests queue मध्ये ठेवते आणि "the default is 512". त्यापुढे ते "with a 503 error indicating the server is overloaded" असा प्रतिसाद देते. एकावेळी चार requests हाताळणाऱ्या server वर 512 requests ची queue ठेवणे हे पाळता न येणारे आश्वासन आहे, कारण 300 व्या क्रमांकावरील client ची turn येण्यापूर्वीच timeout होतो. लहान queue मुळे application retry करू शकणारी किंवा report करू शकणारी error मिळते. कधीही पूर्ण न होणाऱ्या spinner पेक्षा हा पर्याय चांगला आहे.

प्रत्यक्ष चाचणी करा. दोन terminals मधून एकाच वेळी दोन requests पाठवा आणि दोन्हींकडे लक्ष ठेवा. पहिली request पूर्ण होईपर्यंत दुसऱ्या request कडून काहीही output मिळत नसेल, तर parallel setting लागू झालेली नाही.

प्रत्यक्ष serving engine स्वतःचा खर्च भरून काढू लागतो तेव्हा

GPU मध्ये अतिरिक्त क्षमता उपलब्ध असेल आणि साधारणपणे चारपेक्षा अधिक विनंत्या प्रत्यक्ष प्रक्रियेत असतील, तेव्हा vLLM साठी अतिरिक्त सेटअप योग्य ठरतो. त्याचा scheduler token स्तरावर काम करतो. त्याचा cache paged पद्धतीने व्यवस्थापित केला जातो, त्यामुळे मोकळे fragments पुन्हा वापरता येतात. त्यामुळे वापरात नसलेली VRAM concurrency साठी वापरली जाते.

August 2026 पर्यंत documented install आणि launch साठी दोन commands आहेत:

uv pip install vllm --torch-backend=auto
vllm serve Qwen/Qwen2.5-1.5B-Instruct
curl http://localhost:8000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "Qwen/Qwen2.5-1.5B-Instruct",
        "messages": [{"role": "user", "content": "Say hello."}]
    }'

choices array असलेले उत्तर मिळाल्यास server सुरू आहे आणि model load झाले आहे, असे समजते. Load असताना महत्त्वाचे दोन knobs म्हणजे --max-num-seqs — "एका iteration मध्ये process करता येणाऱ्या sequences ची कमाल संख्या" — आणि --max-num-batched-tokens — "एका iteration मध्ये process करता येणाऱ्या tokens ची कमाल संख्या". पहिला concurrency ची कमाल मर्यादा ठरवतो. दुसरा यापूर्वी वर्णन केलेला chunked prefill budget ठरवतो.

चारपेक्षा कमी विनंत्या प्रक्रियेत असतील किंवा supported GPU नसलेल्या कोणत्याही मशीनवर vLLM मुळे complexity वाढते, पण फायदा कमी मिळतो. त्याला CUDA-class card आवश्यक असतो आणि startup वेळी तो बहुतांश memory वापरतो. 4 ते 8 GB VPS साठी हा योग्य पर्याय नाही. अशा ठिकाणी कमी आकाराचे model, कमी context आणि तुमच्या नियंत्रणाखालील queue हा अधिक योग्य पर्याय आहे. Ollama आणि vLLM serving engines म्हणून कसे वेगळे आहेत या निवडीचे संपूर्ण स्पष्टीकरण देते, तर VPS वर Qwen 3 8B चालवणे एक अतिरिक्त user जोडण्यापूर्वी mid-sized model कडून कोणत्या संसाधनांची आवश्यकता असते ते दाखवते.

लोककथेत लपलेला तडजोडीचा मुद्दा

Continuous batching मुळे एकूण throughput वाढतो आणि median latency देखील सहसा सुधारते, कारण रांगेतील request लवकर सुरू होते. मात्र tail latency उलट दिशेने जाते आणि या परिणामाचा उल्लेख क्वचितच केला जातो.

एखाद्या step मध्ये प्रत्येक अतिरिक्त sequence मुळे थोडे अधिक काम वाढते. त्यामुळे batch भरत गेल्यावर सर्वांसाठी ITL वाढतो. नवीन request चे prefill सुरू करताना streaming users साठी उपलब्ध असलेल्या step मधील काही वेळ वापरला जातो. cache वर दबाव आल्यास scheduler preempt करतो. त्यामुळे अर्धवट तयार झालेली request तिच्या prefill च्या सुरुवातीला परत जाते.

Chat UI मध्ये averages नव्हे, तर tail latency दिसते. वाक्याच्या मध्यभागी stream दोन सेकंद थांबला, तर पूर्ण होण्यासाठी लागणारा एकूण वेळ चांगला असला तरी तो अनुभव बिघडलेला वाटतो. अपेक्षित load खाली p95 TTFT आणि p95 ITL मोजा. mean tokens per second ला वापरकर्ता-अनुभवाचे वर्णन न मानता capacity number म्हणून पहा.

यावरून व्यावहारिक setting ठरते. memory परवानगी देते त्यापेक्षा concurrency किंचित कमी मर्यादित करा, जेणेकरून engine ला preempt करण्याची गरज पडणार नाही. खोल batch वारंवार thrash होण्यापेक्षा लहान आणि अंदाज करता येणारी queue चांगली असते. कारण चार सेकंद वाट पाहिल्यानंतर सुरळीत stream मिळालेला user, लगेच सुरू होऊन दोनदा थांबणाऱ्या stream पेक्षा अधिक समाधानी असतो.

ते धीमे असताना काय तपासावे

प्रत्येक वापरकर्त्याचा वेग सामान्य आहे, पण प्रतीक्षा जास्त आहे. ही queue आहे; वेगाची समस्या नाही. सर्वप्रथम parallel setting तपासा. Model योग्य प्रकारे सेवा देत आहे, परंतु एका वेळी एकच request प्रक्रिया करत आहे.

Ollama कडून HTTP 503 मिळतो. Queue भरली आहे. एकतर box खरोखरच capacity वर आहे, किंवा load कमी करण्यासाठी OLLAMA_MAX_QUEUE जाणीवपूर्वक कमी ठेवले आहे. अपेक्षित परिणाम हाच असल्यास ही योग्य वर्तणूक आहे.

CPU box वर load वाढल्यावर tokens per second झपाट्याने कमी होतो. हे घडत असताना vmstat 1 चालवा. si आणि so columns मधील nonzero मूल्ये machine swapping करत असल्याचे दर्शवतात. त्यामुळे प्रत्येक token साठी weights disk वरून वाचले जातात. कोणताही configuration change ही समस्या दूर करू शकत नाही. Model size किंवा slot count कमी करा.

दहा वापरकर्त्यांपैकी एकाची प्रतीक्षा इतरांपेक्षा खूप जास्त असते. vLLM log मध्ये preempted शोधा. Preemption आणि त्यानंतर होणारे recompute हे सामान्यतः कारण असते. याचा अर्थ, तुम्ही अनुमती दिलेल्या context length साठी cache वर जास्त भार आहे.

Server idle असतानाही TTFT खराब आहे. ही concurrency ची समस्या नाही; ही prefill ची समस्या आहे. पहिला token दिसण्यापूर्वी long prompts साठी प्रत्यक्ष processing time लागतो. त्यामुळे hardware तपासण्यापूर्वी prompt size आणि prefix caching तपासा.

FAQ

माझा self-hosted LLM दुसरा वापरकर्ता वापरू लागल्यावर धीमा का होतो?

बहुतेक वेळा तो धीमा होत नाही. विनंत्या रांगेत थांबतात. Ollama मध्ये OLLAMA_NUM_PARALLEL चे default मूल्य 1 असते. त्यामुळे दुसरी विनंती पहिल्या विनंतीचा अंतिम token तयार होईपर्यंत थांबते. हे दोन प्रकार वेगळे ओळखण्यासाठी, एक वापरकर्ता stream पाहत असताना दुसऱ्या वापरकर्त्याची विनंती थांबवून वेळ मोजा. विनंती सुरू झाल्यावर तिचा tokens per second वेग सामान्य असेल, तर ही queue आहे आणि parallel count वाढवल्याने समस्या सुटते. दोन्ही streams अर्ध्या वेगाने चालत असतील, तर memory bandwidth खरोखरच विभागली जात आहे. ही hardware limit आहे.

एक छोटा GPU किती concurrent users हाताळू शकतो?

वापरकर्त्यांची संख्या नव्हे, तर memory मोजा. प्रथम weights, त्यानंतर KV cache मोजा. प्रत्येक active conversation साठी, प्रत्येक token मागे त्याचा खर्च 2 times layers times key/value heads times head dimension times bytes इतका असतो. 36 layers, 8 key/value heads आणि 128 head dimension असलेल्या सामान्य 8B model साठी 16-bit मध्ये प्रत्येक token मागे सुमारे 144 KiB लागतात. त्यामुळे 8,192 token conversation साठी अंदाजे 1.2 GB लागते. हा model 16-bit मध्ये ठेवणाऱ्या 24 GB card मध्ये cache साठी सुमारे 6 GB उरतात. त्यामुळे full context वर सुमारे पाच conversations हाताळता येतात. Context कमी केल्यास त्यापेक्षा अधिक conversations हाताळता येतात.

Continuous batching मुळे प्रत्येक वापरकर्त्याचे उत्तर धीमे होते का?

Median latency सहसा सुधारते, कारण विनंत्यांना पूर्ण batch संपेपर्यंत थांबावे लागत नाही. मात्र tail latency वाढते. प्रत्येक अतिरिक्त sequence मुळे प्रत्येक decoding step मध्ये अधिक काम वाढते. नवीन विनंती आल्यावर तिचे prefill streaming users साठी असलेल्या एका step चा काही भाग वापरते. Preempted request ला दोनदा prefill करावे लागते. त्यामुळे average ऐवजी p95 inter-token latency मोजा. Average मध्ये लपणारे pauses chat window मध्ये स्पष्ट दिसतात.

OLLAMA_NUM_PARALLEL वाढवावे की vLLM वापरावे?

प्रथम parallel count वाढवा. यासाठी अतिरिक्त खर्च नाही आणि एक drop-in file पुरेशी असते. एका मोठ्या उत्तरामागे चार जणांच्या विनंत्या queue मध्ये थांबणे ही सामान्य समस्या असल्यास यामुळे ती सुटते. Memory ही मर्यादा आहे. Parallel requests मुळे ठेवावा लागणारा context वाढतो. त्यामुळे layers CPU वर spill होत आहेत का ते तपासा. GPU मध्ये पुरेशी VRAM शिल्लक असेल आणि चारपेक्षा अधिक requests प्रत्यक्षात एकाच वेळी in flight असतील, तेव्हा vLLM वापरा. त्या टप्प्यावर paged cache आणि per-token scheduling यांचा फायदा त्यांच्या overhead पेक्षा अधिक मिळतो.

Slow LLM server साठी अधिक CPU cores उपयोगी पडतील का?

वापरकर्त्यांना सर्वाधिक जाणवणाऱ्या भागासाठी नाही. प्रत्येक token साठी decode संपूर्ण model memory मधून वाचतो. त्यामुळे ते RAM bandwidth वर अवलंबून असते. Bandwidth भरून गेल्यावर अतिरिक्त cores उपयोगी पडत नाहीत. Prefill मात्र cores वाढवल्याने वेगवान होते. त्यामुळे मोठ्या prompts साठी time to first token कमी होतो. 4 to 8 GB VPS वर मुख्य मर्यादा सहसा memory capacity असते. त्यामुळे अधिक vCPUs देण्याऐवजी छोटा model किंवा कमी context वापरणे हा अधिक प्रभावी उपाय असतो.