पूरी 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 मेगाबाइट में असल में क्या है
इसका सैंतालीस प्रतिशत — 26 फ़ाइलों में 715 किलोबाइट — काउंटर डिज़ाइन परिवार हैं। काउंटर इमेज बनाने के लिए इनमें से ठीक एक की ज़रूरत होती है। बाकी 25 लोड होते हैं, डिक्लेयर होते हैं, और कभी छुए नहीं जाते।
उसके बाद: 189 किलोबाइट झंडों का डेटा, जिसकी ज़रूरत भूगोल वाले पेज पर होती है; 158 किलोबाइट चार्ट लाइब्रेरी, जिसकी ज़रूरत तब होती है जब कुछ चार्ट बनाता है। काउंटर इमेज भेजने में इनमें से किसी की भूमिका नहीं होती, और यही वह अनुरोध है जिसका जवाब यह सेवा सबसे ज़्यादा देती है।
इसकी दिखने वाली कीमत समय नहीं, बल्कि मेमोरी है। प्रति अनुरोध पीक मेमोरी लगभग चार मेगाबाइट बढ़ जाती है, और ओपकोड के उलट — जो सभी प्रोसेस में साझा होते हैं — यह हिस्सा हर अनुरोध पर चुकाया जाता है, समानांतर रूप से, हर वर्कर द्वारा एक साथ।
किसी ने पहले ही ध्यान दिया था
glob का पैटर्न है lib/*.php। यह रिकर्सिव नहीं है, और ठीक इसके नीचे दो डायरेक्टरी हैं: lib/live/ जिसमें 229 किलोबाइट हैं, और lib/recht/ जिसमें 182 किलोबाइट हैं। चार सौ किलोबाइट, जो पहले लोड होने वाले रास्ते में थे और अब नहीं हैं।
इन्हें इसलिए हटाया गया क्योंकि ये बड़ी हैं और इनकी ज़रूरत कम ही पड़ती है: आँकड़ों के सेक्शन और कानूनी टेक्स्ट। एक डायरेक्टरी नीचे होना ही पूरा तंत्र है। न कोई कॉन्फ़िगरेशन, न लेज़ी लोडर, न ऑटोलोड मैप — कोई फ़ाइल या तो glob में है या नहीं है।
यह एक असली सुधार है और यह कहना ज़रूरी है, क्योंकि अगला स्वाभाविक कदम ऑटोलोडर होता, और यहाँ ऑटोलोडर एक बड़ा बदलाव होता, एक ऐसी समस्या हल करने के लिए जिसे एक mkdir पहले ही दो बार हल कर चुका है।
यह क्यों बना रहेगा
एक अकेला glob सबसे सरल चीज़ है जो काम कर सकती है, और सबूत बताते हैं कि यह काम करता है: एक छोटे सर्वर पर, उस रास्ते पर जिसका तेज़ होना ज़रूरी है, एक मिलीसेकंड का तिहाई हिस्सा। इसकी जगह हर फ़ाइल के लिए अलग require लिखने का मतलब है कि हर नई फ़ाइल के लिए कहीं एक लाइन चाहिए, और जिस लाइन को कोई लिखना भूल जाए, वह थोड़े ज़्यादा लोड की जगह प्रोडक्शन में फ़ेटल एरर पैदा करती है।
हाँ, इसे वह चीज़ लिखित रूप में ज़रूर चाहिए, जिसने इसे शुरू से टिकाऊ बनाया: अगर lib/ में कोई फ़ाइल बड़ी हो जाए, तो वह किसी सबडायरेक्टरी में चली जाती है और जहाँ इस्तेमाल होती है, वहीं require की जाती है। यही वह नियम है जिसका वे दो डायरेक्टरी पालन कर रही थीं, और अब तक यह कहीं लिखा नहीं था।
आम सबक इस माप से ज़्यादा फीका है। “सब कुछ सब कुछ लोड करता है” आमतौर पर गलत ढाँचा है, और उसे दोबारा बनाने से पहले यह मापना फ़ायदेमंद है कि उसकी कीमत क्या है। यहाँ इसकी कीमत 0.33 मिलीसेकंड और चार मेगाबाइट है, और नज़र रखने लायक हिस्सा चार मेगाबाइट हैं, क्योंकि वे एक साथ चल रहे अनुरोधों की संख्या के साथ बढ़ते हैं, और मिलीसेकंड नहीं बढ़ते।