روڈ رنر: پی ایچ پی مرنے کے لیے نہیں بنایا گیا ہے، یا گولانگ کو بچانے کے لیے نہیں بنایا گیا ہے۔

روڈ رنر: پی ایچ پی مرنے کے لیے نہیں بنایا گیا ہے، یا گولانگ کو بچانے کے لیے نہیں بنایا گیا ہے۔

ہیلو، حبر! ہم بدو میں سرگرم ہیں۔ پی ایچ پی کی کارکردگی پر کام کرناچونکہ اس زبان میں ہمارے پاس کافی بڑا نظام ہے اور کارکردگی کا مسئلہ پیسہ بچانے کا معاملہ ہے۔ دس سال سے زیادہ پہلے، ہم نے اس کے لیے PHP-FPM بنایا، جو پہلے پی ایچ پی کے لیے پیچ کا ایک سیٹ تھا، اور بعد میں سرکاری تقسیم کا حصہ بن گیا۔

حالیہ برسوں میں، پی ایچ پی نے بہت ترقی کی ہے: کوڑا اٹھانے والے میں بہتری آئی ہے، استحکام کی سطح میں اضافہ ہوا ہے - آج آپ پی ایچ پی میں بغیر کسی دشواری کے ڈیمن اور دیرپا اسکرپٹ لکھ سکتے ہیں۔ اس نے Spiral Scout کو مزید آگے جانے کی اجازت دی: RoadRunner، PHP-FPM کے برعکس، درخواستوں کے درمیان میموری کو صاف نہیں کرتا، جس سے کارکردگی کے اضافی فوائد حاصل ہوتے ہیں (حالانکہ یہ نقطہ نظر ترقیاتی عمل کو پیچیدہ بناتا ہے)۔ ہم فی الحال اس ٹول کے ساتھ تجربہ کر رہے ہیں، لیکن ہمارے پاس ابھی تک اشتراک کرنے کے لیے کوئی نتیجہ نہیں ہے۔ ان کے انتظار میں مزید مزہ آنے کے لیے، ہم Spiral Scout سے RoadRunner کے اعلان کا ترجمہ شائع کر رہے ہیں۔

مضمون کا نقطہ نظر ہمارے قریب ہے: اپنے مسائل کو حل کرتے وقت، ہم اکثر پی ایچ پی اور گو کا مجموعہ استعمال کرتے ہیں، دونوں زبانوں کے فوائد حاصل کرتے ہیں اور ایک دوسرے کے حق میں نہیں چھوڑتے ہیں۔

لطف اندوز ہوں!

پچھلے دس سالوں میں، ہم نے فہرست میں سے کمپنیوں کے لیے درخواستیں تیار کی ہیں۔ فارچیون 500اور ایسے کاروبار کے لیے جن کے سامعین 500 سے زیادہ صارفین نہیں ہیں۔ اس سارے عرصے میں، ہمارے انجینئرز نے بنیادی طور پر پی ایچ پی میں بیک اینڈ تیار کیا۔ لیکن دو سال پہلے، کسی چیز نے نہ صرف ہماری پروڈکٹس کی کارکردگی پر بلکہ ان کی توسیع پذیری پر بھی بڑا اثر ڈالا - ہم نے اپنے ٹیکنالوجی اسٹیک میں Golang (Go) کو متعارف کرایا۔

تقریباً فوراً، ہم نے دریافت کیا کہ Go نے ہمیں 40x تک تیز کارکردگی کے ساتھ بڑی ایپلی کیشنز بنانے کی اجازت دی۔ اس کے ساتھ، ہم پی ایچ پی میں لکھے گئے موجودہ پروڈکٹس کو وسعت دینے کے قابل ہو گئے، دونوں زبانوں کے فوائد کو ملا کر ان کو بہتر بنایا۔

ہم آپ کو بتائیں گے کہ کس طرح Go اور PHP کا امتزاج حقیقی ترقی کے مسائل کو حل کرنے میں مدد کرتا ہے اور یہ ہمارے لیے کس طرح ایک ٹول میں تبدیل ہوا ہے جو اس سے منسلک کچھ مسائل کو ختم کر سکتا ہے۔ پی ایچ پی کا مرنے والا ماڈل.

آپ کا روزانہ پی ایچ پی کی ترقی کا ماحول

اس سے پہلے کہ ہم اس بارے میں بات کریں کہ آپ پی ایچ پی کے ختم ہونے والے ماڈل کو بحال کرنے کے لیے گو کو کس طرح استعمال کر سکتے ہیں، آئیے آپ کے معیاری پی ایچ پی کی ترقی کے ماحول پر ایک نظر ڈالیں۔

زیادہ تر معاملات میں، آپ nginx ویب سرور اور PHP-FPM سرور کے امتزاج کا استعمال کرتے ہوئے ایپلیکیشن چلاتے ہیں۔ سب سے پہلے جامد فائلوں کو پیش کرتا ہے اور مخصوص درخواستوں کو PHP-FPM پر بھیجتا ہے، اور PHP-FPM خود پی ایچ پی کوڈ پر عمل درآمد کرتا ہے۔ شاید آپ Apache اور mod_php سے کم مقبول امتزاج استعمال کر رہے ہیں۔ لیکن اگرچہ یہ تھوڑا مختلف طریقے سے کام کرتا ہے، اصول ایک جیسے ہیں۔

آئیے دیکھتے ہیں کہ پی ایچ پی-ایف پی ایم ایپلیکیشن کوڈ کو کیسے چلاتا ہے۔ جب کوئی درخواست آتی ہے، PHP-FPM چائلڈ PHP کے عمل کو شروع کرتا ہے اور درخواست کی تفصیلات کو اس کی حالت کے حصے کے طور پر پاس کرتا ہے (_GET، _POST، _SERVER، وغیرہ)۔

پی ایچ پی اسکرپٹ پر عمل درآمد کے دوران حالت تبدیل نہیں ہو سکتی، اس لیے ان پٹ ڈیٹا کا نیا سیٹ حاصل کرنے کا ایک ہی طریقہ ہے: پراسیس میموری کو صاف کرکے اور اسے دوبارہ شروع کر کے۔

اس عملدرآمد ماڈل کے بہت سے فوائد ہیں۔ آپ کو میموری کی کھپت کے بارے میں زیادہ فکر کرنے کی ضرورت نہیں ہے، تمام عمل مکمل طور پر الگ تھلگ ہیں، اور اگر ان میں سے ایک مر جاتا ہے، تو یہ باقی عمل کو متاثر کیے بغیر خود بخود دوبارہ بن جائے گا۔ لیکن اس نقطہ نظر کے نقصانات بھی ہیں جو ایپلیکیشن کی پیمائش کرنے کی کوشش کرتے وقت ظاہر ہوتے ہیں۔

پی ایچ پی کے باقاعدہ ماحول کے نقصانات اور ناکاریاں

اگر آپ پی ایچ پی میں پیشہ ورانہ ترقی میں مصروف ہیں، تو آپ جانتے ہیں کہ ایک نیا پروجیکٹ کہاں سے شروع کرنا ہے - ایک فریم ورک کا انتخاب کرکے۔ یہ انحصار انجیکشن، ORMs، ترجمے اور ٹیمپلیٹس کے لیے لائبریریوں پر مشتمل ہے۔ اور یقیناً، تمام صارف ان پٹ آسانی سے ایک آبجیکٹ (Symfony/HttpFoundation یا PSR-7) میں ڈالے جا سکتے ہیں۔ فریم ورک ٹھنڈے ہیں!

لیکن ہر چیز کی قیمت ہوتی ہے۔ کسی بھی انٹرپرائز سطح کے فریم ورک میں، صارف کی ایک سادہ درخواست پر کارروائی کرنے یا ڈیٹا بیس تک رسائی حاصل کرنے کے لیے، آپ کو کم از کم درجنوں فائلیں لوڈ کرنی ہوں گی، متعدد کلاسز بنانا ہوں گی اور کئی کنفیگریشنز کو پارس کرنا ہوگا۔ لیکن سب سے بری بات یہ ہے کہ ہر کام کو مکمل کرنے کے بعد آپ کو ہر چیز کو دوبارہ ترتیب دینے اور دوبارہ شروع کرنے کی ضرورت ہوگی: وہ تمام کوڈ جو آپ نے ابھی شروع کیا ہے بیکار ہو جاتا ہے، اس کی مدد سے آپ کسی اور درخواست پر مزید کارروائی نہیں کریں گے۔ کسی بھی پروگرامر کو بتائیں جو کسی دوسری زبان میں لکھتا ہے، اور آپ کو اس کے چہرے پر حیرت نظر آئے گی۔

پی ایچ پی انجینئرز نے ہوشیار سست لوڈنگ تکنیکوں، مائیکرو فریم ورکس، آپٹمائزڈ لائبریریوں، کیشز وغیرہ کا استعمال کرتے ہوئے اس مسئلے کو حل کرنے کے طریقے ڈھونڈتے ہوئے برسوں گزارے ہیں۔ لیکن آخر میں، آپ کو پھر بھی پوری ایپلیکیشن کو دوبارہ ترتیب دینا ہوگا اور دوبارہ شروع کرنا ہوگا۔ (مترجم کا نوٹ: یہ مسئلہ جزوی طور پر کی آمد کے ساتھ حل ہو جائے گا۔ preload پی ایچ پی 7.4 میں)

کیا گو کے ساتھ پی ایچ پی ایک سے زیادہ درخواستوں کو زندہ رکھ سکتا ہے؟

پی ایچ پی اسکرپٹ لکھنا ممکن ہے جو چند منٹوں (گھنٹوں یا دنوں تک) سے زیادہ چلیں گے: مثال کے طور پر، کرون ٹاسک، CSV پارسر، قطار بسٹر۔ وہ سب ایک ہی منظر نامے کے مطابق کام کرتے ہیں: وہ ایک کام کو بازیافت کرتے ہیں، اسے انجام دیتے ہیں، اور اگلے کام کا انتظار کرتے ہیں۔ کوڈ میموری میں رہتا ہے، قیمتی ملی سیکنڈ بچاتا ہے کیونکہ فریم ورک اور ایپلیکیشن لوڈ کرنے کے لیے بہت سے اضافی اقدامات کی ضرورت ہوتی ہے۔

لیکن دیرپا اسکرپٹ تیار کرنا اتنا آسان نہیں ہے۔ کوئی بھی خامی اس عمل کو مکمل طور پر ختم کر دیتی ہے، میموری لیک کی تشخیص آپ کو دیوانہ بنا دیتی ہے، اور آپ F5 ڈیبگنگ کو مزید استعمال نہیں کر سکتے۔

پی ایچ پی 7 کے اجراء کے ساتھ صورتحال میں بہتری آئی ہے: ایک قابل اعتماد کچرا جمع کرنے والا ظاہر ہوا ہے، غلطیوں کو سنبھالنا آسان ہو گیا ہے، اور کرنل ایکسٹینشن اب لیک ہونے سے محفوظ ہیں۔ سچ ہے، انجینئرز کو اب بھی یادداشت کے ساتھ محتاط رہنے اور کوڈ میں ریاستی مسائل سے آگاہ رہنے کی ضرورت ہے (کیا کوئی ایسی زبان ہے جہاں ہمیں ان چیزوں کے بارے میں فکر کرنے کی ضرورت نہیں ہے؟)۔ اور پھر بھی، پی ایچ پی 7 میں، کم حیرتیں ہمارے منتظر ہیں۔

کیا یہ ممکن ہے کہ طویل عرصے تک چلنے والی پی ایچ پی اسکرپٹس کے ساتھ کام کرنے کا ماڈل اختیار کیا جائے، اسے HTTP درخواستوں پر کارروائی کرنے جیسے معمولی کاموں میں ڈھال لیا جائے، اور اس طرح ہر درخواست کے لیے ہر چیز کو شروع سے لوڈ کرنے کی ضرورت کو ختم کیا جائے؟

اس مسئلے کو حل کرنے کے لیے، ہمیں سب سے پہلے ایک سرور ایپلی کیشن کو لاگو کرنے کی ضرورت ہے جو HTTP درخواستوں کو قبول کر سکے اور اسے ہر بار مارے بغیر پی ایچ پی ورکر کو ایک ایک کرکے آگے بھیج سکے۔

ہم جانتے تھے کہ ہم خالص PHP (PHP-PM) میں یا C ایکسٹینشن (Swoole) کا استعمال کرتے ہوئے ویب سرور لکھ سکتے ہیں۔ اور اگرچہ ہر طریقہ کی اپنی خوبیاں ہیں، لیکن دونوں اختیارات ہمارے موافق نہیں تھے - ہم کچھ اور چاہتے تھے۔ ہمیں صرف ایک ویب سرور سے زیادہ کی ضرورت تھی - ہمیں ایک ایسا حل ملنے کی امید تھی جو ہمیں پی ایچ پی میں "ہارڈ اسٹارٹ" سے منسلک مسائل سے بچا سکے، جسے ایک ہی وقت میں مخصوص ایپلی کیشنز کے لیے آسانی سے ڈھال اور بڑھایا جا سکتا ہے۔ یعنی ہمیں ایک ایپلیکیشن سرور کی ضرورت تھی۔

کیا جاؤ اس میں مدد کر سکتا ہوں؟ ہم جانتے تھے کہ یہ ہوسکتا ہے کیونکہ زبان ایپلی کیشنز کو سنگل بائنریز میں مرتب کرتی ہے۔ یہ کراس پلیٹ فارم ہے؛ HTTP کے ساتھ کام کرنے کے لیے اپنا، بہت ہی خوبصورت، متوازی پروسیسنگ ماڈل (کنکرنسی) اور لائبریری کا استعمال کرتا ہے۔ اور آخر کار، ہزاروں اوپن سورس لائبریریاں اور انضمام ہمارے لیے دستیاب ہوں گے۔

دو پروگرامنگ زبانوں کو یکجا کرنے میں مشکلات

پہلا قدم یہ طے کرنا تھا کہ دو یا دو سے زیادہ ایپلی کیشنز ایک دوسرے کے ساتھ کیسے بات چیت کریں گی۔

مثال کے طور پر، استعمال کرتے ہوئے شاندار لائبریری Alex Palaestras PHP اور Go کے عمل کے درمیان میموری شیئرنگ کو لاگو کر سکتا ہے (Apache میں mod_php کی طرح)۔ لیکن اس لائبریری میں ایسی خصوصیات ہیں جو ہمارے مسئلے کو حل کرنے کے لیے اس کے استعمال کو محدود کرتی ہیں۔

ہم نے ایک اور، زیادہ عام، طریقہ استعمال کرنے کا فیصلہ کیا: ساکٹ/پائپ لائنز کے ذریعے عمل کے درمیان تعامل پیدا کرنے کے لیے۔ اس نقطہ نظر نے پچھلی دہائیوں میں اپنی قابل اعتمادی کو ثابت کیا ہے اور آپریٹنگ سسٹم کی سطح پر اچھی طرح سے بہتر بنایا گیا ہے۔

شروع کرنے کے لیے، ہم نے پروسیس کے درمیان ڈیٹا کے تبادلے اور ٹرانسمیشن کی غلطیوں سے نمٹنے کے لیے ایک سادہ بائنری پروٹوکول بنایا ہے۔ اس کی سب سے آسان شکل میں، اس قسم کے پروٹوکول کی طرح ہے نیٹ سٹرنگ с فکسڈ سائز پیکٹ ہیڈر (ہمارے معاملے میں 17 بائٹس)، جس میں پیکٹ کی قسم، اس کے سائز اور ڈیٹا کی سالمیت کو چیک کرنے کے لیے بائنری ماسک کے بارے میں معلومات ہوتی ہیں۔

پی ایچ پی کی طرف ہم نے استعمال کیا۔ پیک فنکشن، اور گو سائیڈ پر - ایک لائبریری انکوڈنگ/بائنری.

ہمیں ایسا لگتا تھا کہ ایک پروٹوکول کافی نہیں ہے - لہذا ہم نے کال کرنے کی صلاحیت شامل کی۔ پی ایچ پی سے براہ راست نیٹ / آر پی سی پر جائیں۔. اس نے بعد میں ہماری ترقی میں بہت مدد کی، کیونکہ ہم آسانی سے گو لائبریریوں کو پی ایچ پی ایپلی کیشنز میں ضم کر سکتے تھے۔ اس کام کا نتیجہ دیکھا جا سکتا ہے، مثال کے طور پر، ہمارے دوسرے اوپن سورس پروڈکٹ میں گورج.

متعدد پی ایچ پی کارکنوں میں کاموں کی تقسیم

تعامل کے طریقہ کار کو لاگو کرنے کے بعد، ہم نے اس بارے میں سوچنا شروع کیا کہ کس طرح زیادہ سے زیادہ مؤثر طریقے سے کاموں کو پی ایچ پی کے عمل میں منتقل کیا جائے۔ جب کوئی کام آتا ہے، تو اسے مکمل کرنے کے لیے ایپلیکیشن سرور کو ایک مفت کارکن کا انتخاب کرنا چاہیے۔ اگر کوئی کارکن/عمل کسی غلطی کے ساتھ ختم ہو جاتا ہے یا "مر جاتا ہے"، تو ہم اس سے چھٹکارا پاتے ہیں اور اسے تبدیل کرنے کے لیے ایک نیا بناتے ہیں۔ اور اگر کارکن/عمل کامیابی سے مکمل ہو گیا ہے، تو ہم اسے کاموں کو انجام دینے کے لیے دستیاب کارکنوں کے پول میں واپس کر دیتے ہیں۔

روڈ رنر: پی ایچ پی مرنے کے لیے نہیں بنایا گیا ہے، یا گولانگ کو بچانے کے لیے نہیں بنایا گیا ہے۔

فعال کارکنوں کے ایک پول کو ذخیرہ کرنے کے لیے ہم نے استعمال کیا۔ بفر شدہ چینل, پول سے غیر متوقع طور پر "مردہ" کارکنوں کو ہٹانے کے لیے، ہم نے غلطیوں اور کارکن ریاستوں کو ٹریک کرنے کے لیے ایک طریقہ کار شامل کیا۔

نتیجے کے طور پر، ہمیں ایک کام کرنے والا پی ایچ پی سرور ملا جو بائنری شکل میں پیش کردہ کسی بھی درخواست پر کارروائی کرنے کے قابل ہے۔

ہماری ایپلیکیشن کو ویب سرور کے طور پر کام کرنے کے لیے، ہمیں آنے والی HTTP درخواستوں کی نمائندگی کرنے کے لیے ایک قابل اعتماد PHP معیار کا انتخاب کرنا تھا۔ ہمارے معاملے میں ہم صرف تبدیل فارمیٹ میں جاؤ سے net/http کی درخواست PSR-7تاکہ یہ آج دستیاب زیادہ تر پی ایچ پی فریم ورک کے ساتھ مطابقت رکھتا ہو۔

چونکہ PSR-7 کو ناقابل تغیر سمجھا جاتا ہے (کچھ کہتے ہیں کہ تکنیکی طور پر ایسا نہیں ہے)، ڈویلپرز کو ایسی ایپلی کیشنز لکھنی پڑتی ہیں جو بنیادی طور پر درخواست کو عالمی ادارہ کے طور پر نہیں مانتی ہیں۔ یہ طویل عرصے تک پی ایچ پی کے عمل کے تصور کے ساتھ اچھی طرح سے فٹ بیٹھتا ہے۔ ہمارا حتمی نفاذ، جس کا ابھی تک نام نہیں لیا گیا تھا، اس طرح نظر آیا:

روڈ رنر: پی ایچ پی مرنے کے لیے نہیں بنایا گیا ہے، یا گولانگ کو بچانے کے لیے نہیں بنایا گیا ہے۔

روڈ رنر کا تعارف - اعلی کارکردگی والا پی ایچ پی ایپلی کیشن سرور

ہمارا پہلا ٹیسٹ ٹاسک API بیک اینڈ تھا، جو وقتاً فوقتاً درخواستوں کے غیر متوقع طور پر پھٹنے کا تجربہ کرتا تھا (معمول سے کہیں زیادہ)۔ اگرچہ زیادہ تر معاملات میں nginx کافی تھا، لیکن ہمیں باقاعدگی سے 502 خرابیوں کا سامنا کرنا پڑتا ہے کیونکہ ہم بوجھ میں متوقع اضافے کے لیے سسٹم کو تیزی سے متوازن نہیں کر سکتے تھے۔

اس حل کو تبدیل کرنے کے لیے، ہم نے 2018 کے اوائل میں اپنا پہلا پی ایچ پی/گو ایپلیکیشن سرور تعینات کیا۔ اور فوری طور پر ہمیں ایک ناقابل یقین اثر ملا! نہ صرف ہم نے 502 کی خرابی سے مکمل طور پر چھٹکارا حاصل کیا، بلکہ ہم سرورز کی تعداد کو دو تہائی تک کم کرنے میں بھی کامیاب رہے، جس سے انجینئرز اور پروڈکٹ مینیجرز کے لیے بہت سارے پیسے اور سر درد کی بچت ہوئی۔

سال کے وسط تک، ہم نے اپنا حل مکمل کر لیا، اسے MIT لائسنس کے تحت GitHub پر شائع کیا، اور اسے بلایا۔ ہے Roadrunner، اس طرح اس کی ناقابل یقین رفتار اور کارکردگی پر زور دیتا ہے۔

روڈ رنر آپ کے ترقیاتی اسٹیک کو کیسے بہتر بنا سکتا ہے۔

درخواست ہے Roadrunner درخواست کے پی ایچ پی سے ٹکرانے سے پہلے JWT تصدیق کرنے کے لیے Go side پر Middleware net/http استعمال کرنے کی اجازت دی، ساتھ ہی Prometheus میں WebSockets اور عالمی ریاستی جمع کو ہینڈل کرنے کے لیے۔

بلٹ ان آر پی سی کی بدولت، آپ پی ایچ پی کے لیے کسی بھی گو لائبریری کا API بغیر ایکسٹینشن ریپر لکھے کھول سکتے ہیں۔ مزید اہم بات یہ ہے کہ روڈ رنر کو نئے غیر HTTP سرورز کو تعینات کرنے کے لیے استعمال کیا جا سکتا ہے۔ مثالوں میں پی ایچ پی میں ہینڈلرز کو لانچ کرنا شامل ہے۔ او ڈبلیو ایس لامبڈا۔, قابل اعتماد قطار بسٹرز بنانا اور یہاں تک کہ شامل کرنا جی آر پی سی ہماری درخواستوں پر۔

پی ایچ پی اور گو کمیونٹیز کی مدد سے، ہم نے حل کے استحکام میں اضافہ کیا ہے، کچھ ٹیسٹوں میں ایپلیکیشن کی کارکردگی میں 40 گنا تک اضافہ کیا ہے، ڈیبگنگ ٹولز کو بہتر بنایا ہے، سیمفونی فریم ورک کے ساتھ انضمام کو لاگو کیا ہے، اور HTTPS، HTTP/ کے لیے تعاون شامل کیا ہے۔ 2، پلگ انز، اور PSR-17۔

حاصل يہ ہوا

کچھ لوگ اب بھی PHP کے پرانے منظر میں پھنس گئے ہیں کیونکہ ایک سست، بوجھل زبان صرف ورڈپریس پلگ ان لکھنے کے لیے اچھی ہے۔ یہ لوگ یہاں تک کہہ سکتے ہیں کہ پی ایچ پی کی ایک حد ہے: جب ایپلیکیشن کافی بڑی ہو جاتی ہے، تو آپ کو زیادہ "بالغ" زبان کا انتخاب کرنا پڑتا ہے اور کوڈ بیس کو دوبارہ لکھنا پڑتا ہے جو کئی سالوں سے جمع ہو چکا ہے۔

اس سب کا میں جواب دینا چاہتا ہوں: دوبارہ سوچئے۔ ہمیں یقین ہے کہ صرف آپ ہی پی ایچ پی کے لیے کوئی پابندیاں لگا سکتے ہیں۔ آپ اپنی پوری زندگی ایک زبان سے دوسری زبان میں چھلانگ لگانے میں گزار سکتے ہیں، اپنی ضروریات کے لیے بہترین میچ تلاش کرنے کی کوشش کر سکتے ہیں، یا آپ زبانوں کو بطور اوزار سوچنا شروع کر سکتے ہیں۔ پی ایچ پی جیسی زبان کی سمجھی جانے والی خامیاں دراصل اس کی کامیابی کی وجہ ہوسکتی ہیں۔ اور اگر آپ اسے گو جیسی دوسری زبان کے ساتھ جوڑتے ہیں، تو آپ اس سے کہیں زیادہ طاقتور مصنوعات بنا سکتے ہیں اگر آپ صرف ایک زبان تک محدود تھے۔

Go اور PHP کے امتزاج کے ساتھ کام کرنے کے بعد، ہم کہہ سکتے ہیں کہ ہم ان سے محبت کرتے ہیں۔ ہم ایک دوسرے کے لیے قربان کرنے کا ارادہ نہیں رکھتے، بلکہ اس دوہری اسٹیک سے اور بھی زیادہ قیمت حاصل کرنے کے طریقے تلاش کرتے ہیں۔

UPD: ہم RoadRunner کے خالق اور اصل مضمون کے شریک مصنف کا خیرمقدم کرتے ہیں۔ Lachesis

ماخذ: www.habr.com

نیا تبصرہ شامل کریں