اگر آپ file_exists($path) کو کال کرتے ہیں اور $path کسی Amazon S3 bucket کی طرف اشارہ کر رہا ہے، تو آپ مقامی ڈسک (local disk) کو استعمال نہیں کر رہے ہوتے—بلکہ آپ ایک نیٹ ورک ریکویسٹ کر رہے ہوتے ہیں۔ یہ ایک لائن کا چیک S3 کے لیے ایک راؤنڈ ٹرپ (round-trip) بن جاتا ہے جو ہر ریکویسٹ میں کئی ملی سیکنڈز کا اضافہ کر سکتا ہے۔

PHP ریموٹ اسٹور کو stream wrappers کے پیچھے چھپاتا ہے۔ fopen(), file_exists(), is_dir(), unlink() اور file_put_contents() جیسے فنکشنز ان wrappers کے ذریعے کام کرتے ہیں، جو ان کالز کو S3 API آپریشنز میں تبدیل کر دیتے ہیں۔ اس کی میپنگ بالکل سادہ ہے:

  • file_exists()HeadObject
  • is_dir()ListObjects
  • unlink()DeleteObject
  • file_put_contents()PutObject

ہر کال میں اتنی ہی لیٹنسی (latency) ہوتی ہے جتنی کہ متعلقہ S3 API ریکویسٹ میں۔ جب کوئی اسکرپٹ درجنوں فائلوں کو چیک کرتا ہے، تو یہ N+1-اسٹائل کا پیٹرن تخلیق کرتا ہے: ہر ایک چیک کے لیے ایک نیٹ ورک ہاپ (network hop)۔

یہ اب کیوں اہم ہے

ایک عام ڈویلپمنٹ انوائرمنٹ (development environment) میں فائل سسٹم اسی مشین پر ہوتا ہے، اس لیے چیک تقریباً فوری طور پر نتیجہ دے دیتا ہے۔ پروڈکشن (production) میں، جہاں اثاثے (assets) S3 پر ہوتے ہیں، وہی کوڈ کارکردگی میں بڑی کمی (performance cliff) کا باعث بنتا ہے۔ AWS SDK کچھ نتائج کو میموری میں کیش (cache) کر لیتا ہے، جس سے ایک ہی PHP پروسیس میں بار بار کیے جانے والے چیک تیز نظر آتے ہیں۔ تاہم، زیادہ تر PHP ڈیپلائمنٹس (deployments) ہر ویب ریکویسٹ کے لیے ایک نیا پروسیس شروع کرتے ہیں، جس سے ہر بار کیش صاف ہو جاتا ہے۔ نتیجہ: ہر ریکویسٹ پر ہر الگ پاتھ کے لیے ایک مکمل نیٹ ورک راؤنڈ ٹرپ۔

ایک WordPress سائٹ کو اپنا ہوم پیج رینڈر کرنے میں ایک بار دس سیکنڈ لگ گئے تھے۔ ڈیٹا بیس کوئریز (database queries) تیز تھیں، لیکن پیج نے مواد کو ترتیب دینے کے لیے صرف 73 انفرادی S3 کالز کی تھیں۔ ہر کال ایک 'کولڈ ریکویسٹ' (cold request) تھی، جس نے بظاہر بے ضرر file_exists() کو ایک نمایاں تاخیر میں بدل دیا۔

بچاؤ کی حکمت عملی (Mitigation strategies)

  • ریکویسٹس کے درمیان کیش کو برقرار رکھیں (Persist cache across requests) – ان-پروسیس کیش کو Redis جیسے مشترکہ اسٹور میں منتقل کریں۔ جب ایک ریکویسٹ کو معلوم ہو جائے کہ کوئی کی (key) S3 پر موجود ہے، تو اگلی ریکویسٹس S3 سے دوبارہ رابطہ کرنے کے بجائے کیش شدہ نتیجہ پڑھ لیں۔
  • لوکل فرسٹ ورک فلو اپنائیں (Adopt a local-first workflow) – فائلوں کو مقامی ڈسک پر لکھیں، پھر انہیں غیر ہم آہنگ (asynchronously) طریقے سے S3 کے ساتھ سنک (sync) کریں۔ مین ریکویسٹ پاتھ صرف مقامی فائل سسٹم کو چھوتا ہے؛ نیٹ ورک کا خرچہ بیک گراؤنڈ جاب (background job) پر منتقل ہو جاتا ہے۔
  • کوڈ بیس کا آڈٹ کریں (Audit the codebase) – منظم طریقے سے ان فائل سسٹم فنکشنز کو تلاش کریں جو ریموٹ Wrapper میں تبدیل ہو سکتے ہیں۔ ان تمام فنکشنز کو نشان زد کریں جو ٹائٹ لوپس (tight loops) یا ریکویسٹ کے لیے اہم راستوں (request-critical paths) میں نظر آئیں۔
  • APM ڈیٹا کا معائنہ کریں (Inspect APM data) – اگر ڈیٹا بیس میٹرکس (metrics) مستحکم رہیں لیکن رسپانس ٹائم میں اچانک اضافہ ہو، تو اسٹوریج SDK کے ٹائمنگز کی تفصیلات دیکھیں۔ SDK لیٹنسی میں اچانک اضافہ اکثر چھپی ہوئی S3 کالز کی طرف اشارہ کرتا ہے۔

اہم بات یہ ہے: ایک فنکشن جو مائیکرو سیکنڈ کے مقامی چیک جیسا لگتا ہے، وہ نیٹ ورک لیٹنسی کے کئی ملی سیکنڈز کو چھپا سکتا ہے۔ S3 پر file_exists() کو ایک بیرونی کال کے طور پر لیں، اس کے نتیجے کو کیش کریں، اور بھاری کاموں کو ریکویسٹ پاتھ سے ہٹا دیں۔ ورنہ، چھپی ہوئی لیٹنسی آپ کی سائٹ کو ایک ایک کر کے نظر انداز نیٹ ورک ریکویسٹس کے ذریعے سست کرتی رہے گی۔