אם אתם קוראים ל-file_exists($path) ו-$path מצביע על Amazon S3 bucket, אתם לא פונים לדיסק מקומי — אתם מבצעים בקשת רשת. הבדיקה בעלת השורה הבודדת הופכת ל-round-trip ל-S3 שעלול להוסיף עשרות מילישניות לכל בקשה.

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: קפיצה אחת ברשת עבור כל בדיקה בודדת.

למה זה חשוב עכשיו

בסביבת פיתוח טיפוסית, מערכת הקבצים נמצאת על אותה מכונה, ולכן הבדיקה מחזירה תוצאה כמעט באופן מיידי. בסביבת ייצור (production), שבה הנכסים (assets) נמצאים ב-S3, אותו קוד יוצר "צוק ביצועים" (performance cliff). ה-AWS SDK שומר חלק מהתוצאות בזיכרון (cache), מה שגורם לבדיקות חוזרות בתהליך PHP בודד להיראות מהירות. עם זאת, רוב פריסות ה-PHP מפעילות תהליך חדש עבור כל בקשת אינטרנט, ובכך מנקים את ה-cache בכל פעם. התוצאה: round-trip מלא ברשת עבור כל נתיב נפרד בכל בקשה.

אתר WordPress נזקק פעם לעשר שניות כדי לרנדר את דף הבית שלו. שאילתות מסד הנתונים היו מהירות, אך הדף הריץ 73 קריאות S3 בודדות רק כדי להרכיב את התוכן. כל קריאה הייתה cold request, מה שהפך file_exists() שנראה בלתי מזיק לעיכוב מורגש.

אסטרטגיות הפחתה

  • שמירת cache בין בקשות – העבירו את ה-cache הפנימי של התהליך לאחסון משותף כמו Redis. כאשר בקשה אחת מגלה שמפתח קיים ב-S3, בקשות עוקבות יקראו את התוצאה השמורה ב-cache במקום לפנות שוב ל-S3.
  • אימוץ תהליך עבודה של local-first – כתבו קבצים לדיסק מקומי, ולאחר מכן סנכרנו אותם ל-S3 באופן אסינכרוני. נתיב הבקשה העיקרי נוגע רק במערכת הקבצים המקומית; עלות הרשת עוברת למשימת רקע (background job).
  • ביצוע Audit לקוד – חפשו באופן שיטתי פונקציות של מערכת הקבצים שעלולות להסתכם ב-remote wrapper. סמנו כל פונקציה כזו שמופיעה בתוך לולאות צפופות (tight loops) או בנתיבים קריטיים לבקשה.
  • בדיקת נתוני APM – אם זמן התגובה מזנק בזמן שמדדי מסד הנתונים נשארים יציבים, בדקו לעומק את זמני ה-storage SDK. עלייה פתאומית ב-latency של ה-SDK מצביעה לעיתים קרובות על קריאות S3 נסתרות.

השורה התחתונה: פונקציה שנראית כמו בדיקה מקומית של מיקרו-שנייה יכולה להסתיר עשרות מילישניות של latency ברשת. התייחסו ל-file_exists() ב-S3 כאל קריאה חיצונית, שמרו את התוצאה ב-cache, והעבירו את העבודה הכבדה מחוץ לנתיב הבקשה. אחרת, השהיה נסתרת תמשיך להאט את האתר שלכם, בקשת רשת בלתי נראית אחת בכל פעם.