SSD Nodes Learn 🎉 VPS $5.50/ماہ سے
تعلیمی Matt Connorتحریر: Matt Connor · اپ ڈیٹ شدہ 2026-08-13

self-hosted LLM 5 صارفین پر سست کیوں ہو جاتا ہے؟

ایک صارف ٹھیک، مگر 5 پر رفتار ختم؟ Ollama کا default 1 ہے؛ batching، KV cache، prefill اور queue depth بتاتے ہیں کہ server بیک وقت کتنے صارفین سنبھالے گا۔

مزید صارفین آنے پر self-hosted LLM سست کیوں ہو جاتا ہے؟

self-hosted LLM اس وقت 5 بیک وقت صارفین پر رک جاتا ہے جب server اب بھی ایک وقت میں صرف ایک جواب تیار کر رہا ہو اور باقی چار صارفین queue میں انتظار کر رہے ہوں۔ Ollama کی documentation default کے بارے میں واضح ہے: OLLAMA_NUM_PARALLEL "ہر model کے لیے ایک ہی وقت میں process کی جانے والی parallel requests کی زیادہ سے زیادہ تعداد ہے، اور default 1 ہے۔" کچھ خراب نہیں ہوا۔ آپ کے 5 میں سے 4 صارفین اپنی باری کا انتظار کر رہے ہیں۔

اس کا حل عموماً بڑا box نہیں ہوتا۔ ضرورت ایسے serving engine کی ہوتی ہے جو اسی forward pass میں متعدد requests کو model سے گزار سکے، اور اتنی اضافی memory کی بھی جو اس دوران تمام صارفین کی گفتگو محفوظ رکھ سکے۔ دونوں حصے اہم ہیں، لیکن اصل حد دوسرا حصہ طے کرتا ہے۔

ہر request کے دو مراحل

Prefill پورے prompt کو ایک ساتھ پڑھتا ہے اور اس کے لیے attention cache بناتا ہے۔ Prompt کا ہر token model سے بیک وقت گزرتا ہے، اس لیے prefill ایک بڑی matrix multiply ہوتی ہے اور اس کی رفتار arithmetic throughput سے محدود ہوتی ہے۔ اس کے بعد decode جواب کو ایک وقت میں ایک token لکھتا ہے۔ ہر token کے لیے model کے مکمل weights کو دوبارہ memory سے پڑھنا پڑتا ہے، جبکہ اس ایک token پر ہونے والی arithmetic بہت کم ہوتی ہے۔ Decode کی رفتار memory bandwidth سے محدود ہوتی ہے۔

یہی عدم توازن batching کے مؤثر ہونے کی بنیادی وجہ ہے۔ ایک user کے لیے decode ہر token پر، فرض کریں، 5 GB weights پڑھتا ہے اور زیادہ تر arithmetic units غیر استعمال شدہ رہتے ہیں۔ دوسری request شامل کرنے پر engine وہی 5 GB ایک بار پڑھتا ہے، پھر اسی سے دو tokens کا حساب کرتا ہے۔ دوسرے user کی اضافی لاگت تقریباً کوئی نہیں ہوتی۔ Requests کو سختی سے ایک کے بعد ایک process کرنا اس فائدے کو ضائع کر دیتا ہے۔

دو numbers سے معلوم ہوتا ہے کہ user کو کیا محسوس ہوتا ہے۔ TTFT (time to first token) queue wait اور prefill کا مجموعہ ہے۔ ITL (inter-token latency) streamed tokens کے درمیان وقفہ ہے، اور اسے decode متعین کرتا ہے۔ سست server عموماً ان میں سے کسی ایک مرحلے میں سست ہوتا ہے، اور دونوں کے لیے حل ایک جیسے نہیں ہوتے۔

Static batching سب کو سب سے سست جواب کا انتظار کراتی ہے

Static batching اس کا سادہ طریقہ ہے، اور جب آپ application code میں خود requests کو گروپ کرتے ہیں تو یہی حاصل ہوتا ہے۔ Engine N requests جمع کرتا ہے، انہیں ایک ساتھ چلاتا ہے، اور ہر slot کو اس وقت تک روکے رکھتا ہے جب تک گروپ میں سب سے طویل generation مکمل نہ ہو جائے۔

ایک صارف کی طرف سے مانگا گیا 1,200 token کا خلاصہ چار ایک سطری جوابات کو batch میں مقید رکھتا ہے، کیونکہ batch اس وقت تک کوئی slot خالی نہیں کرتی جب تک اس کے سب سے سست رکن کا کام مکمل نہ ہو جائے۔

اس کے دو نقصانات ہیں۔ مکمل ہو جانے والی sequences ایسے slots پر قابض رہتی ہیں جو کوئی مفید computation نہیں کر رہے ہوتے، اس لیے output lengths مختلف ہونے پر مؤثر throughput کم ہو جاتی ہے، جبکہ chat output lengths میں کافی زیادہ فرق ہوتا ہے۔ batch بننے کے ایک step بعد آنے والی request کو شروع ہونے سے پہلے پورے batch کے خالی ہونے کا انتظار کرنا پڑتا ہے، یعنی اس کا TTFT کسی دوسرے شخص کے طویل جواب سے متعین ہوتا ہے۔

Continuous batching ہر token پر requests کو شامل اور فارغ کرتا ہے

Continuous batching ایک decoding step کی سطح پر scheduling کرتا ہے۔ ہر step کے بعد scheduler ان sequences کو ہٹا دیتا ہے جنہوں نے ابھی اپنا stop token جاری کیا ہو، پھر منتظر requests کو خالی slots میں شامل کرتا ہے۔ جو reply step 40 پر ختم ہوتا ہے، وہ اپنا slot step 40 پر خالی کر دیتا ہے، batch کے اختتام پر نہیں۔

یہ کوئی غیر معمولی طریقہ نہیں ہے۔ llama-server میں -cb, --cont-batching کو بطور "continuous batching (جسے dynamic batching بھی کہا جاتا ہے) فعال کرنا ہے یا نہیں (default: enabled)" document کیا گیا ہے، اور vLLM اسی تصور کے گرد بنایا گیا ہے۔ Ollama متوازی requests بھی serve کرتا ہے۔ default صرف تعداد کو one تک محدود کرتا ہے۔ اسی لیے بہت سے لوگ یہ نتیجہ نکالتے ہیں کہ ان کا hardware concurrency نہیں چلا سکتا، حالانکہ ان کی configuration نے اسے منع کیا ہوتا ہے۔

شائع شدہ continuous batching نتائج عموماً ایسی datacenter cards پر ناپے جاتے ہیں جن میں اضافی compute capacity اور cache کے لیے دسیوں gigabytes دونوں موجود ہوتے ہیں۔ ان نتائج کا رجحان آپ کے box پر بھی لاگو ہوتا ہے۔ ان کی مقدار لاگو نہیں ہوتی، اور نیچے دیا گیا memory section اس کی وجہ بیان کرتا ہے۔

Prefill اسی compute کے لیے decode سے مقابلہ کرتا ہے

جب چار replies stream ہو رہی ہوں اور اسی دوران نئی request آئے، تو پہلے اس کے prompt کا prefill کرنا ضروری ہوتا ہے، اور prefill میں compute زیادہ استعمال ہوتا ہے۔ اگر scheduler اس prefill کے لیے الگ step دے، تو اس دوران چاروں streaming users کو کوئی token نہیں ملتا۔ طویل prompt کی صورت میں ہر کھلی window میں یہ وقفہ نمایاں ہوتا ہے۔ جب لوگ کہتے ہیں کہ کسی دوسرے شخص کے send کرنے پر server رک رک کر چلتا ہے، تو ان کی مراد یہی stutter ہوتی ہے۔

Chunked prefill طویل prompt کو حصوں میں تقسیم کرتا ہے اور ہر حصے کو جاری decodes کے اسی step میں شامل کرتا ہے۔ vLLM کی tuning guide اس tradeoff کو براہِ راست بیان کرتی ہے: کم chunk budgets سے "بہتر ITL حاصل ہوتا ہے کیونکہ decodes کو سست کرنے والے prefills کم ہوتے ہیں"، جبکہ زیادہ values سے "بہتر time to first token (TTFT) حاصل ہوتا ہے کیونکہ ایک batch میں زیادہ prefill tokens process کیے جا سکتے ہیں"۔ آپ کو طے کرنا ہوتا ہے کہ کس user experience کو ترجیح دینی ہے: اس شخص کو جسے reply شروع ہونے کا انتظار ہے، یا ان لوگوں کو جو text stream ہوتے دیکھ رہے ہیں۔

Prompt کی لمبائی طے کرتی ہے کہ یہ مسئلہ کتنا شدید ہوگا۔ 200 token کے answer کے مقابلے میں 6,000 token کا prompt، prefill کے 6,000 tokens کا کام پیدا کرتا ہے، جبکہ decode کے صرف 200 steps ہوتے ہیں۔ Retrieval-augmented chat اور طویل system prompts دونوں آپ کو اسی صورتِ حال میں لے جاتے ہیں۔ اس لیے prefill معمولی اضافی کام نہیں رہتا بلکہ وہ عمل بن جاتا ہے جس کا users انتظار کرتے ہیں۔ جب طویل حصہ بار بار دہرایا جائے تو 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 کہتے ہیں۔ اسی کی وجہ سے decode ہر نئے token کے لیے پورے prompt کو دوبارہ calculate نہیں کرتا۔ فی token اس کا سائز ماڈل کی ساخت سے متعین ہوتا ہے: 2 (ایک key اور ایک value) کو layer count، key/value heads کی تعداد، head dimension، اور ہر value کے لیے bytes سے ضرب دیں۔ یہ اعداد ماڈل کے config.json سے حاصل کریں۔

اس حساب کو ایک بار کر لیں تو حد واضح ہو جاتی ہے۔ 36 layers، 8 key/value heads اور 128 head dimension والے عام 8B model میں، اگر cache 16-bit میں رکھی جائے، تو فی token لاگت 2 36 8 128 2 bytes ہوتی ہے۔ یہ 147,456 bytes، یعنی تقریباً 144 KiB، ہے۔ اس لیے 8,192 tokens والی ایک گفتگو کو تقریباً 1.2 GB cache درکار ہوتی ہے۔ ایسی پانچ گفتگوؤں کو weights کے علاوہ تقریباً 6 GB درکار ہوں گے۔ یہی اس سوال کا حقیقی جواب ہے کہ کتنے صارفین بیک وقت چل سکتے ہیں۔

Concurrency context کو کئی گنا بڑھا دیتی ہے، اور tools یہ بات واضح طور پر بتاتے ہیں۔ Ollama کے FAQ میں لکھا ہے: "کسی model کے لیے parallel request processing کرنے سے context size، parallel requests کی تعداد کے مطابق بڑھ جاتا ہے۔ مثال کے طور پر، 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 کے لیے دستیاب گنجائش کم ہو جاتی ہے۔ فی-slot context کا اندازہ لگانے کے بجائے اسے startup log سے پڑھیں۔

vLLM اس کے بجائے پہلے سے memory مختص کرتا ہے۔ --gpu-memory-utilization (default 0.92) "model executor کے لیے استعمال کی جانے والی GPU memory کا حصہ" ہے۔ weights کے بعد جو memory بچتی ہے، وہ paged KV pool بن جاتی ہے۔ جب یہ pool کم پڑنے لگتا ہے تو scheduler request کو fail کرنے کے بجائے اسے 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 کو بری طرح متاثر کر سکتے ہیں۔" یہ log line اس بات کی بہترین وضاحت ہے کہ ایک بدقسمت صارف نے باقی سب کے مقابلے میں بہت زیادہ انتظار کیوں کیا، جبکہ average latency معمول کے مطابق دکھائی دے رہی تھی۔ cumulative count log کرنے کے لیے disable_log_stats=False set کریں، یا vLLM کے فراہم کردہ Prometheus metrics سے preemption counter پڑھیں۔

2، 5 اور 20 بیک وقت صارفین پر کیا تبدیل ہوتا ہے

دو صارفین۔ اضافی cache والے GPU پر اثر تقریباً نظر نہیں آتا، کیونکہ دوسری decode stream پہلے stream کے ساتھ چلتی ہے اور اضافی وقت بہت کم درکار ہوتا ہے۔ صرف CPU والے 4 سے 8 GB RAM کے VPS پر یہ مفت نہیں ہوتا: دونوں streams محدود تعداد میں موجود vCPUs اور اسی RAM bandwidth کو استعمال کرتی ہیں، اس لیے ہر صارف کو تقریباً نصف tokens per second ملتے ہیں، جبکہ cache کی طلب بھی دوگنی ہو جاتی ہے اور دستیاب budget بہت کم ہوتا ہے۔

پانچ صارفین۔ یہاں default settings ناکافی ہونے لگتی ہیں، اور مسئلہ ابتدا میں queue کا ہوتا ہے۔ OLLAMA_NUM_PARALLEL کو 1 پر رکھنے سے چار افراد اس صارف کے منتظر رہتے ہیں جس نے طویل جواب طلب کیا ہو، اور اپنی باری آنے پر ہر صارف کو معمول کی رفتار ملتی ہے۔ parallel count بڑھانے سے مسئلہ اپنی نوعیت بدل لیتا ہے: 8K context کے 5 slots کے لیے 40K tokens کی cache درکار ہوتی ہے۔ اگر یہ VRAM میں نہ سما سکے تو engine layers کو system RAM میں offload کرتا ہے، اور اگر یہ RAM میں بھی نہ سما سکے تو machine swap استعمال کرنے لگتی ہے اور tokens per second تیزی سے کم ہو جاتا ہے۔

20 صارفین۔ chat UI میں موجود 20 انسان عموماً 20 بیک وقت requests نہیں بھیج رہے ہوتے، اور hardware خریدنے سے پہلے سمجھنے کے لیے یہ سب سے اہم نکتہ ہے۔ کوئی شخص جواب پڑھنے کے بعد اگلی باری سے پہلے 20 سے 60 seconds تک سوچتا ہے، اس لیے اس کے session کا زیادہ تر وقت idle ہوتا ہے۔ اس کے برعکس 20 agents یا 20 document summarisation jobs میں 20 حقیقی streams ہوتی ہیں اور idle time بالکل نہیں ہوتا۔ اس کے لیے مختلف machine درکار ہوتی ہے۔

آپ کے صارفین concurrent ہیں، یا صرف logged in ہیں؟

کسی بھی sizing سے پہلے معلوم کریں کہ کتنی requests in flight ہوتی ہیں۔ حساب سادہ ہے: in flight 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 in flight ہیں۔
  3. slot count اس قدر سے کچھ زیادہ رکھیں، پھر اسے memory کے مقابل جانچیں: slots کو فی request درکار context سے ضرب دینے پر حاصل قدر، آپ کے پاس موجود cache tokens میں سما جانی چاہیے۔
  4. queue مختصر رکھیں تاکہ overflow تیزی سے اور واضح طور پر fail ہو۔

دستیاب cache tokens، weights لوڈ ہونے کے بعد بچنے والی free memory کو اوپر والے section میں دی گئی فی token cost سے تقسیم کرنے کے برابر ہیں۔ 24 GB card پر 8B model کو 16-bit میں چلانے سے weights تقریباً 16 GB memory لیتے ہیں، اور default utilisation پر تقریباً 6 GB قابلِ استعمال cache باقی رہتی ہے، جو تقریباً پانچ 8K conversations کے لیے کافی ہے۔ مزید requests کو fit کرنے کے لیے فی request context مختصر کریں، یا cache کو 8-bit میں store کریں (llama-server میں --cache-type-k q8_0 لگتے ہیں)۔ دونوں طریقے کسی چیز کی قیمت پر concurrency بڑھاتے ہیں، اور hardware خریدنے سے پہلے اس trade-off کی حقیقت سمجھنا مفید ہے: GPU VPS API tokens کے مقابل کب break even ہوتا ہے۔

جہاں Ollama کی ڈیفالٹ ترتیبات کافی نہیں رہتیں

متوازی درخواستوں کی تعداد service unit کے ذریعے بڑھائیں، کیونکہ shell export سے systemd کے زیر انتظام 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 دکھانے چاہییں جو آپ نے ابھی set کیے ہیں۔ اگر ایسا نہ ہو تو drop-in save نہیں ہوا، اور آپ جو کچھ بھی مزید کریں گے اس کا کوئی فائدہ نہیں ہوگا۔ اس کے بعد ollama ps loaded model کی فہرست دکھاتا ہے۔ اس کا size صرف weights کے size سے بڑا ہوگا، کیونکہ 8,192 tokens کے 4 slots ان کے ساتھ 32,768 tokens کی cache reserve کرتے ہیں۔ اگر آپ کو توقع تھی کہ model مکمل طور پر GPU پر ہوگا، لیکن PROCESSOR column میں model کا کچھ حصہ CPU پر دکھائی دے، تو اس کا مطلب ہے کہ آپ نے card میں باقی دستیاب گنجائش سے زیادہ cache مانگی ہے۔ دونوں میں سے ایک number کم کریں۔

Queue کی default قدر کا دوبارہ جائزہ لینا چاہیے۔ Ollama زیادہ سے زیادہ OLLAMA_MAX_QUEUE requests queue میں رکھتا ہے، اور "the default is 512"۔ اس حد سے تجاوز ہونے پر یہ "with a 503 error indicating the server is overloaded" جواب دیتا ہے۔ ایک ایسے box پر 512 requests کی queue، جو ایک وقت میں 4 requests serve کرتا ہو، ایسا وعدہ ہے جسے آپ پورا نہیں کر سکتے، کیونکہ position 300 پر موجود client اپنی باری آنے سے بہت پہلے timeout ہو جائے گا۔ مختصر queue ایسا error واپس کرتی ہے جسے آپ کی application retry یا report کر سکتی ہے۔ یہ ایسے spinner سے بہتر ہے جو کبھی مکمل نہ ہو۔

حقیقی طور پر test کریں۔ ایک ہی وقت میں دو terminals سے دو requests بھیجیں اور دونوں کو monitor کریں۔ اگر دوسری request سے پہلی request مکمل ہونے تک کوئی output نہ آئے تو parallel setting لاگو نہیں ہوئی۔

جب باقاعدہ serving engine اپنی لاگت پوری کرنے لگے

vLLM کا اضافی setup اس وقت قابلِ جواز ہوتا ہے جب آپ کے پاس کچھ اضافی گنجائش والا GPU ہو اور تقریباً چار سے زیادہ requests واقعی بیک وقت processing میں ہوں۔ اس کا scheduler ہر token کی سطح پر کام کرتا ہے، اس کا cache pages میں تقسیم ہوتا ہے تاکہ خالی fragments دوبارہ استعمال ہو سکیں، اور یہ اضافی VRAM کو idle چھوڑنے کے بجائے اسے 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 پر مشتمل reply کا مطلب ہے کہ server چل رہا ہے اور model load ہو چکا ہے۔ load کے دوران دو اہم knobs --max-num-seqs، یعنی "ایک iteration میں process کیے جانے والے sequences کی زیادہ سے زیادہ تعداد"، اور --max-num-batched-tokens، یعنی "ایک iteration میں process کیے جانے والے tokens کی زیادہ سے زیادہ تعداد"، ہیں۔ پہلا concurrency کی حد مقرر کرتا ہے۔ دوسرا پہلے بیان کیے گئے chunked prefill budget کو محدود کرتا ہے۔

اگر بیک وقت processing میں تقریباً چار سے کم requests ہوں، یا machine میں supported GPU نہ ہو، تو vLLM complexity بڑھاتا ہے لیکن فائدہ کم دیتا ہے۔ اسے CUDA-class card درکار ہوتا ہے اور یہ startup کے وقت memory کا زیادہ تر حصہ مختص کر لیتا ہے، جو 4 سے 8 GB VPS پر نامناسب trade-off ہے۔ ایسی صورت میں مختصر context اور آپ کے قابو میں موجود queue کے ساتھ چھوٹا model بہتر انتخاب ہے۔ Ollama اور vLLM بطور serving engines کیسے مختلف ہیں میں اس انتخاب کی مکمل وضاحت ہے، جبکہ VPS پر Qwen 3 8B چلانا دکھاتا ہے کہ ایک اضافی user شامل کرنے سے پہلے mid-sized model کو کن وسائل کی ضرورت ہوتی ہے۔

لوک کہانی جس tradeoff کو چھپا دیتی ہے

Continuous batching مجموعی throughput بڑھاتی ہے، اور عموماً median latency بھی بہتر کرتی ہے، کیونکہ queue میں موجود request جلد شروع ہو جاتی ہے۔ Tail latency اس کے برعکس بڑھتی ہے، لیکن اس پہلو کا ذکر شاذ ہی کیا جاتا ہے۔

ہر step میں اضافی sequence شامل ہونے سے تھوڑا مزید کام ہوتا ہے، اس لیے batch بھرنے کے ساتھ سب کے لیے ITL بڑھتا ہے۔ کسی نئی arrival کے prefill میں step کا وہ حصہ استعمال ہوتا ہے جو بصورتِ دیگر streaming users کو ملتا۔ Cache پر دباؤ کے دوران scheduler preempt کرتا ہے، جس سے آدھی تیار request اپنے prefill کے آغاز پر واپس چلی جاتی ہے۔

Chat UI averages نہیں بلکہ tails دکھاتا ہے۔ اگر stream جملے کے درمیان دو سیکنڈ کے لیے رک جائے تو مجموعی completion time اچھا ہونے کے باوجود یہ broken محسوس ہوتی ہے۔ اپنی متوقع load کے تحت p95 TTFT اور p95 ITL ناپیں، اور mean tokens per second کو capacity number سمجھیں، تجربے کی مکمل عکاسی نہ سمجھیں۔

عملی setting اسی سے اخذ ہوتی ہے۔ Concurrency کو memory کی اجازت سے قدرے کم حد پر رکھیں، تاکہ engine کو کبھی preempt نہ کرنا پڑے۔ مختصر اور قابلِ پیش گوئی queue، ایسی گہری batch سے بہتر ہے جو بار بار thrash کرے، کیونکہ وہ user زیادہ مطمئن ہوتا ہے جو چار سیکنڈ انتظار کے بعد مسلسل stream دیکھے، بہ نسبت اس user کے جو فوراً شروع کرے لیکن دو بار رک جائے۔

جب رفتار سست ہو تو کیا جانچیں

ہر صارف کا تجربہ معمول کے مطابق ہے، لیکن انتظار طویل ہے۔ یہ queue ہے، رفتار کا مسئلہ نہیں۔ پہلے parallel setting جانچیں۔ ماڈل درست طور پر service دے رہا ہے، لیکن ایک وقت میں صرف ایک request process ہو رہی ہے۔

Ollama سے HTTP 503 موصول ہو رہا ہے۔ queue بھر چکی ہے۔ یا تو machine واقعی اپنی capacity تک پہنچ چکی ہے، یا OLLAMA_MAX_QUEUE کو جان بوجھ کر کم رکھا گیا ہے تاکہ load کم کیا جا سکے۔ یہی اس setting کا مطلوبہ مقصد ہے۔

CPU machine پر load کے دوران tokens per second اچانک کم ہو جاتی ہے۔ مسئلہ پیدا ہوتے وقت vmstat 1 چلائیں۔ si اور so columns میں nonzero values کا مطلب ہے کہ machine swapping کر رہی ہے، اس لیے ہر token کے لیے weights disk سے پڑھے جا رہے ہیں۔ کوئی configuration change اس مسئلے کو حل نہیں کر سکتی۔ ماڈل کا سائز یا slot count کم کریں۔

ہر 10 صارفین میں سے 1 باقی صارفین کے مقابلے میں کہیں زیادہ دیر انتظار کرتا ہے۔ vLLM log میں preempted تلاش کریں۔ عموماً وجہ preemption اور اس کا recompute ہوتا ہے۔ اس کا مطلب ہے کہ آپ کی اجازت دی گئی context length کے لیے cache پر ضرورت سے زیادہ load ہے۔

سرور idle ہونے کے باوجود TTFT خراب ہے۔ یہ prefill کا مسئلہ ہے، concurrency کا نہیں۔ پہلے token کے ظاہر ہونے سے پہلے طویل prompts حقیقی processing time لیتے ہیں۔ اس لیے hardware دیکھنے سے پہلے prompt size اور prefix caching جانچیں۔

FAQ

میرے self-hosted LLM کے سست ہونے کی کیا وجہ ہے جب دوسرا شخص اسے استعمال کرتا ہے؟

اکثر یہ سست نہیں ہوتا، بلکہ queue میں چلا جاتا ہے۔ Ollama میں OLLAMA_NUM_PARALLEL کی default قدر 1 ہوتی ہے، اس لیے دوسری request پہلی request کے آخری token کے اجرا تک انتظار کرتی ہے۔ دونوں صورتوں میں فرق کرنے کے لیے ایک صارف کے stream کا وقت اس وقت ناپیں جب دوسرا صارف انتظار کر رہا ہو: اگر stream شروع ہونے کے بعد اس کی tokens per second رفتار معمول کے مطابق ہو تو مسئلہ queue کا ہے، اور parallel count بڑھانے سے حل ہو جائے گا۔ اگر دونوں streams نصف رفتار سے چلیں تو آپ واقعی memory bandwidth شیئر کر رہے ہیں، اور یہ hardware کی حد ہے۔

ایک چھوٹا GPU کتنے concurrent users کو سروس دے سکتا ہے؟

صارفین کی تعداد نہیں، memory گنیں۔ پہلے weights، پھر KV cache کا حساب کریں۔ ہر active conversation کے ہر token کے لیے اس کی لاگت 2 times layers times key/value heads times head dimension times bytes ہوتی ہے۔ ایک عام 8B model میں 36 layers، 8 key/value heads اور head dimension 128 ہو تو 16-bit میں فی token تقریباً 144 KiB درکار ہوتی ہے۔ اس لیے 8,192 tokens کی conversation کے لیے تقریباً 1.2 GB درکار ہوگا۔ 16-bit میں اس model کو رکھنے والے 24 GB card میں cache کے لیے تقریباً 6 GB بچتی ہے۔ اس سے full context پر تقریباً پانچ conversations چل سکتی ہیں، یا context مختصر کرنے پر اس سے زیادہ۔

کیا continuous batching ہر صارف کے جواب کو سست کر دیتی ہے؟

Median latency عموماً بہتر ہوتی ہے، کیونکہ requests کو پوری batch کے مکمل ہونے تک انتظار نہیں کرنا پڑتا۔ Tail latency خراب ہو جاتی ہے۔ ہر اضافی sequence ہر decoding step میں مزید کام شامل کرتی ہے، نئی request کی prefill streaming users کے ایک step کا کچھ حصہ لے لیتی ہے، اور preempted request کو دو بار prefill کرنا پڑتا ہے۔ اوسط کے بجائے p95 inter-token latency ناپیں، کیونکہ chat window میں pauses واضح ہوتی ہیں، جبکہ average انہیں چھپا دیتی ہے۔

کیا مجھے OLLAMA_NUM_PARALLEL بڑھانا چاہیے یا vLLM پر منتقل ہونا چاہیے؟

پہلے parallel count بڑھائیں۔ یہ مفت ہے، صرف ایک drop-in file درکار ہوتی ہے، اور اس عام صورت کو حل کرتا ہے جس میں چار افراد ایک طویل جواب کے پیچھے queue میں کھڑے ہوتے ہیں۔ حد memory ہے: parallel requests اس context کو کئی گنا بڑھا دیتی ہیں جسے آپ کو برقرار رکھنا ہوتا ہے، اس لیے دیکھیں کہ layers CPU پر spill تو نہیں ہو رہیں۔ vLLM پر اس وقت منتقل ہوں جب GPU میں اضافی VRAM موجود ہو اور تقریباً چار سے زیادہ requests واقعی بیک وقت in flight ہوں، کیونکہ اسی مرحلے پر paged cache اور per-token scheduling اپنی لاگت سے زیادہ فائدہ دیتے ہیں۔

کیا زیادہ CPU cores سست LLM server کو ٹھیک کر سکتے ہیں؟

صارفین کو محسوس ہونے والے اہم حصے کے لیے نہیں۔ Decode ہر token کے لیے پورا model memory سے پڑھتا ہے، اس لیے یہ RAM bandwidth سے محدود ہوتا ہے۔ Bandwidth saturate ہونے کے بعد اضافی cores مزید فائدہ نہیں دیتے۔ Prefill cores کے ساتھ scale کرتا ہے، اس لیے زیادہ cores طویل prompts پر first token تک کا وقت کم کر سکتے ہیں۔ 4 سے 8 GB VPS پر عموماً اصل رکاوٹ memory capacity ہوتی ہے۔ اس لیے مؤثر حل زیادہ vCPUs کے بجائے چھوٹا model یا مختصر context ہوتا ہے۔