Ollama concurrency: OLLAMA_NUM_PARALLEL कैसे सेट करें
OLLAMA_NUM_PARALLEL और OLLAMA_MAX_QUEUE के जरिए Ollama में concurrency मैनेज करें। जानें कि कैसे ये सेटिंग्स HTTP 503 error को रोकती हैं और क्यों हर स्लॉट VRAM खपत बढ़ाता है।
जब पहली request generate हो रही हो, तो दूसरी Ollama request का क्या होता है
Ollama की concurrency तीन environment variables द्वारा तय की जाती है, और default रूप से एक loaded model एक समय में केवल एक ही request को process करता है। दूसरी request को न तो अस्वीकार (refuse) किया जाता है और न ही उसे अधूरा उत्तर मिलता है। वह queue में तब तक प्रतीक्षा करती है जब तक कि एक slot खाली न हो जाए, और उसके बाद वह सामान्य गति से चलती है।
एक incoming request के तीन संभावित परिणाम हो सकते हैं। यह तुरंत एक खाली slot में शुरू हो जाती है। यह queue में प्रतीक्षा करती है। या फिर queue पहले से ही भरी हुई है और server इसे HTTP 503 error के साथ अस्वीकार कर देता है। आपको क्या परिणाम मिलेगा, यह OLLAMA_NUM_PARALLEL, OLLAMA_MAX_QUEUE और OLLAMA_MAX_LOADED_MODELS द्वारा तय किया जाता है।
Default setting सुरक्षित है, और यही कारण है कि दूसरा user यह रिपोर्ट करता है कि server "hang" हो गया है, जबकि वास्तव में कुछ भी खराब नहीं हुआ होता है। Slots बढ़ाना केवल दो लाइन का बदलाव है। जो हिस्सा समस्या पैदा करता है, वह memory है। प्रत्येक parallel slot को अपने स्वयं के key/value cache (KV cache) की आवश्यकता होती है, जो memory का वह block है जिसे model उन tokens के लिए रखता है जिन्हें वह पहले ही process कर चुका है। यदि आप VRAM (GPU पर video memory) बढ़ाए बिना slots बढ़ाते हैं, तो आप एक धीमे उत्तर को failed load में बदल देंगे।
OLLAMA_NUM_PARALLEL, OLLAMA_MAX_QUEUE और OLLAMA_MAX_LOADED_MODELS क्या नियंत्रित करते हैं
ये अगस्त 2026 तक के वर्तमान Ollama releases में डिफ़ॉल्ट मान हैं। यहाँ दी गई संख्याओं पर भरोसा करने के बजाय, नीचे दिखाए गए log line का उपयोग करके अपनी सेटिंग्स की जाँच करें।
OLLAMA_NUM_PARALLELयह नियंत्रित करता है कि एक loaded model एक ही समय में कितने requests को संभाल सकता है। डिफ़ॉल्ट मान 1 है, इसलिए requests को एक के बाद एक पूरा किया जाता है।OLLAMA_MAX_LOADED_MODELSयह नियंत्रित करता है कि एक साथ कितनी अलग-अलग models memory में रह सकती हैं। डिफ़ॉल्ट मान 0 है, जिसका अर्थ है कि Ollama स्वयं चयन करता है: प्रति GPU तीन models, और बिना GPU वाली मशीन पर भी तीन models।OLLAMA_MAX_QUEUEयह नियंत्रित करता है कि कितनी requests प्रतीक्षा सूची (queue) में रह सकती हैं। डिफ़ॉल्ट मान 512 है। जब queue भर जाती है, तो आने वाली नई request को तुरंत अस्वीकार कर दिया जाता है।
सबसे खराब स्थिति में memory की खपत पहले दो मानों का गुणनफल होती है। यदि चार-चार slots वाली दो models loaded हैं, तो कुल आठ KV cache slots का आवंटन एक साथ memory में रहेगा, और Ollama इसे पूरा करने का प्रयास करेगा। एक ही GPU वाले सिस्टम पर आमतौर पर एक ही model को रखना और उसे अधिक slots देना बेहतर होता है, क्योंकि इससे गणना सरल बनी रहती है।
हर parallel slot के लिए VRAM की आवश्यकता क्यों होती है
जब Ollama किसी model को load करता है, तो वह एक अलग runner process शुरू करता है। इसमें भेजे जाने वाले दो arguments महत्वपूर्ण हैं: -c वह कुल context है जिसके लिए runner एक KV cache allocate करता है, और -np parallel sequences की संख्या है। Ollama -c को आपकी प्रति-अनुरोध (per-request) context length और slot count के गुणनफल पर सेट करता है। इसके बाद runner उस कुल मात्रा को slots के बीच समान रूप से विभाजित कर देता है, ताकि प्रत्येक अनुरोध को उतनी ही context length मिले जितनी आपने मांगी थी।
यही एकमात्र बाधा है, और इसीलिए parallelism मुफ्त नहीं है। एक slot से चार slots पर जाने का मतलब है कि समान प्रति-अनुरोध context पर चार गुना KV cache की आवश्यकता। slots के बीच कुछ भी साझा नहीं होता है, और एक खाली slot का हिस्सा किसी व्यस्त slot को नहीं दिया जा सकता, क्योंकि runner शुरू होते ही विभाजन तय हो जाता है।
आप उन मानों के बजाय वास्तविक संख्याएँ देख सकते हैं जिन्हें आप सेट करना चाहते थे:
journalctl -u ollama --no-pager -n 500 | grep "starting llama-server"उस पंक्ति में पूरा runner command line होता है, जिसमें -c और -np शामिल हैं। यदि variable सेट करने के बाद भी -np का मान 1 है, तो setting सर्वर तक नहीं पहुँच रही है, और अगला भाग इसका कारण बताता है।
यदि model weights और वह KV cache VRAM में नहीं समाते हैं, तो Ollama कुछ layers को system RAM में ले जाता है और वे layers CPU पर चलती हैं। CPU layers, GPU layers की तुलना में बहुत धीमी होती हैं, इसलिए इससे हर अनुरोध धीमा हो जाता है, जिसमें वह एकल अनुरोध भी शामिल है जिससे आपने शुरुआत की थी। इसलिए, parallelism बढ़ाने से throughput बढ़ने के बजाय घट सकता है।
ollama psजब पूरी चीज़ VRAM में समा जाती है, तो PROCESSOR column में 100% GPU दिखाई देता है। 35%/65% CPU/GPU जैसा विभाजन होने का मतलब है कि model का कुछ हिस्सा CPU पर चल रहा है। SIZE column में KV cache शामिल होता है, इसलिए जब आप slot count बढ़ाते हैं और model को reload करते हैं, तो यह बढ़ जाता है। OLLAMA_NUM_PARALLEL को बढ़ाएं, restart करें, एक अनुरोध भेजें, और फिर से ollama ps चलाएं: यह आपके बदलाव की memory लागत है, जिसे अनुमान लगाने के बजाय मापा गया है।
Context length और slot count आपस में गुणा होते हैं, इसलिए उन्हें एक साथ चुना जाना चाहिए। चार slots के साथ एक बड़ी context का मतलब है चार बड़ी contexts। यदि आप अपने model के लिए num_ctx context window को भी ट्यून कर रहे हैं, तो एक बार में दोनों में से केवल एक को बदलें, अन्यथा आपको पता नहीं चलेगा कि किस कारण से card भर गया।
इन variables को reboot के बाद भी बनाए रखने का तरीका
Linux पर, Ollama एक systemd service के रूप में चलता है। अपने shell में export OLLAMA_NUM_PARALLEL=4 चलाने से कुछ नहीं बदलता, क्योंकि systemd service को अपने स्वयं के environment के साथ शुरू करता है और आपके shell को नहीं देख पाता। इसके लिए एक drop-in file का उपयोग करें।
sudo systemctl edit ollama.serviceखुलने वाले editor में इसे जोड़ें:
[Service]
Environment="OLLAMA_NUM_PARALLEL=4"
Environment="OLLAMA_MAX_LOADED_MODELS=1"
Environment="OLLAMA_MAX_QUEUE=32"फिर reload और restart करें:
sudo systemctl daemon-reload
sudo systemctl restart ollama
systemctl show ollama --property=Environmentsystemctl show वह जानकारी दिखाता है जो systemd process को देगा। यदि आपकी variable वहाँ नहीं है, तो drop-in save नहीं हुआ है या daemon-reload को छोड़ दिया गया है। सर्वर की तरफ से भी इसकी पुष्टि करें:
journalctl -u ollama --no-pager | grep "server config" | tail -1Ollama startup पर अपने पूरे environment को एक line में log करता है जिसका message server config होता है। वह map ही अंतिम सत्य है। यह पता लगाने का सबसे तेज़ तरीका है कि कोई variable प्रभावी हुई है या नहीं।
जो model पहले से loaded है, वह उसी slot count को बनाए रखता है जिसके साथ उसे शुरू किया गया था, क्योंकि यह value launch के समय ही runner process में fix हो जाती है। ऊपर दिया गया restart सब कुछ unload कर देता है, इसलिए अगली request नए setting के साथ model को reload करती है और load time एक बार चुकाना पड़ता है। उसके बाद model कितनी देर तक resident रहता है, यह एक अलग control है, जिसे requests के बीच Ollama model को loaded रखना में समझाया गया है।
Client के नजरिए से served, queued और refused का अर्थ
एक साथ कई requests भेजें और उनका समय मापें। यह कमांड समानांतर (parallel) रूप से आठ streaming requests चलाती है और प्रत्येक के लिए status और timings प्रिंट करती है:
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
waitttfb स्ट्रीम के पहले बाइट तक का समय है। यह time to first token (TTFT) के करीब है क्योंकि स्ट्रीम किया गया पहला chunk ही पहला token लेकर आता है।
समानांतर में served (Served in parallel)। प्रत्येक request एक समान ttfb रिपोर्ट करती है, और उन सभी के लिए total एक साथ बढ़ता है। GPU को चल रहे slots के बीच साझा किया जाता है, इसलिए प्रत्येक उत्तर अकेले चलने की तुलना में धीमा होता है, लेकिन प्रति मिनट अधिक उत्तर पूरे होते हैं। जब आप OLLAMA_NUM_PARALLEL बढ़ाते हैं, तो आप इसी regime का उपयोग कर रहे होते हैं।
Queued (कतारबद्ध)। पहली requests जल्दी उत्तर देती हैं और बाद वाली requests में एक लंबा ttfb दिखाई देता है, जिसके बाद सामान्य generation होती है। यह प्रतीक्षा समय queue का है, न कि model का। चैट विंडो देख रहे उपयोगकर्ता को एक लंबा खाली अंतराल दिखाई देता है और फिर पूरी गति से टेक्स्ट आता है। वह आकार, जो शुरू होने में धीमा है और फिर तेज, overloaded GPU के बजाय queue की पहचान है।
Refused (अस्वीकृत)। client को लगभग तुरंत http=503 प्राप्त होता है, और body इस प्रकार होती है:
{"error":"server busy, please try again. maximum pending requests exceeded"}इस संदेश का अर्थ है कि जिस क्षण request पहुँची, उस समय queue भरी हुई थी। यह VRAM या model के बारे में कुछ नहीं कहता है।
एक स्पष्ट सीमा: Ollama queue की गहराई (depth) प्रकाशित नहीं करता है। ollama ps और /api/ps endpoint उन models की रिपोर्ट करते हैं जो loaded हैं, न कि उन requests की जो प्रतीक्षा कर रही हैं। इसलिए आप client side से queue को मापते हैं, time to first byte को देखकर, या आप अपने सामने मौजूद किसी भी चीज़ पर 503 responses की गिनती करते हैं।
MAX_QUEUE को छोटा रखना अक्सर बेहतर सेटिंग क्यों है
512 की queue सुनने में काफी बड़ी लगती है, लेकिन एक single slot पर यह लगभग बेकार है। 300वां request 299 पूर्ण generations के पीछे प्रतीक्षा करता है। इसमें कम से कम कुछ मिनट लग सकते हैं। हर HTTP client उससे बहुत पहले ही हार मान लेता है, इसलिए caller को client-side timeout दिखाई देता है। यह उसे कारण के बारे में कुछ नहीं बताता और आपके monitoring system को भी alert करने के लिए कुछ नहीं मिलता।
Queue को लगभग उस संख्या पर सेट करें जिसे आपका सर्वर आपके client के timeout के भीतर पूरा कर सके। ऐसा करने पर overflow होने पर तुरंत 503 error मिलेगा। 503 error उपयोगी है: एक reverse proxy इसे retry कर सकता है, client प्रतीक्षा (back off) कर सकता है, dashboard इसे count कर सकता है, और कोई व्यक्ति इसे पढ़ सकता है। इस संख्या का निर्धारण अपने स्वयं के measurements से करें। यदि एक generation में लगभग दस सेकंड लगते हैं और आपका client साठ सेकंड प्रतीक्षा करता है, तो प्रति slot लगभग छह requests उस समय सीमा के भीतर पूरे हो सकते हैं। इससे अधिक गहरी queue केवल timeouts ही पैदा करेगी।
Ollama के सामने queue कब लगाएँ
Ollama की इन-बिल्ट queue 'first in, first out' (FIFO) आधार पर काम करती है और इसे यह नहीं पता होता कि request कौन भेज रहा है। यदि एक application एक server से बात कर रही है, तो यह पर्याप्त है; अतिरिक्त infrastructure लगाने से केवल failure के नए कारण पैदा होंगे। निम्नलिखित स्थितियों में आपको Ollama के सामने एक queue लगाने की आवश्यकता होती है:
- आपको priority की आवश्यकता है। एक interactive chat को batch summarisation job के पीछे इंतज़ार नहीं करना चाहिए। Ollama की queue में priority का कोई प्रावधान नहीं है, इसलिए batch work को बाहर रोककर धीरे-धीरे process करना पड़ता है।
- आपको fairness की आवश्यकता है। एक client पूरी queue को भर सकता है, जिसके बाद बाकी सभी को 503 error मिलने लगता है।
- आपको यह सुनिश्चित करना है कि restart के बाद भी काम सुरक्षित रहे। queue server की memory में रहती है। Ollama को restart करते ही सभी waiting requests नष्ट हो जाती हैं।
- आपको backoff के साथ वास्तविक retries की आवश्यकता है, जिन्हें बाद में जांचने के लिए कहीं record किया गया हो।
इसका हल्का विकल्प एक reverse proxy है। Nginx में, limit_conn simultaneous connections को सीमित करता है और limit_req प्रति client arrival rate को नियंत्रित करता है, जिससे overflow को proxy पर ही रोक दिया जाता है और वह Ollama की queue तक नहीं पहुँचता। इसका भारी विकल्प एक job queue है जिसमें database का उपयोग किया जाता है, जो एक worker के माध्यम से Ollama को call करता है। यदि आप चाहते हैं कि requests process restart के बाद भी बनी रहें, तो यही सही तरीका है। वास्तविक traffic के लिए इसका आकार निर्धारित करना एक अलग प्रक्रिया है: concurrent users के लिए self-hosted LLM की योजना बनाना में इसकी गणना समझाई गई है, और VPS पर Ollama चलाना में उस बुनियादी installation को कवर किया गया है जिस पर ये variables आधारित हैं।
जब सही समाधान एक अलग सर्वर हो
एक सीमा ऐसी है जिसे आप किसी भी ट्यूनिंग से पार नहीं कर सकते। जब मॉडल लोड होता है, तो Ollama KV cache को समान और निश्चित स्लॉट्स में विभाजित कर देता है। एक खाली स्लॉट की मेमोरी का उपयोग व्यस्त स्लॉट द्वारा नहीं किया जा सकता है, और मॉडल को अनलोड किए बिना स्लॉट की संख्या बदली नहीं जा सकती। यह डिज़ाइन एक व्यक्ति, एक छोटी टीम या कोडिंग एजेंट के लिए उपयुक्त है।
कई उपयोगकर्ताओं के लिए बनाए गए सर्वर अलग तरह से काम करते हैं। वे मांग के अनुसार KV cache को छोटे पेजों में आवंटित करते हैं और आने वाले अनुरोधों को पहले से चल रहे बैच में जोड़ देते हैं, जिससे मेमोरी का उपयोग निश्चित विभाजन के बजाय वास्तविक मांग के अनुसार होता है। यदि आपका लक्ष्य एक GPU पर बड़ी संख्या में समवर्ती उपयोगकर्ताओं को संभालना है, तो यह आर्किटेक्चरल अंतर OLLAMA_NUM_PARALLEL के किसी भी मान से अधिक मायने रखता है। Ollama और vLLM के बीच तुलना वह स्थान है जहाँ आपको यह निर्णय लेना चाहिए। हालाँकि, केवल सिद्धांत के आधार पर न बदलें: एक अलग सर्वर को संचालित करना अधिक जटिल है, और यदि आपका ट्रैफ़िक कुछ ही लोगों का है, तो इन-बिल्ट व्यवहार ही सही समाधान है।
अपने थ्रूपुट और टाइम टू फर्स्ट टोकन (time to first token) को मापें
टोकन प्रति सेकंड (tokens per second) के प्रकाशित आंकड़े किसी और के GPU, मॉडल, क्वांटाइजेशन, कॉन्टेक्स्ट लेंथ और प्रॉम्प्ट पर आधारित होते हैं। इनमें से कोई भी आपके सेटअप से मेल नहीं खाता है, इसलिए किसी भी आंकड़े को केवल एक अनुमान मानें और अपने सामने मौजूद मशीन पर स्वयं मापें।
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))}'इसे एक स्लॉट के साथ चलाएं, फिर उस कॉन्करेंसी (concurrency) पर दोबारा चलाएं जिसकी आप वास्तव में अपेक्षा करते हैं। इसके बाद उन दो आंकड़ों की तुलना करें जो यह तय करते हैं कि उपयोगकर्ता संतुष्ट होंगे या नहीं: टाइम टू फर्स्ट टोकन और प्रति रिक्वेस्ट टोकन प्रति सेकंड। जैसे-जैसे स्लॉट बढ़ाए जाते हैं, प्रति रिक्वेस्ट थ्रूपुट हमेशा गिरता है। मुख्य प्रश्न यह है कि क्या यह गिरावट उस स्तर से अधिक है जिसे आपके उपयोगकर्ता स्वीकार करेंगे। लोकल LLM पर टोकन प्रति सेकंड मापना इस विधि को अधिक विस्तार से कवर करता है, जिसमें यह भी शामिल है कि रन के बीच प्रॉम्प्ट को स्थिर कैसे रखा जाए।
एक public endpoint जिसमें बड़ी queue हो, वह denial of service का लक्ष्य बन सकता है
OLLAMA_HOST=0.0.0.0:11434 सेट करने से API हर interface पर उपलब्ध हो जाता है, और Ollama में कोई built-in authentication नहीं है। default queue वाला एक open endpoint किसी भी व्यक्ति से 512 waiting requests स्वीकार कर लेगा। इस queue को भरने में हमलावर का लगभग कोई खर्च नहीं होता: लंबे prompts, कोई login नहीं, कोई rate limit नहीं, और कोई बिल नहीं। इसके परिणामस्वरूप आपके अपने users को 503 responses मिलते हैं या लंबा इंतज़ार करना पड़ता है, और मशीन हर समय व्यस्त रहती है।
listener को loopback पर रखें और इसे SSH tunnel या private network के माध्यम से access करें, या इसके सामने authentication और rate limiting लगाएँ। Ollama API endpoint को सुरक्षित करना इन दोनों तरीकों को कवर करता है। इसके बाद ही queue को tune करें, क्योंकि queue की लंबाई केवल एक capacity setting है, और यह किसी चीज़ की सुरक्षा नहीं करती है।
FAQ
मेरी दूसरी Ollama request पहली के पूरा होने तक क्यों प्रतीक्षा करती है?
क्योंकि OLLAMA_NUM_PARALLEL का डिफ़ॉल्ट मान 1 है, इसलिए एक लोड की गई model एक समय में केवल एक request चलाती है और बाकी कतार में प्रतीक्षा करती हैं। प्रतीक्षा करने वाली request अपना HTTP connection खुला रखती है और जब तक slot खाली नहीं होता, कोई डेटा नहीं भेजती, जो client side से एक धीमी model जैसा दिखता है। इसका पता timing के पैटर्न से चलता है: एक लंबा pause और फिर पूरी गति से text आना कतार (queue) का संकेत है, जबकि पहले token से ही धीमी गति से text आना model के धीमे होने का संकेत है। systemd drop-in के साथ slot की संख्या बढ़ाएं और service को restart करें।
"server busy, please try again. maximum pending requests exceeded" का क्या अर्थ है?
यह Ollama का queue overflow error है, जो HTTP status 503 के साथ आता है। प्रतीक्षा कर रही requests की संख्या OLLAMA_MAX_QUEUE तक पहुँच गई है (जिसका डिफ़ॉल्ट मान 512 है), इसलिए सबसे नई request को कतार में जोड़ने के बजाय reject कर दिया गया। यह memory error या model error नहीं है। कतार की सीमा बढ़ाने से callers को केवल rejection से पहले अधिक प्रतीक्षा करनी पड़ेगी, इसलिए वास्तविक समाधान यह है कि यदि आपके पास VRAM है तो अधिक slots जोड़ें, incoming load कम करें, या सामने एक ऐसी queue लगाएँ जो retry और prioritize कर सके।
क्या OLLAMA_NUM_PARALLEL बढ़ाने से Ollama तेज हो जाता है?
नहीं। यह एक ही समय में अधिक requests को चलने की अनुमति देता है, और उनमें से प्रत्येक request अकेले चलने की तुलना में धीमी होती है, क्योंकि वे एक ही GPU साझा करती हैं। यह KV cache को भी बढ़ा देता है, क्योंकि Ollama आपके context length को slot count से गुणा करके runner शुरू करता है। यदि परिणाम VRAM में फिट नहीं होता है, तो Ollama layers को CPU पर धकेल देता है और हर request धीमी हो जाती है, यहाँ तक कि बिना किसी प्रतिस्पर्धा वाली एक अकेली request भी। बदलाव के बाद ollama ps की जाँच करें और सुनिश्चित करें कि PROCESSOR column अभी भी 100% GPU दिखा रहा है।
क्या इन variables को बदलने के बाद मुझे Ollama को restart करने की आवश्यकता है?
हाँ। server इन्हें startup पर पढ़ता है, और एक चल रही model उसी slot count को बनाए रखती है जो launch के समय उसके runner process में fix हो गया था। sudo systemctl edit ollama.service के साथ drop-in को edit करें, फिर sudo systemctl daemon-reload और sudo systemctl restart ollama चलाएँ। systemctl show ollama --property=Environment के साथ पुष्टि करें, और फिर journalctl -u ollama में server config line की जाँच करें, जो उस environment को सूचीबद्ध करती है जिसे server ने वास्तव में लोड किया है।
मुझे कितने parallel slots सेट करने चाहिए?
1 से शुरू करें और एक-एक करके बढ़ाएँ। हर चरण के बाद, Ollama को restart करें, model लोड करने के लिए एक request भेजें, और ollama ps चलाएँ। उस अंतिम मान पर रुकें जहाँ PROCESSOR अभी भी 100% GPU दिखाता है और SIZE column आपके द्वारा serve किए जाने वाले सबसे लंबे context के लिए जगह छोड़ता है। फिर अपने वास्तविक concurrency के तहत उस setting पर time to first token और tokens per second मापें, और यदि प्रति request गति आपके users की सहनशीलता से कम हो जाए, तो एक कदम पीछे हट जाएँ।