מה באמת עולה טעינת כל התיקייה lib/
במאמר הזה
שורה 46 בקובץ הכניסה היחיד של השירות הזה:
foreach (glob(__DIR__ . '/lib/*.php') as $f) { require_once $f; }
אלה 65 קבצים ו־1.5 מגה־בייט שנטענים בכל בקשה. תמונת מונה, דף סטטיסטיקה, 404 — הכול אותו דבר. אתמול זה קרה 20,734 פעמים.
המספר החשוב הוא הקטן
טעינת הכול מאפס, כשמטמון קוד הפעולה כבוי, אורכת כ־132 אלפיות השנייה. זה המספר שהיה הופך זאת לבעיה, וזה אינו המספר שהשרת משלם.
כשקוד הפעולה כבר מהודר ומוחזק בזיכרון משותף, מה שנותר הוא רשימת התיקייה וקריאת stat() אחת לכל קובץ, כי אימות חותמות הזמן פעיל: 0.33 אלפיות השנייה. בתעבורה של אתמול מדובר בפחות משבע שניות עבודה לאורך כל היום.
ביניהן נמצאת מדידה שלישית, 18.2 אלפיות השנייה, שנלקחה כשמטמון קוד הפעולה קורא מדיסק במקום מזיכרון. זה חסם עליון ולא הנתון האמיתי — זה מה שקורה כשהמטמון קיים אבל איטי מהמטמון האמיתי. הוא מדווח מפני שזה הנתון היחיד במצב חם שאפשר למדוד משורת הפקודה, ולהעמיד פנים אחרת תהיה הטעות הקלה.
לכן זה כמעט לא עולה דבר, וזה כמעט לא עולה דבר אך ורק בזכות משהו אחר. אם מכבים את מטמון קוד הפעולה, אותה שורה תעלה פי ארבע מאות. זאת תלות אמיתית, וכדאי לדעת שהיא קיימת במקום לגלות אותה בזמן שדרוג.
מה יש בפועל בתוך 1.5 המגה־בייט
ארבעים ושבעה אחוז ממנו — 715 קילובתים ב־26 קבצים — הם משפחות עיצובי מונים. ציור תמונת מונה צריך בדיוק אחת מהן. 25 האחרות נטענות, מוכרזות ולעולם אין בהן שימוש.
אחריהן: מידע דגלים בנפח 189 קילובתים, שנדרש בדף הגאוגרפיה; ספריית תרשימים בנפח 158 קילובתים, שנדרשת כשמשהו מצייר תרשים. אף אחד מהם אינו מעורב בהגשת תמונת מונה, שהיא הבקשה שהשירות הזה עונה עליה יותר מכל בקשה אחרת.
העלות הגלויה של זה היא זיכרון ולא זמן. שיא הזיכרון לבקשה עולה בכארבעה מגה־בייט, ובניגוד לקוד הפעולה — שמשותף לכל התהליכים — החלק הזה משולם לכל בקשה, במקביל, בידי כל אחד מהתהליכים המבצעים בבת אחת.
מישהו כבר הבחין
ה־glob הוא lib/*.php. הוא אינו רקורסיבי, ושתי תיקיות נמצאות ממש מתחתיו: lib/live/ עם 229 קילובתים וכן lib/recht/ עם 182 קילובתים. ארבע מאות קילובתים שהיו בעבר במסלול הטעינה וכעת אינם בו.
הן הועברו כי הן גדולות ונדרשות לעיתים רחוקות: אזורי הסטטיסטיקה והטקסטים המשפטיים. עצם ההעמקה בתיקייה אחת היא כל המנגנון. אין הגדרות, אין טוען עצל, אין מפת טעינה אוטומטית — קובץ נמצא ב־glob או שאינו נמצא בו.
זה תיקון אמיתי וכדאי לומר זאת, כי הצעד הבא המובן מאליו יהיה טוען אוטומטי, וכאן טוען אוטומטי יהיה שינוי גדול לפתרון בעיה שפקודת mkdir כבר פתרה פעמיים.
למה זה נשאר
פקודת glob יחידה היא הדבר הפשוט ביותר שיכול לעבוד, ולפי הראיות היא אכן עובדת: שליש אלפית השנייה, בשרת קטן, במסלול שחייב להיות מהיר. החלפתה בקריאות require לכל קובץ פירושה שכל קובץ חדש צריך שורה במקום כלשהו, והשורה שנשכחת מפיקה שגיאה קטלנית בייצור במקום עומס מעט גדול יותר.
מה שדרוש הוא הדבר שאפשר לו לשרוד מלכתחילה, מתועד: אם קובץ בתיקייה lib/ גדל, הוא עובר לתת־תיקייה ונטען ב־require במקום שבו משתמשים בו. זה הכלל ששתי התיקיות האלה פעלו לפיו, והוא לא נכתב בשום מקום עד עכשיו.
הגרסה הכללית משעממת יותר מהמדידה. “הכול טוען הכול” הוא בדרך כלל הדפוס הלא מתאים, וכדאי למדוד את עלותו לפני שבונים אותו מחדש. כאן הוא עולה 0.33 אלפיות השנייה וארבעה מגה־בייט, וארבעת המגה־בייט הם החלק שכדאי לעקוב אחריו, כי הם גדלים עם המקביליות ואלפיות השנייה אינן גדלות.