আপনি যদি file_exists($path) কল করেন এবং $path যদি একটি Amazon S3 বাকেটের দিকে নির্দেশ করে, তবে আপনি কোনো লোকাল ডিস্কে হিট করছেন না—বরং আপনি একটি নেটওয়ার্ক রিকোয়েস্ট পাঠাচ্ছেন। এই একটি লাইনের চেকটি S3-তে একটি রাউন্ড-ট্রিপে পরিণত হয়, যা প্রতিটি রিকোয়েস্টে কয়েক দশ মিলিসেকেন্ড যোগ করতে পারে।

PHP স্ট্রিম র‍্যাপার (stream wrappers)-এর মাধ্যমে রিমোট স্টোরটিকে লুকিয়ে রাখে। fopen(), file_exists(), is_dir(), unlink() এবং file_put_contents() এর মতো ফাংশনগুলো এই র‍্যাপারগুলোর মাধ্যমে কাজ করে, যা কলগুলোকে S3 API অপারেশনে রূপান্তরিত করে। এর ম্যাপিং খুবই সহজ:

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

প্রতিটি কল সংশ্লিষ্ট S3 API রিকোয়েস্টের মতোই ল্যাটেন্সি (latency) বা বিলম্ব তৈরি করে। যখন একটি স্ক্রিপ্ট ডজন ডজন ফাইল চেক করে, তখন এটি একটি N+1-স্টাইল প্যাটার্ন তৈরি করে: প্রতিটি একক চেকের জন্য একটি করে নেটওয়ার্ক হপ (network hop)।

কেন এটি এখন গুরুত্বপূর্ণ

একটি সাধারণ ডেভেলপমেন্ট এনভায়রনমেন্টে ফাইল সিস্টেম একই মেশিনে থাকে, তাই চেকটি প্রায় সাথে সাথে ফলাফল প্রদান করে। কিন্তু প্রোডাকশনে, যেখানে অ্যাসেটগুলো S3-তে থাকে, একই কোড পারফরম্যান্সের ক্ষেত্রে বড় ধরনের সমস্যা (performance cliff) তৈরি করতে পারে। AWS SDK মেমরিতে কিছু ফলাফল ক্যাশ (cache) করে রাখে, যার ফলে একটি সিঙ্গেল PHP প্রসেসে বারবার চেক করা দ্রুত মনে হয়। তবে, বেশিরভাগ PHP ডিপ্লয়মেন্ট প্রতিটি ওয়েব রিকোয়েস্টের জন্য একটি নতুন প্রসেস তৈরি করে, যা প্রতিবার ক্যাশ মুছে ফেলে। ফলাফল হলো: প্রতিটি রিকোয়েস্টে প্রতিটি আলাদা পাথের জন্য একটি পূর্ণ নেটওয়ার্ক রাউন্ড-ট্রিপ।

একটি WordPress সাইটের হোমপেজ রেন্ডার হতে একসময় দশ সেকেন্ড সময় লাগত। ডাটাবেস কুয়েরিগুলো দ্রুত ছিল, কিন্তু কন্টেন্ট সাজানোর জন্য পেজটি ৭৩টি আলাদা S3 কল ট্রিগার করেছিল। প্রতিটি কল ছিল একটি কোল্ড রিকোয়েস্ট (cold request), যা আপাতদৃষ্টিতে নিরীহ file_exists() ফাংশনটিকে একটি লক্ষণীয় বিলম্ব বা ডিলে-তে পরিণত করেছিল।

প্রশমন কৌশল (Mitigation strategies)

  • রিকোয়েস্টের মাধ্যমে ক্যাশ বজায় রাখা (Persist cache across requests) – ইন-প্রসেস ক্যাশটিকে Redis-এর মতো একটি শেয়ার্ড স্টোরে সরিয়ে নিন। যখন একটি রিকোয়েস্ট দেখে যে একটি কী (key) S3-তে বিদ্যমান, তখন পরবর্তী রিকোয়েস্টগুলো আবার S3-তে যোগাযোগ করার পরিবর্তে ক্যাশ করা ফলাফলটি পড়ে নেয়।
  • লোকাল-ফার্স্ট ওয়ার্কফ্লো গ্রহণ করুন (Adopt a local-first workflow) – ফাইলগুলো লোকাল ডিস্কে লিখুন, তারপর সেগুলোকে এসিনক্রোনাসলি (asynchronously) S3-তে সিঙ্ক করুন। মূল রিকোয়েস্ট পাথ শুধুমাত্র লোকাল ফাইল সিস্টেম ব্যবহার করবে; নেটওয়ার্কের খরচটি একটি ব্যাকগ্রাউন্ড জবে স্থানান্তরিত হবে।
  • কোডবেস অডিট করুন (Audit the codebase) – পদ্ধতিগতভাবে এমন ফাইল-সিস্টেম ফাংশনগুলো খুঁজুন যা রিমোট র‍্যাপারে রূপান্তরিত হতে পারে। যে ফাংশনগুলো টাইট লুপ (tight loops) বা রিকোয়েস্ট-ক্রিটিক্যাল পাথের ভেতরে থাকে, সেগুলোকে চিহ্নিত করুন।
  • APM ডেটা পরীক্ষা করুন (Inspect APM data) – যদি ডাটাবেস মেট্রিক্স স্থির থাকা সত্ত্বেও রেসপন্স টাইম হঠাৎ বেড়ে যায়, তবে স্টোরেজ SDK-এর টাইমিংগুলো গভীরভাবে পরীক্ষা করুন। SDK ল্যাটেন্সির হঠাৎ বৃদ্ধি প্রায়শই লুকানো S3 কলের দিকে নির্দেশ করে।

মূল কথা হলো: একটি ফাংশন যা দেখতে মাইক্রোসেকেন্ডের লোকাল চেকের মতো মনে হয়, তা কয়েক দশ মিলিসেকেন্ডের নেটওয়ার্ক ল্যাটেন্সি লুকিয়ে রাখতে পারে। S3-তে file_exists()-কে একটি এক্সটার্নাল কল হিসেবে বিবেচনা করুন, এর ফলাফল ক্যাশ করুন এবং ভারী কাজগুলো রিকোয়েস্ট পাথ থেকে সরিয়ে নিন। অন্যথায়, লুকানো ল্যাটেন্সি আপনার সাইটকে ধীর করে দেবে, একটি করে অদৃশ্য নেটওয়ার্ক রিকোয়েস্টের মাধ্যমে।