پہلا سکیلنگ کا مسئلہ شاذ و نادر ہی اچانک پیدا ہوتا ہے۔ تھوڑی دیر کے لیے سب کچھ ٹھیک ہے۔ صفحات تیزی سے لوڈ ہوتے ہیں، ڈیٹا بیس بمشکل ہی پسینہ بہاتے ہیں، اور ٹیمیں بنیادی ڈھانچے کے بارے میں زیادہ سوچے بغیر خصوصیات فراہم کرتی ہیں۔
پھر ٹریفک بڑھ جاتی ہے۔ آپ کی مہم نے بہت زیادہ کارکردگی کا مظاہرہ کیا ہے۔ مارکیٹ پلیس مقبول فروخت کنندگان کو آن بورڈ کرتی ہے۔ ہمارا SaaS پروڈکٹ دو کارپوریٹ اکاؤنٹس پر دستخط کرتا ہے۔
اچانک، /dashboard اس میں 300 ملی سیکنڈ کے بجائے 2 سیکنڈ لگتے ہیں۔ قطار والی ملازمتیں جو سیکنڈوں میں صاف ہو گئی تھیں منٹوں تک انتظار میں رہتی ہیں۔ ہم ہر سہ پہر ڈیٹا بیس CPU اسپائکس کا تجربہ کرتے ہیں۔
لہذا ایک اور ایپ سرور کو شامل کرنے سے جوابی وقت میں مشکل سے کمی آئے گی۔ اصل وجہ بڑی میزوں پر مسلسل سست سوالات تھے۔
اگر آپ نے کبھی Laravel کو پیداواری ماحول میں چلایا ہے، تو آپ نے شاید اس طرح کے ورژن کا تجربہ کیا ہوگا۔ اچھی خبر یہ ہے کہ Laravel کو بڑھانے کا مطلب فریم ورک کو ترک کرنا نہیں ہے۔ اس کا مطلب یہ ہے کہ یہ سیکھنا کہ دباؤ کہاں لاگو ہوتا ہے اور لوڈ ہونے پر آپ کی درخواست کو توقع کے مطابق انجام دینا۔
اس گائیڈ میں، آپ سیکھیں گے کہ کس طرح عام رکاوٹوں کو تلاش کرنا ہے، اپنے ڈیٹا بیس کو ٹیون کرنا ہے، Redis کو مؤثر طریقے سے استعمال کرنا ہے، سست کاموں کو قطاروں میں منتقل کرنا، APIs کو بہتر بنانا، اور پیداوار میں اپنے Laravel ایپلیکیشن کی نگرانی کرنا۔
اس میں سے کسی کو بھی بہادری سے دوبارہ لکھنے کی ضرورت نہیں ہے۔ سب سے بڑی جیت عام طور پر ناکارہ استفسارات کو ختم کرنے، سست کاموں کو قطاروں میں دھکیلنے، صحیح اشاریہ جات کو شامل کرنے، احتیاط سے منتخب کردہ ڈیٹا کو کیش کرنے، اور یہ پیمائش کرنے کے اصل کام سے حاصل ہوتی ہے کہ آیا ہر تبدیلی نے واقعی مدد کی ہے۔
شرطیں
اگر آپ پہلے ہی سے واقف ہیں تو آپ اس گائیڈ سے زیادہ سے زیادہ فائدہ اٹھائیں گے:
-
Laravel اور PHP کا استعمال کرتے ہوئے ایپلی کیشنز بنانا
-
فصیح سوالات لکھنا اور ڈیٹا بیس کو منتقل کرنا
-
قطاروں، کاموں، اور طے شدہ کمانڈز کا استعمال کریں۔
-
ڈیفالٹ ڈیٹا بیس استفسار کا منصوبہ پڑھیں
-
Laravel کو پروڈکشن سرور یا پلیٹ فارم پر تعینات کریں۔
-
پروڈکشن جیسے سیٹ اپ میں Redis اور MySQL یا PostgreSQL کے ساتھ کام کریں۔
انڈیکس
جب آپ کی Laravel ایپ بڑھنے لگتی ہے تو کیا ہوتا ہے؟
ٹریفک چھوٹی ناکارہیوں کو مستقل اخراجات میں بدل کر نظام کے رویے کو بدل دیتی ہے۔ ایک سوال جس میں 80 ملی سیکنڈ کا وقت لگتا ہے وہ بے ضرر ہے جب ایک گھنٹے میں سینکڑوں بار عمل میں لایا جائے۔ ایک ایسے صفحے پر جس کو فی منٹ ہزاروں ہٹس ملتے ہیں، جب فی صفحہ 30 مرتبہ ویو پر عمل کیا جاتا ہے تو وہی سوال صلاحیت کا مسئلہ بن جاتا ہے۔
دباؤ متوقع جگہوں پر ظاہر ہوتا ہے۔ مزید درخواستوں کا مطلب ہے زیادہ پی ایچ پی کارکن، زیادہ ڈیٹا بیس کنکشن، زیادہ قطار والیوم، اور مزید Redis کام۔
خواہ MySQL ہو یا PostgreSQL، ڈیٹا بیس عام طور پر حل کرنے والا پہلا مسئلہ ہوتا ہے۔ جب ملازمتیں اس سے زیادہ تیزی سے تخلیق کی جاتی ہیں کہ کارکنان انہیں استعمال کر سکتے ہیں، تو قطار کا بیک اپ لیا جاتا ہے۔ کیشنگ صرف اس صورت میں مددگار ثابت ہوتی ہے جب ہٹ ریٹ زیادہ رہیں اور کمی کو کنٹرول کیا جائے۔ اور ہر چیز کو افقی طور پر پیمانہ کرنا میلا کوڈ کو مہنگے کلاؤڈ اخراجات میں بدل سکتا ہے۔
اس لیے اسکیلنگ کو پیمائش سے شروع کرنے کی ضرورت ہے، اندازہ لگانے سے نہیں۔ اس سے پہلے کہ میں کچھ بھی تبدیل کروں، میں جاننا چاہتا ہوں کہ اصل میں سیر شدہ کیا ہے: CPU، ڈیٹا بیس I/O، لاک کنٹینشن، Redis لیٹنسی، قطار کی گہرائی، بیرونی API، یا بڑے پے لوڈز کی درخواست کریں۔
بڑھتی ہوئی Laravel ایپ میں ایک عام درخواست کئی تہوں سے گزرتی ہے۔ صارف ایک درخواست بھیجتا ہے، لوڈ بیلنسر اسے ایپ سرورز تک پہنچاتا ہے، اور Laravel Redis میں کیش شدہ نتائج کو چیک کرتا ہے۔ جب کوئی غلطی ہو جاتی ہے، تو یہ ڈیٹا بیس سے استفسار کرتا ہے، حسابی نتائج کو دوبارہ Redis میں اسٹور کرتا ہے، اور سست جانشینوں کو قطار میں کھڑا کرتا ہے۔ کارکن بعد میں اس کام کو اٹھا لیتا ہے اور لاراویل فوراً جواب دیتا ہے۔
اہم حصہ یہ ہے: مزید ایپ سرورز کو شامل کرنے سے کوئی اثر نہیں پڑے گا اگر سوالات سست ہیں، اشاریہ جات غائب ہیں، یا قطاریں اوورلوڈ ہیں۔ افقی اسکیلنگ صرف اس صورت میں ادائیگی کرتی ہے جب ان سرورز کے پیچھے مشترکہ انحصار کو برقرار رکھا جا سکے۔
Laravel کی عام رکاوٹیں۔
Laravel خود شاذ و نادر ہی اسکیلنگ کے مسائل کا سبب بنتا ہے۔ زیادہ تر مسائل اس سے پیدا ہوتے ہیں کہ ایپلیکیشن کوڈ ڈیٹا بیس، نیٹ ورک اور بیک گراؤنڈ ورکرز کے ساتھ کیسے بات چیت کرتا ہے۔
N+1 سوالات
ایک عام حملہ آور N+1 استفسار ہے۔ ماڈل کی فہرست لوڈ کریں، پھر آہستہ آہستہ ہر ماڈل کے رشتوں کو چھوئے۔
use App\Models\Post;
$posts = Post::latest()->take(50)->get();
foreach (\(posts as \)post) {
echo $post->author->name;
}
یہ پوسٹ کے لیے ایک سوال ہے اور فی مصنف ایک سوال ہے۔ یعنی ایک صفحے کے لیے 51 سوالات۔ اس کے بجائے، رشتوں کو فوری طور پر لوڈ کریں۔
use App\Models\Post;
$posts = Post::with('author')
->latest()
->take(50)
->get();
foreach (\(posts as \)post) {
echo $post->author->name;
}
پیداوار میں، یہ کپٹی ہے. کنٹرولرز میں، متعلقہ رسائی اکثر API وسائل، بلیڈ اجزاء، اور تصدیق کی جانچ کے اندر پوشیدہ ہوتی ہے جہاں یہ واضح نہیں ہوتا ہے۔
لاپتہ انڈیکس
انڈیکس کو شامل کرنا سب سے زیادہ منافع بخش تبدیلیوں میں سے ایک ہے۔ درج ذیل استفسار کریں:
\(orders = Order::where('account_id', \)accountId)
->where('status', 'paid')
->whereBetween('created_at', [\(start, \)end])
->latest()
->paginate(50);
اگر orders اگر آپ کے پاس لاکھوں قطاریں ہیں اور آپ کے پاس مفید جامع اشاریہ نہیں ہے، تو آپ کا ڈیٹا بیس ضرورت سے کہیں زیادہ قطاریں بازیافت کرے گا۔ ایسے اشاریہ جات شامل کریں جو آپ کے درحقیقت استفسار کے طریقے سے مماثل ہوں۔
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
public function up(): void
{
Schema::table('orders', function (Blueprint $table) {
$table->index(['account_id', 'status', 'created_at']);
});
}
public function down(): void
{
Schema::table('orders', function (Blueprint $table) {
$table->dropIndex(['account_id', 'status', 'created_at']);
});
}
};
تاہم، انڈیکس آزاد نہیں ہیں۔ یہ جگہ لیتا ہے اور لکھنے کو سست کرتا ہے۔ اصل اعادی استفسار کے نمونوں کے لیے شامل کریں، ہر اس کالم کے لیے نہیں جو استفسار میں ظاہر ہوتا ہے۔ where میں
غیر موثر شوقین لوڈنگ
آپ مخالف سمت میں بہت دور جھول سکتے ہیں۔ تمام رشتوں کو لوڈ کرنا "صرف اس صورت میں” میموری استعمال کرتا ہے اور درخواست میں غیر استعمال شدہ ڈیٹا کو منتقل کرتا ہے۔
$users = User::with([
'profile',
'teams',
'roles.permissions',
'invoices.lineItems.product',
])->get();
یہ ایڈمن کی تفصیلات والے صفحے کے لیے ٹھیک ہو سکتا ہے جو ایک صارف کو دکھاتا ہے۔ فہرست کے صفحہ پر، آپ ذمہ دار ہیں۔ فوری لوڈنگ کو محدود کریں اور صرف وہی کالم منتخب کریں جن کی آپ کو ضرورت ہے۔
$users = User::query()
->select(['id', 'name', 'email'])
->with([
'profile:id,user_id,avatar_url',
'teams:id,name',
])
->latest()
->paginate(25);
ایک انتباہ: تنگ منتخب فہرستیں بعد کے کوڈ کو توڑ سکتی ہیں جس سے ان کالموں کی توقع ہوتی ہے جو آپ نے لوڈ نہیں کیے ہیں۔ اس ٹکنالوجی کو پڑھنے پر مرکوز اینڈ پوائنٹس کے قریب رکھیں، جہاں فوائد واضح ہوں۔
ہم وقت ساز پروسیسنگ
ہائی ٹریفک ایپس کو مختصر ویب درخواستیں درکار ہوتی ہیں۔ ای میل بھیجنا، پی ڈی ایف بنانا، تھرڈ پارٹی APIs کو کال کرنا، امیجز کا سائز تبدیل کرنا، اور ایکسپورٹ بنانا عام طور پر درخواست کے چکر سے باہر ہوتے ہیں۔ یہ ورژن نقصان کا سبب بن سکتا ہے اگر:
public function store(Request $request)
{
\(order = Order::create(\)request->validated());
Mail::to(\(order->user)->send(new OrderReceipt(\)order));
return response()->json($order, 201);
}
اس کے بجائے، یہ کاموں کو قطار میں دھکیلتا ہے۔
public function store(StoreOrderRequest $request)
{
\(order = Order::create(\)request->validated());
SendOrderReceipt::dispatch($order->id);
return response()->json([
'id' => $order->id,
'status' => 'accepted',
], 202);
}
اب جواب کے اوقات آپ کے میل فراہم کنندہ پر منحصر نہیں ہیں۔ اگر آپ کے فراہم کنندہ کی دوپہر سست ہے، تو قطار اسے جذب کر لے گی اور آپ کو انتظار نہیں کرنا پڑے گا۔
بڑے پے لوڈ
ایک JSON ردعمل جو بہت بڑا ہے سلسلہ میں موجود ہر ایک کے لیے نقصان دہ ہے۔ یعنی، ایپ سرور جو اسے سیریلائز کرتا ہے، نیٹ ورک جو اسے فراہم کرتا ہے، اور کلائنٹ جو اسے پارس کرتا ہے۔ ایک عام غلطی یہ ہے کہ جب آپ سمری واپس کرنے کا ارادہ رکھتے ہوں تو پورے ماڈل کو واپس کر دیں۔
return User::with('orders', 'invoices', 'teams')->findOrFail($id);
اس کے بجائے، واضح API وسائل کی وضاحت کریں۔
use Illuminate\Http\Resources\Json\JsonResource;
class UserSummaryResource extends JsonResource
{
public function toArray($request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'avatar_url' => $this->profile?->avatar_url,
'plan' => $this->subscription_plan,
];
}
}
چھوٹے، سوچے سمجھے جوابی معاہدوں سے اختتامی قیمتوں کا اندازہ لگانا اور حادثاتی پابندی کو روکنا آسان ہو جاتا ہے۔
مہنگا شمولیت
جوائنز کارآمد ہیں، لیکن بڑے ٹیبلز پر مہنگے جوائنز ڈیٹا بیس کا وقت کھا سکتے ہیں، خاص طور پر جب غیر اشاریہ شدہ کالموں کو چھانٹتے یا فلٹر کرتے ہیں۔
$rows = DB::table('orders')
->join('users', 'users.id', '=', 'orders.user_id')
->join('accounts', 'accounts.id', '=', 'users.account_id')
->where('accounts.region', 'us-east')
->where('orders.status', 'paid')
->orderByDesc('orders.created_at')
->limit(100)
->get();
آپ کے پیمانے پر منحصر ہے، آپ کو چھوٹے فیلڈز کو غیر معمولی بنانے، رپورٹنگ ٹیبلز سے پہلے، یا مکمل طور پر بنیادی لین دین کے ڈیٹا بیس سے تجزیہ منتقل کرنے کی ضرورت پڑ سکتی ہے۔ غیر معمولی ہونے کو شکست کا اعتراف نہ سمجھیں۔ قابل اعتماد فیلڈ کاپی، جیسے account_id اوپر orders آپ گرم راستوں سے مہنگے جوڑوں کو ختم کر سکتے ہیں۔ آپ جو قیمت ادا کرتے ہیں وہ ڈپلیکیٹ ڈیٹا کو مستقل رکھنا ہے، اور یہ ایک قابل قدر تجارت ہو سکتی ہے۔
اپنے ڈیٹا بیس کو کیسے بہتر بنائیں
اگر آپ کی Laravel ایپ سست ہے، تو عام طور پر پہلی جگہ آپ کا ڈیٹا بیس ہوتا ہے۔
اصل استفسار کے پیٹرن کے ارد گرد انڈیکس شامل کریں۔
سست استفسار کے لاگز، ڈیٹا بیس میٹرکس، اور انتشار کے بجائے نشانات کے ساتھ شروع کریں۔ اگر آپ کی ایپ اکاؤنٹ کے لحاظ سے مسلسل فعال سبسکرپشنز تلاش کرتی ہے، تو ایک جامع انڈیکس بنائیں جو اس رسائی کے پیٹرن سے مماثل ہو۔
Schema::table('subscriptions', function (Blueprint $table) {
$table->index(['account_id', 'status', 'renews_at']);
});
پھر ہم ایک سوال لکھتے ہیں تاکہ ہم اصل میں انڈیکس کا استعمال کر سکیں۔
\(subscription = Subscription::where('account_id', \)accountId)
->where('status', 'active')
->where('renews_at', '>=', now())
->orderBy('renews_at')
->first();
دوڑنے کی عادت ڈالیں۔ EXPLAIN انڈیکس کو شامل کرنے کے بعد یہ دیکھنے کے لیے کہ آیا پلان بدل گیا ہے۔ اشاریہ جات جنہیں اصلاح کنندہ نظر انداز کرتا ہے وہ صرف اوور ہیڈ لکھتے ہیں۔
شوقین لوڈنگ کا جان بوجھ کر استعمال
فوری طور پر لوڈنگ سے میل کھاتا ہے جو اختتامی نقطہ اصل میں واپس کرتا ہے۔ فہرست کے اختتامی نکات کے لیے، تعلقات کو کم اور محدود رکھیں۔
$projects = Project::query()
->select(['id', 'account_id', 'name', 'updated_at'])
->withCount('openTasks')
->with([
'owner:id,name',
])
->where('account_id', $accountId)
->latest('updated_at')
->paginate(30);
جب آپ کو صرف نمبروں کی ضرورت ہو، withCount یہ حساب کرنے کے لیے پورے رشتے کو لوڈ کرنے سے بہتر ہے۔
$teams = Team::query()
->withCount([
'members',
'invitations as pending_invitations_count' => fn (\(query) => \)query->whereNull('accepted_at'),
])
->paginate(25);
میموری کی جگہ یکساں رہتی ہے، جو فہرست کے صفحات کے لیے تفصیلی صفحات کے مقابلے میں زیادہ اہم ہے۔
ہارڈ ویئر شامل کرنے سے پہلے سوالات کو بہتر بنائیں
ایک بڑی ڈیٹا بیس مثال کا استعمال آپ کو کچھ وقت خرید سکتا ہے۔ یہ ناکارہ سوالات کو بھی چھپاتا ہے جب تک کہ اگلی ٹریفک چھلانگ انہیں دوبارہ بے نقاب نہیں کر دیتی۔ ایک بڑی مشین خریدنے سے پہلے معلوم کریں کہ کون سا سوال آپ کو سب سے زیادہ خرچ کرے گا۔ مقامی یا اسٹیجنگ ماحول میں، سست ماحول میں لاگ ان کرنا آسان ہے۔
use Illuminate\Database\Events\QueryExecuted;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
DB::listen(function (QueryExecuted $query) {
if ($query->time > 100) {
Log::warning('Slow query detected', [
'sql' => $query->toRawSql(),
'time_ms' => $query->time,
]);
}
});
پیداوار میں محتاط رہیں۔ بائنڈنگز میں حساس ڈیٹا ہو سکتا ہے، اور تفصیلی لاگنگ کی بڑی مقدار میں کارکردگی کے اپنے مسائل ہو سکتے ہیں۔
چنکنگ کا استعمال کرتے ہوئے بڑی میزوں پر کارروائی کرنا
بیچ آپریشنز کے لیے پوری بڑی میزیں میموری میں لانے سے گریز کریں۔
User::where('is_active', true)
->chunkById(1000, function ($users) {
foreach (\(users as \)user) {
RefreshUserSearchIndex::dispatch($user->id);
}
});
chunkById اگر آپریشن کے دوران قطاریں بدل سکتی ہیں، تو یہ آفسیٹ پر مبنی چنکنگ سے زیادہ محفوظ ہے کیونکہ یہ عددی آفسیٹ کے بجائے آخری دکھائی دینے والی ID کو ٹریک کرتا ہے۔ بڑی برآمدات کے لیے، سٹریم یا بیچ ریکارڈ۔
آف سیٹ صفحہ بندی سست ہے کیونکہ صارف گہرائی میں اسکرول کرتا ہے کیونکہ ڈیٹا بیس کو تمام قطاروں کو چھوڑنا پڑتا ہے جو وہ واپس نہیں آتی ہیں۔ فیڈز، آڈٹ لاگز، پیغامات، اور ٹائم لائنز کے لیے، عام طور پر کرسر صفحہ بندی زیادہ مناسب ہوتی ہے۔
$events = AuditEvent::query()
->where('account_id', $accountId)
->orderByDesc('id')
->cursorPaginate(50);
return AuditEventResource::collection($events);
یہ ایک مستحکم، اشاریہ ترتیب والے کالم کا استعمال کرتا ہے اور لامحدود اسکرول فیڈز کے لیے عام طور پر درکار بے ترتیب صفحہ نمبروں کے بجائے اگلے/پچھلے کرسر کا استعمال کرتا ہے۔
اسپلٹ ریڈز کو پڑھنے والی نقلوں میں
جیسے جیسے پڑھا ہوا ٹریفک بڑھتا ہے، نقل بنیادی پر بوجھ کو کم کر سکتی ہے۔
'mysql' => [
'driver' => 'mysql',
'read' => [
'host' => [
env('DB_READ_HOST', '127.0.0.1'),
],
],
'write' => [
'host' => [
env('DB_WRITE_HOST', '127.0.0.1'),
],
],
'sticky' => true,
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
],
کہ sticky آپشن اسی درخواست کے اندر لکھنے کے بعد لکھنے کے کنکشن پر پڑھنے کو برقرار رکھ کر پڑھنے کے بعد لکھنے کے حیرت سے بچنے میں مدد کرتا ہے۔
نقلوں میں نقل میں تاخیر ہوتی ہے، اور یہ تاخیر اہم ہے۔ جب تک کہ آپ کا کاروباری بہاؤ صحیح معنوں میں پرانے ڈیٹا کو دیکھنے کو برداشت نہ کر سکے، ادائیگی کی تصدیقات، پاس ورڈ کی تبدیلیوں، اجازت کی جانچ پڑتال، یا کچھ سیکنڈز کے لیے پرانی ہو جانے والی نقلوں کے لیے مستقل مزاجی سے حساس کسی بھی چیز کو روٹ نہ کریں۔
ریڈیس کے ساتھ پیمانہ کیسے کریں۔
Redis اکثر Laravel پروڈکشن اسٹیک میں بہت سے کام انجام دیتا ہے، بشمول کیشنگ، سیشنز، ریٹ محدود کرنا، قطاریں، تالے، اور Horizon میٹرکس۔ یہ تیز ہے، لیکن پھر بھی کچھ سوچنے کی ضرورت ہے: معقول کلیدی ڈیزائن، میعاد ختم ہونے کی پالیسی، میموری کی نگرانی، اور باطل ہونے کے لیے حقیقی منصوبہ بندی۔
کیشنگ
کیش مہنگی ریڈز جن کی اکثر درخواست کی جاتی ہے اور وہ قدرے باسی ہو سکتے ہیں۔
use Illuminate\Support\Facades\Cache;
$stats = Cache::remember(
"accounts:{$account->id}:dashboard-stats",
now()->addMinutes(5),
fn () => DashboardStats::forAccount($account)->calculate()
);
شارٹ ٹائم ٹو لائیو (TTL) قدریں حیرت انگیز طور پر طویل عرصے تک چلتی ہیں۔ 5 منٹ کا کیش زیادہ تر ڈیش بورڈز پر ڈیٹا کو تازہ رکھتے ہوئے ہزاروں ڈپلیکیٹ سوالات کو صاف کر سکتا ہے۔
اگر معلوم واقعہ کے بعد ڈیٹا میں تبدیلی آتی ہے تو اسے واضح طور پر باطل کر دیں۔
Order::created(function (Order $order) {
Cache::forget("accounts:{$order->account_id}:dashboard-stats");
});
کیشنگ اس وقت بہترین کام کرتی ہے جب کیز قابل قیاس ہوں اور غلطیاں اندازے کے بجائے ڈومین ایونٹس سے منسلک ہوں۔
سیشن
افقی طور پر اسکیل کردہ ایپ سرورز کے لیے، فائل پر مبنی سیشنز ایک نقصان ہیں۔ اگلی درخواست کسی دوسرے سرور تک پہنچ سکتی ہے جس نے کبھی سیشن نہیں دیکھا۔ ریڈیس یا ڈیٹا بیس میں سیشنز کو اسٹور کریں تاکہ کوئی بھی سرور کسی بھی درخواست کو سنبھال سکے۔
SESSION_DRIVER=redis
CACHE_STORE=redis
QUEUE_CONNECTION=redis
رفتار کی حد
شرح کو محدود کرنا آپ کو بدنیتی پر مبنی کلائنٹس، بھاگے ہوئے لوپز، اور اختتامی پوائنٹس کو نقصان پہنچانے سے بچاتا ہے۔
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(120)->by(
optional(\(request->user())->id ?: \)request->ip()
);
});
مہنگے اختتامی مقامات کو سخت حدود کی ضرورت ہوتی ہے۔
RateLimiter::for('exports', function (Request $request) {
return Limit::perHour(10)->by($request->user()->id);
});
کاروباری لاگت کو نمبروں کو چلانے دیں۔ لاگ ان، تلاش، برآمد، اور ویب ہک اینڈ پوائنٹس کو شاذ و نادر ہی ایک جیسی پابندیوں کی ضرورت ہوتی ہے۔
دم
Redis ایک عام قطار میں کھڑا بیک اینڈ ہے کیونکہ یہ تیز ہے اور Horizon اسے اچھی طرح سپورٹ کرتا ہے۔
QUEUE_CONNECTION=redis
درخواست سے نامزد قطار میں بھیجنے کا کام۔
GenerateInvoicePdf::dispatch($invoice->id)
->onQueue('documents');
پروفائلز کے لحاظ سے اپنے کام کو تقسیم کریں: default, emails, webhooks, documentsاور importsاس کی وجہ یہ ہے کہ ہر کام کے بوجھ کو کارکنوں کی مختلف تعداد کی ضرورت پڑسکتی ہے اور قواعد کی دوبارہ کوشش کریں۔ اپنا نام بامعنی رکھیں۔ ایک واقعے کے دوران، "دستاویز کی قطار 20 منٹ لیٹ ہے” آپ کو "ڈیفالٹ سست ہے” سے کہیں زیادہ بتاتی ہے۔
قطار پر مبنی فن تعمیر کا استعمال کیسے کریں۔
قطاریں Laravel کے بہترین اسکیلنگ ٹولز میں سے ایک ہیں۔ یہ آپ کی ایپ کو کاموں کو تیزی سے قبول کرنے اور کنٹرول شدہ ہم آہنگی کے ساتھ غیر مطابقت پذیر طور پر کارروائی کرنے دیتا ہے۔ یہ نظام کو مزید لچکدار بھی بناتا ہے۔ اگر فریق ثالث کا API نیچے جاتا ہے، تو آپریشن PHP-FPM درخواست کارکن کو باندھنے کے بجائے خود دوبارہ کوشش کرے گا۔
لاریول قطار
اچھے آپریشنز چھوٹے، کمزور اور دوبارہ کوشش کرنے کے لیے محفوظ ہیں۔
use App\Mail\OrderReceiptMail;
use App\Models\Order;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Mail;
class SendOrderReceipt implements ShouldQueue
{
use Queueable;
public int $tries = 3;
public int $backoff = 60;
public function __construct(public int $orderId)
{
}
public function handle(): void
{
\(order = Order::with('user')->findOrFail(\)this->orderId);
Mail::to(\(order->user)->send(new OrderReceiptMail(\)order));
}
}
پورے Eloquent ماڈل کے بجائے ٹاسک کے لیے ID پاس کریں۔ ٹاسک چلنے سے پہلے ماڈل تبدیل ہو سکتا ہے، اور پورے ماڈل کو سیریل کرنے کے نتیجے میں ایک بڑا پے لوڈ ہو گا۔ بیرونی APIs کے لیے، ٹائم آؤٹ شامل کریں اور ڈپلیکیٹ کام سے بچیں۔
use App\Models\Order;
use App\Services\CrmClient;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
class SyncOrderToCrm implements ShouldQueue
{
use Queueable;
public int $tries = 3;
public int $backoff = 60;
public function __construct(public int $orderId)
{
}
public function handle(CrmClient $crm): void
{
\(order = Order::findOrFail(\)this->orderId);
if ($order->crm_synced_at) {
return;
}
\(crm->upsertOrder(\)order->external_reference, [
'total' => $order->total,
'status' => $order->status,
]);
$order->forceFill(['crm_synced_at' => now()])->save();
}
}
کہ crm_synced_at تصدیق کلید ہے۔ آپریشنز کو حقیقی زندگی میں ایک سے زیادہ بار انجام دیا جاتا ہے، اور آئیڈیمپوٹینسی ایسی ہے کہ دوبارہ کوششیں ڈبل بلنگ یا ڈبل سنکرونائزیشن کو روکتی ہیں۔
افق
Horizon ریڈیس قطاروں پر مرئیت اور کنٹرول فراہم کرتا ہے۔ ایک عام سیٹ اپ مختلف کام کے بوجھ کے لیے مختلف سپروائزر چلاتا ہے۔
'production' => [
'supervisor-default' => [
'connection' => 'redis',
'queue' => ['default', 'emails'],
'balance' => 'auto',
'maxProcesses' => 20,
'tries' => 3,
],
'supervisor-documents' => [
'connection' => 'redis',
'queue' => ['documents'],
'balance' => 'simple',
'maxProcesses' => 5,
'tries' => 2,
'timeout' => 300,
],
],
علیحدگی ضروری ہے۔ طویل عرصے سے چلنے والے دستاویزی کاموں سے آپ کو فوری پاس ورڈ دوبارہ ترتیب دینے والی ای میلز ختم نہیں ہونے چاہئیں۔
ناکام آپریشنز اور دوبارہ کوششیں۔
دوبارہ کوشش صرف اس صورت میں مدد کرتی ہے جب ناکامی عارضی ہو۔ مستقل طور پر روکے گئے آپریشن کی دوبارہ کوشش کرنے سے صلاحیت ختم ہوجاتی ہے۔ کاروبار کی آخری تاریخ کے ساتھ کاموں کے لیے، استعمال کریں: retryUntil:
use DateTime;
use Throwable;
public function retryUntil(): DateTime
{
return now()->addMinutes(30);
}
public function failed(Throwable $exception): void
{
ImportBatch::whereKey($this->batchId)->update([
'status' => 'failed',
'failed_reason' => $exception->getMessage(),
]);
}
استعمال کریں failed اس مسئلے کو نشان زد کریں جہاں لوگ اسے دیکھ سکتے ہیں۔ آپ جو کچھ بھی کریں، تیسرے فریق کی خدمات تک پہنچنے والے آپریشنز کے لیے لامحدود دوبارہ کوششیں مت کریں۔
قطار کی نگرانی
قطار کی گہرائی، انتظار کا وقت، ناکامی کی شرح، اور پروسیسنگ کا وقت ایک ساتھ ٹریک کیا جاتا ہے۔ اکیلے گہرائی آپ کو گمراہ کر سکتی ہے۔ جیسا کہ آپ گہرائی حاصل کرنا شروع کرتے ہیں، منظم طریقے سے دیکھیں. کیا آپ کے کارکنان آنے والے کام کے ساتھ رفتار برقرار رکھے ہوئے ہیں؟ اگر قطار بڑھتی رہتی ہے تو چیک کریں کہ انفرادی کاموں میں کتنا وقت لگتا ہے۔ اگر سست حصہ ڈیٹا بیس ہے تو استفسار میں ترمیم کریں یا ورکر کنکرنسی کو ڈائل بیک کریں۔ اگر یہ ایک بیرونی API ہے تو بیک آف یا سرکٹ بریکر شامل کریں۔ اگر آپ کا کام سی پی یو سے منسلک ہے، تو کارکنوں کی پیمائش کریں یا کام کو چھوٹے ٹکڑوں میں توڑ دیں۔
لیکن اپنی "پیمانہ کارکن” جبلتوں سے ہوشیار رہیں۔ پہلے ڈیٹا بیس کی جانچ کیے بغیر کارکنوں کو شامل کرنا واقعات کو مزید خراب کر سکتا ہے۔ زیادہ کارکنان کا مطلب ہے زیادہ ہم آہنگی کے سوالات، زیادہ لاکنگ، اور پہلے سے جدوجہد کرنے والے بنیادی ڈیٹا بیس پر زیادہ دباؤ۔
API کی کارکردگی کو کیسے بہتر بنایا جائے۔
APIs خاص دلچسپی کے حامل ہیں کیونکہ کلائنٹ انہیں بار بار کال کرتے ہیں اور ان کے پے لوڈز کئی مہینوں میں خاموشی سے بڑھتے رہتے ہیں۔
API وسائل
وسائل جان بوجھ کر ایک ذمہ دار شکل کو برقرار رکھتے ہیں۔
class OrderResource extends JsonResource
{
public function toArray($request): array
{
return [
'id' => $this->id,
'status' => $this->status,
'total' => $this->total,
'placed_at' => $this->created_at->toIso8601String(),
'customer' => new CustomerSummaryResource($this->whenLoaded('customer')),
];
}
}
whenLoaded یہاں حقیقی کام ہو رہا ہے۔ اگر رشتہ فوری طور پر لوڈ نہیں کیا جاتا ہے، تو وسائل خاموشی سے سست سوالات کو متحرک کرنا بند کر دیتے ہیں۔
$orders = Order::query()
->with('customer:id,name')
->where('account_id', $accountId)
->latest()
->paginate(50);
return OrderResource::collection($orders);
ایک غیر محدود مجموعہ کو واپس کرنا API کارکردگی کے مسائل پیدا کرنے کا ایک آسان طریقہ ہے جو اس وقت تک محسوس نہیں کیا جائے گا جب تک کہ کلائنٹ کے پاس بہت زیادہ ڈیٹا نہ ہو۔
$perPage = min((int) request('per_page', 50), 100);
\(orders = Order::where('account_id', \)accountId)
->latest()
->paginate($perPage);
صفحہ کا سائز محدود کریں۔ اگر کلائنٹ کو واقعی برآمد کے لیے تمام ریکارڈز کی ضرورت ہے، تو اسے بڑے ہم وقت ساز جواب کی بجائے ایک غیر مطابقت پذیر آپریشن بنائیں۔
رسپانس آپٹیمائزیشن
ان فیلڈز کو واپس کرنا بند کریں جنہیں کوئی نہیں پڑھتا۔ ریڈ ہیوی اینڈ پوائنٹس پر، صرف ان کالموں کا انتخاب کرنا جن کی آپ کو ضرورت ہوتی ہے، ڈیٹا بیس I/O اور سیریلائزیشن کے اخراجات دونوں کو کم کر دیتا ہے۔
$products = Product::query()
->select(['id', 'name', 'slug', 'price', 'thumbnail_url'])
->where('is_visible', true)
->orderBy('name')
->paginate(40);
یہ آپ کے ویب سرور یا لوڈ بیلنسر پر کمپریشن آن کرنے کے قابل بھی ہو سکتا ہے۔ JSON بہت اچھی طرح سے کمپریس کرتا ہے، اور یہ اکثر حقیقی بینڈوتھ معاوضے کے ساتھ ترتیب میں ایک چھوٹی سی تبدیلی ہوتی ہے۔
رفتار کی حد
شناخت اور اختتامی قیمت کے لیے API کی شرح کی حدیں ڈیزائن کریں۔
Route::middleware(['auth:sanctum', 'throttle:api'])
->group(function () {
Route::get('/orders', [OrderController::class, 'index']);
Route::post('/exports/orders', [OrderExportController::class, 'store'])
->middleware('throttle:exports');
});
یہ معمول کی تلاشوں اور مہنگی برآمدات کو الگ الگ پالیسیوں کے تحت رکھتا ہے، لہذا ایک بھاری صارف ہر کسی پر دباؤ نہیں ڈال سکتا۔
API ردعمل کیشنگ
کیشے کے جوابات جو کمپیوٹیشنل طور پر مہنگے اور قدرے پرانے ہو سکتے ہیں:
public function index(Request $request)
{
\(accountId = \)request->user()->account_id;
\(page = \)request->integer('page', 1);
\(cacheKey = "api:accounts:{\)accountId}:orders:v1:page:{$page}";
return Cache::remember(\(cacheKey, now()->addSeconds(60), function () use (\)accountId) {
return OrderResource::collection(
Order::with('customer:id,name')
->where('account_id', $accountId)
->latest()
->paginate(50)
)->response()->getData(true);
});
}
توجہ فرمائیں v1 چابی پر۔ اس ورژن نمبر کو ٹکرانے سے، جب آپ ظاہری شکل بدلتے ہیں تو آپ پورے جوابی فارمیٹ کو ایک ساتھ باطل کر سکتے ہیں۔ ایسی اشیاء کے لیے جو واقعی عالمی نہیں ہیں، ہمیشہ کرایہ دار یا صارف کے لیے کلید کا دائرہ کار رکھیں۔
پیداوار میں لاریول کی نگرانی کیسے کریں۔
وہ ٹیمیں جو صارفین سے پہلے مسائل کی نشاندہی کرتی ہیں وہی ہیں جو ہر جگہ سے سگنل جمع کرتی ہیں: Laravel، قطاریں، ڈیٹا بیس، Redis، انفراسٹرکچر، اور بیرونی خدمات۔
Laravel کچھ اچھے ابتدائی نکات فراہم کرتا ہے۔ Horizon قطار کے تھرو پٹ، ناکام جابز، لیٹنسی، اور ورکر بیلنسنگ دکھاتا ہے۔ ٹیلی سکوپ درخواست کی تفصیلات، سوالات، استثنیٰ، کام، میل، اور کیش ایونٹس دکھاتا ہے۔ لاگز سست کارروائیوں، غیر متوقع دوبارہ کوششوں، اور بیرونی خرابیوں کو پکڑتے ہیں۔ میٹرکس لیٹنسی، ایرر ریٹ، قطار کی گہرائی، ٹاسک رن ٹائم، ڈیٹا بیس سی پی یو، لاک ویٹ، کیش ہٹ ریٹ، اور ریڈیس میموری کو ٹریک کرتا ہے۔ آپ کا انتباہ ان سب کو اس سے جوڑتا ہے کہ آپ کے گاہک اصل میں کیا محسوس کر سکتے ہیں۔
وہ آخری حصہ ہے جہاں ٹیمیں اکثر غلطیاں کرتی ہیں۔ بہترین انتباہ علامات کے بارے میں ہیں، نہ کہ آپ کے کمپیوٹر کے مصروف ہونے کے بارے میں۔ p95 API لیٹنسی 10 منٹ کے لیے 800ms سے زیادہ، ادائیگی کی غلطی کی شرح 1% سے زیادہ، ای میل قطار 5 منٹ سے زیادہ انتظار، ڈیٹا بیس CPU 85% سے زیادہ استفسار کی وجہ سے، Redis میموری 80% سے زیادہ، یا ادائیگی کا ویب ہک حد سے تجاوز کرنے میں ناکام۔
کچھ مفید ذہنی ماڈلز میں شامل ہیں: لاگز آپ کو بتاتے ہیں کہ کیا ہوا، میٹرکس آپ کو بتاتے ہیں کہ آیا نظام صحت مند ہے، اور نشانات آپ کو بتاتے ہیں کہ وقت کہاں گیا۔ درحقیقت، مہنگے کاروباری کاموں کو تھوڑا سا آلات کے ساتھ سمیٹنے سے جلد ادائیگی ہو سکتی ہے۔
use Illuminate\Support\Facades\Log;
$startedAt = microtime(true);
\(report = \)builder->forAccount($account)->build();
Log::info('Billing report generated', [
'account_id' => $account->id,
'duration_ms' => (int) ((microtime(true) - $startedAt) * 1000),
'invoice_count' => $report->invoiceCount(),
]);
اگر مسئلہ صبح 2 بجے پیش آتا ہے، تو اس طرح کی لاگ لائن آپ کو یہ جاننے میں مدد کرے گی کہ کون سا اکاؤنٹ، درآمد، یا رپورٹ مسئلہ کا باعث ہے۔
اندرونی بنانے کے قابل ایک اور چیز تاخیر کے ساتھ ساتھ تھرو پٹ کی نگرانی کرنا ہے۔ ایک قطار فی منٹ ہزاروں ملازمتوں کو سنبھال سکتی ہے، لیکن یہ اب بھی بے ترتیب ہو سکتا ہے اگر اہم ملازمتیں شروع ہونے سے پہلے بہت زیادہ انتظار کریں۔ صارفین انتظار محسوس کرتے ہیں، تھرو پٹ نہیں۔
ہائی ٹریفک لاریول فن تعمیر کی مثال
ہائی ٹریفک لاریول سیٹ اپ عام طور پر چار چیزوں کو الگ کرتے ہیں: اسٹیٹ لیس ویب درخواستیں، مشترکہ کیشے اور سیشن اسٹوریج، غیر مطابقت پذیر کارکنان، اور ڈیٹا بیس کے کردار۔
آپ لوڈ بیلنسر استعمال کرتے ہیں جو ٹریفک کو اسٹیٹ لیس لاریول ایپ سرورز پر تقسیم کرتا ہے۔ وہ سرورز کیشے، سیشنز، ریٹ محدود کرنے، قطاروں اور ہورائزن ڈیٹا کے لیے Redis استعمال کرتے ہیں۔ قطار میں کھڑے کارکن الگ سے سست یا ناقابل اعتبار کاموں پر کارروائی کرتے ہیں۔ MySQL پرائمری نقلیں تمام تحریریں اور مستقل مزاجی سے حساس پڑھنے کو انجام دیتی ہیں، جب کہ پڑھنے کی نقلیں پڑھنے والے اختتامی نقطوں کو جذب کرتی ہیں، جو کچھ نقل کی وقفے کو برداشت کر سکتی ہیں۔
بہاؤ مندرجہ ذیل ہے:
Users
-> Load balancer
-> Stateless Laravel app servers
-> Redis for cache, sessions, rate limits, queues, and Horizon data
-> Primary database for writes and consistency-sensitive reads
-> Read replica for safe read-heavy endpoints
Redis queue
-> Queue workers
-> Database, external APIs, mail providers, object storage, and other services
یہ واحد درست شکل نہیں ہے۔ PostgreSQL MySQL کی جگہ لے سکتا ہے، Amazon SQS Redis کی قطاروں کی جگہ لے سکتا ہے، CDNs جامد اثاثوں اور عوامی ردعمل کو کیش کر سکتے ہیں، اور صارف کے اپ لوڈز کو آرکائیو کرنے کے لیے آبجیکٹ اسٹوریج کی ضرورت ہے۔ اہم اصول یہ ہے کہ ہر پرت کا ایک واضح کام ہوتا ہے اور اسے خود بڑھایا یا ڈھال لیا جا سکتا ہے۔
اسٹیٹ لیس ایپ سرور کا منفی پہلو یہ ہے کہ درخواست ختم ہونے کے بعد صارف کو جو بھی چیز درکار ہوتی ہے وہ مشترکہ اسٹوریج میں رہتی ہے۔ اپ لوڈز، بنائی گئی فائلیں، اور سیشن کی حالت کسی ایک سرور کی مقامی ڈسک پر نہیں ہونی چاہیے۔ بصورت دیگر، یہ صارف کی نظر سے غائب ہو سکتا ہے جب لوڈ بیلنسر اگلی درخواست کہیں اور بھیجتا ہے۔
سبق مشکل طریقے سے سیکھا۔
1. ابتدائی اصلاح
یہ عام طور پر خود کو نفیس انفراسٹرکچر کے طور پر ظاہر کرتا ہے اس سے پہلے کہ ایپ کے اپنے طور پر کوئی حقیقی مرئیت ہو۔
عملی راستہ بہتر کام کرتا ہے۔ اس کا مطلب ہے کہ رکاوٹوں کی پیمائش کریں، ان کی درجہ بندی کریں، سب سے بڑی کو درست کریں، اور دہرائیں۔ زیادہ تر Laravel ایپس کے لیے، اسکیلنگ کا پہلا دور زیادہ تر اشاریہ سازی، N+1 ترمیم، قطار کی تقسیم، اور پے لوڈ تراشنا ہے۔
2. ضرورت سے زیادہ کیشنگ
کیشنگ سسٹم کو ایک ہی وقت میں تیز اور مشکل بنا سکتی ہے۔ ایک ٹیم نے اکاؤنٹ سیٹ اپ کے جوابات کو 30 منٹ تک محفوظ کیا اور پھر بعد میں انہی جوابات میں کردار کی تبدیلیوں کو سمیٹ دیا۔ نتیجے کے طور پر، جن صارفین نے ابھی رسائی کھو دی تھی وہ اس خصوصیت کو دیکھنا جاری رکھ سکتے ہیں جب تک کہ کیشے کی میعاد ختم نہ ہو جائے۔
درستی یہ تھی کہ اکاؤنٹ کے مستحکم میٹا ڈیٹا کو اجازت کی حساس حالت سے الگ کیا جائے۔ سبق یہ ہے کہ تصدیقی ڈیٹا کو کیش کرنے سے گریز کیا جائے جب تک کہ آپ غلط ہونے کے بارے میں احتیاط سے نہ سوچیں۔
3. گمشدہ اشاریہ جات
یہ اس وقت تک چھپا ہوا ہے جب تک کہ میز سائز کی حد سے تجاوز نہ کر جائے۔ ایک سوال جو ترقی میں 20,000 قطاروں کو اسکین کرتا ہے پیداوار میں 20 ملین قطاروں کو اسکین کرسکتا ہے۔ اپنے فنکشنل کاموں میں انڈیکس کے جائزے تیار کریں اور انڈیکس کی بڑی منتقلی کی منصوبہ بندی کریں تاکہ بدترین ممکنہ وقت پر گرم میزوں کو بند کرنے سے بچا جا سکے۔
4. قطار اوورلوڈ
قطار ملازمتوں کو ہٹانے کے بجائے منتقل کرتی ہے۔ ایک کلاسک ناکامی تب ہوتی ہے جب ایک شور کام کا بوجھ باقی سب چیزوں کو روکتا ہے۔ ایک بڑی CSV درآمد مرکزی قطار کو اوور فلو کر دے گی اور پاس ورڈ دوبارہ ترتیب دینے والی ای میلز اس کے پیچھے پھنس جائیں گی۔ ایک الگ قطار اس پوری ایکسیڈنٹ کلاس کے لیے سستی بیمہ ہے۔
5. بڑے لین دین
لمبے لین دین میں تالے زیادہ ہوتے ہیں اور ناکامی کی وجہ سے زیادہ مہنگے ہوتے ہیں۔ لین دین کے اندر کام کرنا خاص طور پر خطرناک ہوتا ہے کیونکہ کارکنان کو لین دین سے پہلے کام مل سکتا ہے۔
DB::transaction(function () use ($request) {
$order = Order::create([...]);
\(order->items()->createMany(\)request->items);
GenerateInvoicePdf::dispatch($order->id);
SyncOrderToCrm::dispatch($order->id);
});
ان تمام کارروائیوں کے لیے پوسٹ کمٹ ڈسپیچ کا استعمال کریں جو پرعزم ڈیٹا پر منحصر ہوں۔
GenerateInvoicePdf::dispatch($order->id)->afterCommit();
SyncOrderToCrm::dispatch($order->id)->afterCommit();
لین دین کے دائرہ کار کو ڈیٹا تک رکھیں جسے اصل میں جوہری طور پر تبدیل کرنے کی ضرورت ہے۔
6. علامات کا علاج اسباب کے طور پر کریں۔
یہ مہنگا ہے۔ اگر آپ کا اینڈ پوائنٹ 300 استفسارات چلاتا ہے اور اس میں زیادہ تاخیر ہے، تو ایک ایپ سرور شامل کرنے سے آپ کے ڈیٹا بیس پر بوجھ بڑھ جائے گا۔ اگر آپ کا کام سست ہے کیونکہ یہ ایک بیرونی API کے ذریعہ محدود ہے، تو مزید کارکنوں کو شامل کرنے سے ناکامیوں میں کئی گنا اضافہ ہو جائے گا۔
اچھا سکیلنگ کا کام ایک ہی سوالات کو بار بار پوچھتا ہے۔ کون سے وسائل سیر ہوتے ہیں؟ کون سا اختتامی نقطہ، کام، کرایہ دار، یا استفسار مسئلہ کا سبب بن رہا ہے؟ کیا درخواست پر یہ ضروری ہے؟ کیا اسے کم، ملتوی، کیش یا الگ کیا جا سکتا ہے؟ میں کیسے جان سکتا ہوں کہ آیا میری تبدیلیوں میں مدد ملی؟
پری لانچ ایکسپینشن چیک لسٹ
کسی بڑے لانچ، ٹریفک مہم، یا کارپوریٹ لانچ سے پہلے ایسا کرنے کی کوشش کریں۔
درخواست اور رن ٹائم: تعیناتی کے دوران کیش کنفیگریشن، راستے اور مناظر۔ سیٹ APP_DEBUG=false. OPcache کو آن کریں۔ ویب درخواستوں کو مختصر رکھیں اور سست کاموں کو قطار میں منتقل کریں۔ اپ لوڈز کو ایپ سرور ڈسک کے بجائے آبجیکٹ اسٹوریج میں اسٹور کریں۔ سرورز کو بے وطن رکھتا ہے۔ تمام بیرونی HTTP کالوں کے لیے ٹائم آؤٹ سیٹ کریں۔
ڈیٹا بیس: پہلے اپنے سست استفسار کے لاگز کا جائزہ لیں۔ بڑے فلٹرز، جوائنز اور ترتیب کے لیے اشاریہ جات شامل کریں۔ کنٹرولرز، وسائل، پالیسیوں اور آراء میں N+1 کے سوالات تلاش کریں۔ فہرست کے تمام اختتامی مقامات کو صفحہ بندی کرتا ہے۔ استعمال کریں chunkById یا بیچ آپریشنز کے لیے کرسر۔ لین دین کے اندر طویل لین دین اور بیرونی کالوں سے پرہیز کریں۔ یقینی بنائیں کہ آپ کا بیک اپ اور بحالی کا عمل کام کر رہا ہے۔ اگر آپ نقلیں استعمال کرتے ہیں تو پڑھے جانے والے باسی رویے کی جانچ کریں۔
ریڈیس اور کیشے: کیشز، سیشنز، ریٹ محدود کرنے، اور مناسب قطاروں کے لیے Redis استعمال کریں۔ TTL مقرر کریں جب تک کہ آپ کے پاس نہ کرنے کی واضح وجہ ہو۔ اگر متعلقہ ہو تو کلید میں کرایہ دار، صارف، مقام، اور ورژن شامل کریں۔ ہماری یادداشت اور بے دخلی کی پالیسیوں کا جائزہ لیں۔ احتیاط سے غلط ہونے کے بغیر اجازت کے حساس جوابات کو کیش کرنے سے گریز کریں۔ مہنگی دوبارہ گنتی کی وجہ سے کیشے کے ضبط کو روکتا ہے۔
دم: کام کے بوجھ سے قطاریں الگ کریں۔ ہورائزن سپروائزرز کو فی قطار کی بنیاد پر ترتیب دیں۔ ہم جان بوجھ کر ٹائم آؤٹ، دوبارہ کوششیں، اور بیک آف سیٹ کرتے ہیں۔ جب ممکن ہو آپریشنوں کو کمزور بنائیں۔ استعمال کریں afterCommit ان کارروائیوں کے لیے جو پرعزم ڈیٹا پر منحصر ہیں۔ تاخیر، رن ٹائم، ناکامیوں اور دوبارہ کوششوں کی نگرانی کریں۔ ناکام کاموں کو نظر انداز کرنے کے بجائے ان کا جائزہ لیں۔
apis: جواب کی شکل کو کنٹرول کرنے کے لیے وسائل کا استعمال کریں۔ ٹوپی per_page. بڑی فیڈز اور لاگز کے لیے کرسر صفحہ بندی کا استعمال کریں۔ کیز اور مختصر ٹی ٹی ایل کے محفوظ ورژنز کا استعمال کرتے ہوئے مہنگے ریڈز کیش کریں۔ اختتامی قیمت کے لحاظ سے شرح کو محدود کرنے کا اطلاق کریں۔ خام فصاحت ماڈل واپس نہ کریں. کناروں پر ردعمل کو کمپریس کرتا ہے۔
مشاہدہ: اہم اختتامی پوائنٹس پر p50، p95، اور p99 لیٹنسی کو ٹریک کریں۔ راستے اور ٹاسک کلاس کے ذریعہ غلطی کی شرحوں کو ٹریک کریں۔ یہ آپ کو قطار کے انتظار کے اوقات کے ساتھ ساتھ سائز کے بارے میں خبردار کرتا ہے۔ ڈیٹا بیس CPU، کنکشن، سست سوالات، اور لاک انتظار کا مشاہدہ کریں۔ Redis میموری، لیٹنسی اور بے دخلی کو دریافت کریں۔ ادوار اور شناخت کنندگان کا استعمال کرتے ہوئے اہم کاروباری کاموں کو ریکارڈ کریں۔ خاموش انتباہات بغیر انتباہات سے بدتر ہو سکتی ہیں، لہذا لانچ کی رات سے پہلے اپنے انتباہات کی جانچ کریں۔
نتیجہ
Laravel اعلی ٹریفک پروڈکشن سسٹمز پر مؤثر طریقے سے چلتا ہے جب ڈیٹا، ہم آہنگی، اور بیرونی انحصار کو ذہن میں رکھتے ہوئے ڈیزائن کیا جاتا ہے۔ بہتر بنانے سے پہلے پیمائش کرنا یقینی بنائیں، کیونکہ اندازہ لگانے سے وقت ضائع ہوتا ہے اور غلط تہوں کو پیچیدہ کرنے کا رجحان ہوتا ہے۔
پہلے ڈیٹا بیس میں ترمیم کریں۔ اشاریہ جات، استفسار کی شکلیں، صفحہ بندی، اور بے چین لوڈنگ عام طور پر ابتدائی طور پر سب سے بڑی ادائیگی فراہم کرتی ہے۔ درخواستوں کو تیز رکھنے کے لیے قطاروں کا فائدہ اٹھائیں اور پس منظر کے کنٹرول والے کارکنوں کے لیے سست کاموں کو آگے بڑھائیں۔ ہم جان بوجھ کر واضح کلیدوں، عام TTL، اور باطل کرنے کے منصوبے کے ساتھ کیش کرتے ہیں۔ تاخیر، غلطیوں، قطار میں تاخیر، ڈیٹا بیس کی صحت، ریڈیس میموری، اور بیرونی انحصار پر نظر رکھیں۔
سکیلنگ کے بہترین آپریشنز عملی اور دوبارہ کیے جا سکتے ہیں۔ آپ کے پاس موجود سسٹمز کا مطالعہ کریں، فضلہ کو ختم کریں، سست حصوں کو الگ کریں، اور اعتماد کے ساتھ اپنی اگلی تبدیلیاں کرنے کے لیے کافی مرئیت حاصل کریں۔ اگر بار بار کیا جائے تو بڑی دوبارہ تحریریں شاذ و نادر ہی ضروری ہیں۔