01प्रोजेक्ट का अवलोकन
keepix.cloudएक मीडिया होस्ट है जो उन उत्पादों के लिए है जिन्हें दूसरों की फ़ाइलों की सेवा करनी होती है: एक स्टोरफ्रंट में कैटलॉग फ़ोटो, एक मार्केटप्लेस में समीक्षा चित्र, एक ऐप में वॉकथ्रू वीडियो। आप एक साइन किए गए अनुरोध में मूल भेजते हैं, और उत्तर पहले से ही समाप्त पते ले जाता है - एक छवि के लिए नामित WebP विविधताओं का सेट, एक वीडियो के लिए HLS सीढ़ी। फ़ाइलें ग्राहक के अपने उपडोमेन से परोसी जाती हैं, इसलिए पाठक उनका ब्रांड देखता है और हमें कभी नहीं देखता।
यह धारणा है कि मीडिया एक विशेषता नहीं है जिसे आप प्रति परियोजना एक बार बनाते हैं। हर उत्पाद जो लोगों को कुछ अपलोड करने की अनुमति देता है, वही चीज़ फिर से लिखता है: आकार बदलना, फ़ॉर्मेट रूपांतरण, एक नामकरण योजना, एक कैश नीति, मेटाडेटा स्ट्रिपिंग, इस व्यक्ति के बारे में सब कुछ हटाने का रास्ता। पांचवीं बार लिखने पर, यह पांचवीं बार बुरी तरह से लिखा जाता है - और जो भाग गलत होते हैं (एक लीक हुआ GPS टैग, एक SVG जो एक स्क्रिप्ट निकला) चुपचाप विफल होते हैं, बिना किसी त्रुटि और बिना लॉग लाइन के।
इसलिए हमने सेवा को एक विचार के चारों ओर बनाया: पता सेवा द्वारा घोषित किया जाता है और ग्राहक द्वारा संग्रहीत किया जाता है, कभी भी ग्राहक की ओर से गणना नहीं की जाती। यह एकल निर्णय सबसे सामान्य तरीके को हटा देता है जिससे मीडिया एकीकरण टूटते हैं - एक पृष्ठ जो पूरी तरह से रेंडर होता है जिसमें उत्पाद फ़ोटो के लिए एक छिद्र होता है।
हमने पूरे उत्पाद को डिज़ाइन और बनाया: इनटेक पाइपलाइन, विविधता मॉडल, वीडियो सीढ़ी, अपने स्वयं के डोमेन और साइनिंग कुंजियों के साथ मल्टी-टेनेंट मॉडल, मीटर किए गए बिलिंग, डैशबोर्ड, सार्वजनिक API अनुबंध और दस्तावेज़ीकरण। नीचे यह है कि यह किस समस्या का समाधान करता है, इसे कैसे एक साथ रखा गया है, और कौन से इंजीनियरिंग निर्णय हम फिर से उसी तरह लेंगे।
02संदर्भ और समस्या
एक अपलोड की गई तस्वीर को स्टोर करना आसान है। एक मीडिया पथ चलाना जो वर्षों तक सही रहता है, लोड के तहत, कई उत्पादों और अन्य लोगों की फ़ाइलों के बीच, आसान नहीं है। जब हमने कार्य को अनपैक किया, तो समस्याएँ जल्दी सामने आईं।
- मनमाने चौड़ाई एक जाल है। एक URL जैसे
?w=473लचीला लगता है और वास्तव में एक साथ दो समस्याएँ हैं: एक कैश जो कभी गर्म नहीं होता, क्योंकि हर पृष्ठ थोड़े अलग संख्या की मांग करता है, और किसी के लिए प्रोसेसर को एक हजार चौड़ाई की मांग करके कब्जा करने का एक मुफ्त तरीका। - एक गणना की गई पता चुपचाप टूट जाती है।नियम "id → shard → path", जो क्लाइंट के कोड में वायर्ड है, पहले लेआउट परिवर्तन तक ठीक रहता है। फिर पृष्ठ अभी भी रेंडर होता है और उत्पाद के पास बस एक छिद्र होता है जहाँ इसकी फोटो थी — कोई त्रुटि नहीं, लॉग में कुछ नहीं।
- मेटाडेटा एक रिसाव है जिसे कोई नहीं देखता।किसी के घर के GPS निर्देशांक जो एक समीक्षा फोटो के EXIF में होते हैं, कोई त्रुटि नहीं उठाते, कोई पृष्ठ नहीं तोड़ते और कोई निगरानी नहीं पहुंचाते। यह केवल एक रिसाव होता है जब कोई देखता है।
- SVG एक चित्र नहीं है।यह निष्पादन योग्य मार्कअप है। एक छवि के रूप में स्वीकार किया गया और क्लाइंट के अपने डोमेन से परोसा गया, इसके अंदर एक स्क्रिप्ट उस डोमेन की ओर से चलती है।
- हटाना प्रमाणित होना चाहिए।एक GDPR मिटाने के अनुरोध का उत्तर जो पंक्तियों को हटाए गए के रूप में चिह्नित करता है जबकि बाइट्स डिस्क पर रहते हैं, एक ऐसा हटाना है जो नहीं हुआ।
- वीडियो एक सेट है, न कि एक फ़ाइल।एक अपलोड को एक प्ले करने योग्य सीढ़ी, एक पोस्टर फ्रेम और एक फॉलबैक में बदलना होगा — और इनमें से कोई भी उस अनुरोध के अंदर नहीं हो सकता जिसने फ़ाइल को स्वीकार किया।
- बिलिंग को छोटे नंबरों पर ईमानदार होना चाहिए।एक गीगाबाइट की कीमत एक सेंट से कम हो सकती है; पूरे सेंट में गोल करने से पूरी मीटर की बिलिंग खत्म हो जाती है और चालान एक कल्पना बन जाता है।
एक और आवश्यकता थी, और इसने पूरे डिज़ाइन को आकार दिया: सेवा को इंटरनेट में बिल्कुल नहीं जाना चाहिए. एक मीडिया होस्ट जो क्लाइंट की ओर से तीसरे पक्ष के पते से एक छवि लाता है, जानता है कि किसने क्या मांगा और उस ज्ञान को जिस CDN का उसने उपयोग किया, उसे सौंप देता है। keepix को कोई तीसरा पक्ष का पता नहीं पता है, और यह कोड की एक विशेषता है, मूल्य निर्धारण पृष्ठ पर एक वादा नहीं।
03प्रोजेक्ट के लक्ष्य
कार्य एक लक्ष्यों की सूची में बदल गया जिसे हम हर चरण में पकड़े रहे:
- एक अनुरोध अंदर, समाप्त पते बाहर।क्लाइंट मूल भेजता है और तुरंत स्टोर करने के लिए पते वापस प्राप्त करता है - कोई दूसरा कॉल नहीं, छवियों के लिए काम खत्म होने का इंतजार नहीं।
- एक नामित, सीमित सेट के रूपांतर।छवियों के लिए तीन चौड़ाई और वीडियो के लिए चार रूप, फ़ाइल के प्रकार के अनुसार घोषित, ताकि कैश गर्म रहे और प्रोसेसर किराए पर न हो।
- क्लाइंट का अपना डोमेन। फ़ाइलें यहाँ से परोसी जाती हैं
img.theirdomain, सेवा पते की पट्टी में अदृश्य है। - एक कैश जिसे हमेशा के लिए रखा जा सकता है। पता सामग्री का हैश ले जाता है, इसलिए एक फ़ाइल को बदलने से उसका पता बदल जाता है और यह तुरंत पाठक तक पहुँचता है।
- पथ में सुरक्षा निर्मित। प्रकार पार्सिंग द्वारा निर्धारित, एक वायरस स्कैन जो चीजों को पास करने के बजाय मना करता है, हर छवि पर पुनः-कोडिंग, मेटाडेटा हटाया गया, SVG दोनों सिरों पर मना किया गया।
- सिद्ध मिटाना। क्लाइंट के अपने द्वारा एक अनुरोध
owner_ref, और एक उत्तर जो बताता है कि कितने ऑब्जेक्ट और फ़ाइलें गईं। - वास्तविक अलगाव के साथ मल्टी-टेनेंसी।अपने डोमेन, अपने प्रकार और विविधताएँ, अपने सीमाएँ, दो साइनिंग कीज़ ताकि रोटेशन में कोई डाउनटाइम न हो।
- आप जांच सकते हैं कि मीटर किया गया बिलिंग।स्टोरेज औसत के रूप में, न कि पीक के रूप में, ट्रैफ़िक वास्तव में वितरित किए गए बाइट्स के रूप में, संचालन को एक-एक करके गिना गया — डैशबोर्ड में दिन के अनुसार विभाजित।
- एक API जो स्वीकार करता है कि उसने क्या किया।हर उत्तर बताता है कि क्या बनाया गया और क्या छोड़ा गया, और बैच में माइग्रेशन की जांच के लिए एक सूखी सामंजस्य बिंदु है।
04हमने क्या किया
keepix कुछ स्पष्ट टुकड़ों में टूटता है, प्रत्येक के पास एक काम है:
- इंटेक। एक साइन किया हुआ एंडपॉइंट मूल को इसके प्रकार, इसकी कुंजी और इच्छित वेरिएंट की सूची के साथ स्वीकार करता है। चित्र उसी उत्तर में तैयार होकर वापस आते हैं; वीडियो एक कतार में जाता है और उत्तर में यह कहा जाता है।
- प्रोसेसिंग पाइपलाइन। प्रकार पहचान, वायरस स्कैन, पुनः-कोडिंग, मेटाडेटा स्ट्रिपिंग, वेरिएंट निर्माण — एक निश्चित क्रम में जो प्रति अनुरोध छोड़ नहीं सकते।
- डिलीवरी। एक अलग होस्ट जिसमें कोई सत्र नहीं, कोई जावास्क्रिप्ट नहीं और कोई
Set-Cookieनहीं है, जो फ़ाइलों को सीधे डिस्क से एक साल लंबे अपरिवर्तनीय कैश के साथ सेवा देता है। - टेनेंट एपीआई। HMAC-SHA256 के साथ साइन किया गया, जिसमें पते हल करने, बैच में सामंजस्य बनाने, इन्वेंटरी निर्यात करने, एक ऑब्जेक्ट को हटाने और एक व्यक्ति से संबंधित सब कुछ मिटाने के लिए एंडपॉइंट हैं।
- डैशबोर्ड।फोल्डर, ड्रैग-एंड-ड्रॉप, शीर्षक, विवरण और टैग द्वारा खोजें — और उपयोग दिन के अनुसार विभाजित। यह पूरी तरह से बिना जावास्क्रिप्ट के काम करता है; स्क्रिप्ट सुविधा जोड़ती है, काम करने की क्षमता नहीं।
- बिलिंग।पैकेज के साथ मीटर किए गए ओवरएज, सेंट के सैकड़ों में रखे गए, जिसमें इनटेक रुकता है बजाय इसके कि मुफ्त योजना पर चुपचाप पैसे खर्च किए जाएं।
- स्टॉक।एक मार्केटप्लेस लेयर जहां किरायेदार अपने काम को खरीद और बेच सकते हैं, समान भंडारण और वितरण पथ साझा करते हुए।
नीचे सब कुछ उन टुकड़ों के अंदर के निर्णयों पर एक करीबी नज़र है — वे जो बाद में बदलने के लिए महंगे होंगे।
05सॉल्यूशन आर्किटेक्चर
सेवा तीन स्थानों के साथ है शारीरिक रूप से अलग प्रवेश बिंदु, और वह विभाजन पूरे डिज़ाइन की रीढ़ है:
- सार्वजनिक डिलीवरी - कोई API नहीं।वेब सर्वर फ़ाइल को डिस्क पर देखता है और इसे सर्व करता है। नहीं मिला का मतलब 404 है, "इसे तुरंत उत्पन्न करें" नहीं। उस पथ पर कोई निष्पादन योग्य कोड नहीं है, यही कारण है कि डिलीवरी होस्ट इसे ले जा सकता है
डिफ़ॉल्ट-स्रोत 'कोई नहीं'; सैंडबॉक्सऔर इसका मतलब है। - किरायेदार का निजी API।हर अनुरोध पर हस्ताक्षर किया गया; हस्ताक्षर विधि, पथ इसके क्वेरी स्ट्रिंग के साथ, टाइमस्टैम्प और शरीर का हैश। क्वेरी के बिना पथ पर हस्ताक्षर करने से
प्रकारऔरकीबिना हस्ताक्षर — स्वैप करने योग्य, और कोई भी इसे नहीं देखेगा। - व्यवस्थापक एपीआई नियंत्रण पैनल के लिए, इसके अपने प्रवेश बिंदु पर अपने स्वयं के क्रेडेंशियल्स के साथ।
उत्तर हमेशा JSON होते हैं और हमेशा अंग्रेजी में होते हैं, प्रत्येक अस्वीकृति कोड के लिए एक शब्दावली के साथ — इसलिए वही विफलता हर ग्राहक की लॉग में एक समान पढ़ी जाती है, चाहे उनकी उत्पाद की भाषा कुछ भी हो।
अंदर, भंडारण एक में विभाजित होता है ठंडा पेड़ मूल को धारण करते हुए, जिसे कभी भी बाहर नहीं परोसा जाता है, और विभिन्नताओं का परोसा गया पेड़। मूल को बनाए रखना यह संभव बनाता है कि एक साल बाद एक नई विविधता बिना ग्राहक से कुछ फिर से अपलोड करने के लिए कहे — और यही कारण है कि "हम उस फ़ाइल को परोसते नहीं हैं जो आपने भेजी" एक निरपेक्ष नियम हो सकता है बजाय कि सामान्यतः।
06एक फ़ाइल का जीवन
एक फ़ाइल एक निश्चित अनुक्रम से गुजरती है, और क्रम ही महत्वपूर्ण है:
- प्रकार को पार्सिंग द्वारा निर्धारित किया जाता है — सामग्री से, न कि एक्सटेंशन से और न ही क्लाइंट द्वारा कहे जाने वाले से। आउटपुट फ़ाइल पर एक्सटेंशन सेवा का होता है।
- वायरस स्कैन चलता है, और यह अस्वीकार कर सकता है।यदि स्कैनर पहुँच से बाहर है, तो इनटेक उत्तर देता है
503फ़ाइल को पास करने के बजाय। चुपचाप फ़ाइल को पास करना जबकि जांच बंद है, किए गए काम के बारे में एक झूठ है, और यह ऐसा झूठ है जो केवल बहुत बाद में सामने आता है। - छवि को फिर से एन्कोड किया जाता है।जो फ़ाइल आई थी उसका एक भी बाइट कभी वापस नहीं दिया जाता।
- मेटाडेटा फिर से एन्कोडिंग के दौरान जीवित नहीं रहता। EXIF और GPS चले गए हैं क्योंकि पथ कैसे बनाया गया है, न कि क्योंकि जिसने अपलोड किया उसने उन्हें हटाने की याद रखी।
- वेरिएंट बनाए गए हैं और उनके पते उसी उत्तर में लौटाए जाते हैं।
SVG न तो स्वीकार किया जाता है और न ही सेवा दी जाती है — कभी नहीं, अंदर आते समय या बाहर जाते समय। जांच दो बार चलती है, घोषित सामग्री प्रकार पर और फ़ाइल के पहले बाइट्स पर, क्योंकि SVG के लिए एक प्रकार स्निफर अक्सर बस "text" कहेगा। जो सेवा दी जाती है वह WebP, JPEG, PNG, MP4, एक HLS प्लेलिस्ट और इसके खंड हैं; बाकी सब एक 415.
इनटेक है आइडेम्पोटेंट: वही sha256 एक ही कुंजी के तहत काम को फिर से नहीं करता है और वही पते लौटाता है। टूटे हुए कनेक्शन के बाद पुनः प्रयास इसलिए मुफ्त हैं, जो महत्वपूर्ण है जब फ़ाइल दो गीगाबाइट की हो और नेटवर्क एक फोन हो।
07नामित रूपांतर, मनमाने चौड़ाई नहीं
छवियों के तीन नामित चौड़ाई होती हैं — थंब 400, कार्ड 1000, पूर्ण 1400, सभी WebP गुणवत्ता 82 पर — और आप नाम से एक भिन्नता मांगते हैं। सेट सीमित है और फ़ाइल के प्रकार के अनुसार घोषित किया गया है। यह निर्णय है जिस पर पूरी सेवा निर्भर करती है, और यह समस्याओं के एक वर्ग को हटाता है न कि एक बग।
दो नियम हैं जो यह निर्धारित करते हैं कि एक भिन्नता वैध रूप से क्यों नहीं दिखाई दे सकती, और दोनों पाठक को झूठ बोलने से बचाने के लिए हैं:
- कुछ भी खींचा नहीं गया है। यदि मूल भिन्नता की चौड़ाई से संकीर्ण है, तो भिन्नता मूल के आकार पर बनी रहती है और उत्तर ईमानदारी से ऐसा कहता है —
wऔरहफ़ील्ड वास्तविक संख्याएँ ले जाती हैं। एक बढ़ी हुई प्रति सेवा की गलती की तरह दिखती है, और यह सच में होगी। - समान प्रतियां दो बार नहीं रखी जाती हैं।यदि दो चौड़ाई एक ही फ़ाइल उत्पन्न करती हैं, तो दूसरा पता नहीं बनाया जाता है। दो बाइट-समान फ़ाइलें दो पते पर किसी के फोन पर एक ही चीज़ के दो डाउनलोड हैं।
जिसका मतलब है कि उत्तर पढ़ा जाना चाहिए, अनुमानित नहीं: आप दो भिन्नताएँ मांग सकते हैं और एक प्राप्त कर सकते हैं, जिसमें एक छोड़ दिया गया ब्लॉक यह बताता है कि ऐसा क्यों है। हमने इसे एक सामान्य, अपेक्षित उत्तर बना दिया है न कि एक किनारे का मामला, क्योंकि एक आशावादी आकार के खिलाफ लिखा गया एक एकीकरण पहले छोटे चित्र पर टूट जाता है जो एक उपयोगकर्ता अपलोड करता है।
बाद में एक नई भिन्नता जोड़ने के लिए कुछ भी फिर से अपलोड करने की आवश्यकता नहीं है: यह मूल से ठंडी पेड़ में बनाया गया है। यही कारण है कि मूल को रखा गया है।
08वीडियो: एक HLS सीढ़ी, एक पोस्टर और एक पूर्वावलोकन
एक वीडियो अपलोड एक सेट बन जाता है, क्योंकि यही एक खिलाड़ी को वास्तव में चाहिए: एक HLS सीढ़ी तीन गुणवत्ता स्तरों (640, 1280 और 1920 पिक्सल) तक, एक पोस्टर फ्रेम जो अवधि के 10% पर लिया गया है, एक मौन पूर्वावलोकन क्लिप पहले कुछ सेकंड के लिए होवर और फीड ऑटोप्ले के लिए, और एक प्रगतिशील MP4 पुराने क्लाइंट्स के लिए बैकअप के रूप में।
एक मूल से चौड़ा कदम नहीं बनाया जाता है, उसी कारण से कि एक खींची गई छवि नहीं होती: एक अपस्केल की गई प्रति सेवा की गलती की तरह दिखती है। पोस्टर को अवधि के एक दसवें पर लिया जाता है न कि पहले फ्रेम पर, क्योंकि एक असली वीडियो का पहला फ्रेम बहुत बार काला होता है।
वीडियो प्रोसेसिंग उस अनुरोध के अंदर नहीं होती जो फ़ाइल को स्वीकार करता है - यह एक कतार में जाती है, और उत्तर ऐसा कहता है। इनटेक प्रतिक्रिया ईमानदार है कि कौन से भाग अब तैयार हैं और कौन से लंबित हैं, ताकि एक क्लाइंट जो उसके पास है उसे संग्रहीत कर सके और बाद में फिर से पूछ सके, बजाय इसके कि उपयोगकर्ता के अपलोड स्क्रीन को एक ट्रांसकोड पर अवरुद्ध करे।
09आपका अपना डोमेन और एक स्थायी कैश
फ़ाइलें किरायेदार के अपने उपडोमेन से परोसी जाती हैं - img.theirdomain - जिसे किरायेदार एक ए रिकॉर्ड के साथ सेवा की ओर इंगित करता है। पाठक अपने ब्रांड और अपने पते को देखता है, और बिल्कुल भी कीपिक्स नहीं देखता। मुफ्त योजना पर डोमेन साझा किया जाता है; दोनों रास्ते एक ही तरीके से काम करते हैं।
एक किरायेदार जितने चाहें उतने डोमेन कनेक्ट कर सकता है लेकिन बिल्कुल एक मानक एक, और यह बाध्यता जानबूझकर है: दो मानक डोमेन के साथ एक फ़ाइल को दो पते मिलते हैं, जिसका मतलब है दो कैश और एक ही बाइट्स को एक ही पाठक के फोन पर दो बार डाउनलोड किया जाता है।
डिलीवरी हेडर हर किरायेदार के लिए समान होते हैं और नहीं बदलते: एक साल भर का अपरिवर्तनीय कैश, नोस्निफ़, डिफ़ॉल्ट-स्रोत 'कोई नहीं'; सैंडबॉक्स, पढ़ने के लिए एक उदार CORS नीति, और न ही एक Set-Cookie. हमेशा का कैश सुरक्षित है क्योंकि पता सामग्री का हैश ले जाता है: बाइट्स को बदलें और पता उनके साथ बदल जाता है, इसलिए एक प्रतिस्थापित छवि तुरंत पाठक तक पहुँचती है बजाय इसके कि TTL का इंतज़ार करे।
और यही कारण है कि पता क्लाइंट की तरफ से गणना नहीं किया जा सकता। यह सेवा द्वारा लौटाया जाता है, उस रिकॉर्ड के बगल में संग्रहीत किया जाता है जिससे यह संबंधित है, और फिर से पूछा जाता है हल करें यदि यह कभी खो जाए।
10इनटेक: प्रकार, वायरस स्कैन, मेटाडेटा
सेवा पर सब कुछ एक फ़ाइल है जो किसी व्यक्ति ने भेजी है - समीक्षा में एक फोटो, एक वॉकथ्रू वीडियो। इनटेक नियम उनके लिए लिखे गए हैं न कि रूप के लिए, और उनमें से प्रत्येक इस कारण से मौजूद है क्योंकि विकल्प चुपचाप विफल हो जाता है।
पार्सिंग द्वारा प्रकार निर्धारित करनाविस्तार के बजाय पेडेंट्री नहीं है: विस्तार वह एक चीज़ है जिसे अपलोडर पूरी तरह से नियंत्रित करता है।जब स्कैनर डाउन होता है तो मना करनाउपलब्धता की कीमत चुकाता है और यह गारंटी खरीदता है कि "स्कैन किया गया" का मतलब स्कैन किया गया है।हर छवि को फिर से एन्कोड करनाका मतलब है कि एक तैयार की गई फ़ाइल कभी भी अपने मूल रूप में पाठक तक नहीं पहुँचती।उस पुनः-कोडिंग के दौरान मेटाडेटा को हटानाका मतलब है कि इसे भुलाया नहीं जा सकता।
डिलीवरी पक्ष पर गारंटी संरचनात्मक होती हैं न कि प्रक्रियात्मक। डिलीवरी होस्ट में कोई सत्र नहीं होते, कोई जावास्क्रिप्ट नहीं होती और न ही पथ पर कोई निष्पादन योग्य कोड होता है; सामग्री एक सामग्री सुरक्षा नीति के साथ बाहर जाती है जो एक ब्राउज़र को कुछ भी चलाने से रोक देगी, भले ही कुछ खतरनाक अंदर आ गया हो। दो स्वतंत्र परतें, क्योंकि दिलचस्प विफलताएँ वे होती हैं जहाँ पहली परत गलत कॉन्फ़िगर की गई थी और किसी ने ध्यान नहीं दिया।
डिलीवरी लॉग, जिसमें पाठकों के पते होते हैं, जीवित है 24 घंटे। सेवा में इसे लंबे समय तक रखने की आवश्यकता नहीं है, जो अन्य लोगों के निशानों का केवल संचय बनाता है।
11एक व्यक्ति के बारे में सब कुछ मिटाना
प्रत्येक वस्तु एक owner_ref ले जाती है - जो भी किरायेदार उस फ़ाइल के मालिक को कहता है। कैटलॉग छवियों के लिए यह खाली है: वे किसी व्यक्ति के बारे में नहीं हैं। समीक्षा फ़ोटो और उपयोगकर्ता वीडियो के लिए यह आवश्यक है।
एक अनुरोध इसके तहत सब कुछ मिटा देता है, और उत्तर एक संख्या का नाम देता है: कितने ऑब्जेक्ट और कितनी फ़ाइलें गईं। वह संख्या एंडपॉइंट का बिंदु है। एक व्यक्तिगत डेटा गेट को निष्पादन की जांच करनी चाहिए, इरादे की नहीं — एक पंक्ति जो हटा दी गई है जबकि बाइट्स अभी भी डिस्क पर हैं, एक ऐसा हटाना है जो नहीं हुआ, और यह तब तक नहीं होगा जब तक कोई देखता नहीं।
हटाना रिकॉर्ड और बाइट्स को एक साथ हटा देता है न कि किसी कार्यक्रम पर, और यह पहले के संस्करणों की स्थगित प्रतियों को भी ले जाता है। यह वह हिस्सा भी है जो keepix को एक उत्पाद के रूप में उपयोगी बनाता है जिसकी अपनी GDPR जिम्मेदारियाँ हैं: क्लाइंट के कोड में एक हटाने की प्रक्रिया इसे इनलाइन कॉल कर सकती है और गिनती वापस पढ़ सकती है, इसके बजाय कि कहीं एक सफाई कार्य इसे प्राप्त करेगा।
हस्ताक्षर कुंजी उसी तरह काम करती हैं।एक किरायेदार हमेशा दो का उपयोग करता है, क्योंकि एक कुंजी रोटेशन का मतलब डाउनटाइम है — और डाउनटाइम ही है जो रोटेशन को हमेशा के लिए स्थगित कर देता है। रहस्य एक बार जारी होने पर दिखाया जाता है और इसे नियंत्रण पैनल को वापस नहीं दिया जाता: एक अनुरोध पर हस्ताक्षर करने में सक्षम होना किसी और के स्टोरेज में लिखने का अधिकार है।
12एक हस्ताक्षरित API और सामंजस्य
हर निजी अनुरोध में चार हेडर होते हैं — किरायेदार, कुंजी आईडी, टाइमस्टैम्प और हस्ताक्षर — और हस्ताक्षर है HMAC-SHA256 विधि, पूर्ण पथ के साथ क्वेरी, टाइमस्टैम्प और शरीर के हैश पर। विंडो 300 सेकंड है। एक समान हस्ताक्षरित अनुरोध जो उसी सेकंड के भीतर दोहराया जाता है, उसे पुनःप्रस्तुति के रूप में अस्वीकार कर दिया जाता है, जो कि सुरक्षा का सही तरीके से काम करना है, और अनुबंध इसे स्पष्ट रूप से कहता है बजाय इसके कि एकीकृत करने वालों को इसे खोजने के लिए छोड़ दे।
एंडपॉइंट सेट छोटा है और प्रत्येक एक वास्तविक संचालन प्रश्न का उत्तर देता है:
रखें— एक मूल स्वीकार करें;रखें-परिवर्तन— एक पहले से समाप्त प्रति को बिना पुनः-कोडित किए स्वीकार करें, जो ग्राहक के पास पहले से है उसे स्थानांतरित करने के लिए। एक समाप्त प्रति को पुनः-कोडित करना गुणवत्ता को बिना किसी कारण के खोने का मतलब है।हल करेंऔरसुलझाना-बैच(1000 कुंजी तक) — इस कुंजी के पास कौन से पते हैं। यह एक मरम्मत उपकरण है: यदि एक रिकॉर्ड खो जाता है तो आप पूछते हैं न कि अनुमान लगाते हैं।सुलह— एक सूखी जांच, एक समय में 1000 रिकॉर्ड तक, जो कुछ भी नहीं बदलती और उत्तर देती हैठीक है/गायब/असंगति/लंबितप्रति रिकॉर्ड के लिए और बैच का एक सारांश।इन्वेंटरी— निर्यात जो तुलना को दूसरी दिशा में चलाता है, सेवा की सूची के खिलाफ ग्राहक की, कुंजी द्वारा पृष्ठबद्ध ताकि पृष्ठ उस समय नहीं खिसके जब चीजें मध्य-चलन में स्वीकार की जा रही हैं।वस्तु,मिटाना,कोटा,पिंग, और एक बिना हस्ताक्षर वालाहेल्थजजो कहता है कि फ्रंट एंड जीवित है और कुछ नहीं — न संस्करण, न डेटाबेस स्थिति।
सुलह को अपनी नोट की आवश्यकता है, क्योंकि यह वह अंत बिंदु है जो पूरे अनुबंध को सही ठहराता है। एक बड़े माइग्रेशन के बाद एक ही सवाल महत्वपूर्ण होता है: क्या सब कुछ पार हो गया। इसे एक फाइल में एक बार में उत्तर देना मतलब है जितने अनुरोध हैं उतनी फाइलें, इसलिए कोई ऐसा नहीं करता — और फिर एक माइग्रेशन को इस आधार पर समाप्त घोषित किया जाता है कि अपलोड स्क्रिप्ट क्रैश नहीं हुई। बैच सुलह ईमानदार उत्तर को इतना सस्ता बनाती है कि वास्तव में इसे प्राप्त किया जा सके।
13डैशबोर्ड, उपयोग और बिलिंग
डैशबोर्ड एक पुस्तकालय है जिसमें कोई कोड नहीं है: फ़ोल्डर, माउस के साथ फ़ाइलें खींचना, शीर्षक, विवरण और टैग द्वारा खोज। यह काम करता है पूर्ण रूप से बिना जावास्क्रिप्ट के — स्क्रिप्ट सुविधा जोड़ती है, काम करने की क्षमता नहीं। यह कोई पुरानी यादें नहीं हैं; यह खराब कनेक्शन पर पैनल को उपयोगी बनाए रखने और बिना ब्राउज़र इंजन के परीक्षण योग्य रखने का सबसे सस्ता तरीका है।
उपयोग महीने की शुरुआत से गिना जाता है और दिन के अनुसार विभाजित किया जाता है: कितनी स्टोरेज, कितनी डिलीवरी ट्रैफिक और प्रत्येक तारीख पर कितनी ऑपरेशंस हुईं, पैकेज का कितना हिस्सा खाया गया और क्या ऊपर आया। विभाजन कुल से अधिक महत्वपूर्ण है — एक बिल जिसे आप किसी दिन को नहीं सौंप सकते, वह एक बिल है जिस पर आप बहस नहीं कर सकते।
बिलिंग में तीन निर्णय नाम लेने लायक हैं:
- स्टोरेज अवधि का औसत है, न कि पीक।एक ही दिन में बड़े अपलोड के लिए पूरे महीने की कीमत नहीं होनी चाहिए।
- डिलीवरी ट्रैफिक वे बाइट्स हैं जो वास्तव में डिलीवर की गई हैं, सर्वर लॉग से लिया गया — न कि "फाइल आकार × अनुरोधों की संख्या", जो हर रेंज अनुरोध और हर छोड़े गए डाउनलोड को अधिक आंकता है।
- दरें सेंट के सौवें हिस्से में रखी जाती हैं।एक गीगाबाइट की कीमत एक सेंट से कम हो सकती है; पूरे सेंट में गोल करने से पूरी मीटर की गई बिलिंग खत्म हो जाएगी और चुपचाप चालान को कल्पना में बदल देगी।
फ्री प्लान पर कोई मीटर की गई बिलिंग नहीं है: इनटेक रुक जाता है बजाय इसके कि चुपचाप ग्राहक का पैसा खर्च करना शुरू कर दे। एक सेवा जो अपने आप किसी को बिल करने का निर्णय लेती है जिसने कभी कार्ड दर्ज नहीं किया, वह सेवा है जिसे कोई दो बार नहीं सुझाता।
14प्रौद्योगिकी स्टैक
हमने उस सेवा के लिए स्टैक चुना जिसका हॉट पाथ एक वेब सर्वर है जो एक फ़ाइल को हैंडल करता है:
- PHP 8.4 एपीआई और नियंत्रण पैनल के लिए — परिपक्व, इस पाथ पर पर्याप्त तेज और चलाने के लिए सस्ता, जो एक मुफ्त स्तर वाले उत्पाद के लिए महत्वपूर्ण है।
- एक समर्पित डिलीवरी होस्ट जो सीधे डिस्क से सेवा दे रहा है, बिना किसी एप्लिकेशन कोड के अनुरोध पाथ में।
- WebP निश्चित गुणवत्ता में छवियों के लिए, H.264 + AAC in HLS वीडियो के लिए जिसमें एक प्रगतिशील MP4 बैकफॉल है।
- एक कतारवीडियो कार्य के लिए, इसलिए एक ट्रांसकोड कभी भी अपलोड अनुरोध के अंदर नहीं बैठता।
- HMAC-SHA256प्रत्येक टेनेन्ट के लिए दो लाइव कुंजी के साथ अनुरोध हस्ताक्षर और 300 सेकंड की विंडो।
- ओरिजिनल का एक ठंडा पेड़सेवा पथ के बाहर, जो नए रूपांतर और पुनर्निर्माण को बाद में संभव बनाता है।
सेवा जानबूझकर इस पर निर्भर रहने में सतर्क है। यह अपने स्वयं के कोई आउटबाउंड अनुरोध नहीं करता, कोई तृतीय-पक्ष CDN का उपयोग नहीं करता और टेनेन्ट, कुंजी, प्रकार, बाइट गिनती और रूपांतर के अलावा ग्राहक के उपयोगकर्ताओं के बारे में कोई रिकॉर्ड नहीं रखता। आपके पास जो भी निर्भरता नहीं है, वह एक निर्भरता है जो मंगलवार को आपके मीडिया को तोड़ नहीं सकती।
15डिजाइन और UX
सार्वजनिक साइट का एक ही काम था: एक बुनियादी ढांचा उत्पाद को उस इंजीनियर के लिए स्पष्ट बनाना जो वास्तव में इसे एकीकृत करेगा। इसलिए पहला स्क्रीन वास्तविक अनुरोध और वास्तविक उत्तर दिखाता है - JSON में वापस आने वाले पते - न कि उनका एक अमूर्त रूप। एक एकीकृत करने वाला लगभग तीस सेकंड में तय करता है कि एक मीडिया सेवा उनके कोड में फिट बैठती है, और वे इसके उत्तर के आकार को देखकर तय करते हैं।
साइट का बाकी हिस्सा उसी तरह लिखा गया है। प्रत्येक क्षमता को इसके प्रतिबंध के साथ stated किया गया है: नामित रूपांतर औरक्यों मनमाने चौड़ाई को अस्वीकार किया जाता है; एक स्थायी कैशऔरपते में हैश जो इसे सुरक्षित बनाता है; एक मिटाने का अंत बिंदुऔरजिस संख्या के साथ यह उत्तर देता है। दस्तावेज़ जो केवल यह सूचीबद्ध करता है कि एक सेवा क्या कर सकती है, पाठक को उत्पादन में किनारों की खोज करने के लिए छोड़ देता है।
डैशबोर्ड में वही सिद्धांत बिना-जावास्क्रिप्ट आधार रेखा और दिन-प्रतिदिन के उपयोग के टूटने में बदल जाता है: स्क्रीन पर कुछ भी नहीं जो पाठक जांच नहीं कर सकता, और कुछ भी नहीं जो काम करना बंद कर देता है जब एक स्क्रिप्ट लोड होने में विफल होती है।
16हमने कैसे काम किया
प्रोजेक्ट चरणों में चला, प्रत्येक कुछ प्रदर्शनीय में समाप्त होता है:
- पहले अनुबंध।हमने API अनुबंध लिखा - हस्ताक्षर योजना, अंत बिंदु, अस्वीकृति कोड, उत्तर आकार - कार्यान्वयन से पहले, क्योंकि अनुबंध वह हिस्सा है जिस पर ग्राहक निर्माण करते हैं और वह हिस्सा है जिसे बदलना महंगा होता है।
- इंटेक और विविधताएँ।पाइपलाइन, अपने निश्चित क्रम में, दो नियमों के साथ कि न तो खींचना है और न ही डुप्लिकेट संग्रहीत करना है, शुरू से ही निर्मित है।
- डिलीवरी।अलग होस्ट, हेडर सेट, सामग्री-हैश किया गया पता जो स्थायी कैश को सुरक्षित बनाता है।
- वीडियो।सीढ़ी, पोस्टर और पूर्वावलोकन, और कतार जो अपलोड अनुरोध से ट्रांसकोडिंग करती रहती है।
- मल्टी-टेनेंसी।डोमेन, प्रकार, विविधताएँ, सीमाएँ, और दो-की रोटेशन मॉडल।
- बिलिंग और डैशबोर्ड।दिन-प्रतिदिन के विभाजन के साथ मीटर की गणना, फिर इसके ऊपर लाइब्रेरी UI।
- एक वास्तविक माइग्रेशन।हमने एक लाइव कैटलॉग को सेवा पर स्थानांतरित किया और इसे बैचों में समायोजित किया - यही कारण है कि समायोजन अंत बिंदु ने अपना आकार प्राप्त किया।
यह अंतिम चरण किसी भी मात्रा के आंतरिक परीक्षण से अधिक मूल्यवान था। वास्तविक फ़ाइलों के सैकड़ों हजारों को स्थानांतरित करने से उन चीज़ों का पता चला जो एक परीक्षण सूट नहीं करता: वस्तुएं जिन्हें सेवा ने स्वीकार किया और खो दिया, रिकॉर्ड जिनका संग्रहीत पता भटक गया था, और एक जांच के बीच का अंतर जो हैश की पुष्टि करता है और एक जांच जो केवल यह पुष्टि करता है कि एक पंक्ति मौजूद है। एक सत्यापन जिसमें सत्यापित करने के लिए कुछ नहीं बचा है, सफलता की रिपोर्ट करता है - इसलिए हमने कमजोर मोड को यह बताने के लिए बनाया कि यह किस मोड में है।
17परिणाम
जो निकला वह एक मीडिया होस्ट है जिस पर एक उत्पाद निर्भर कर सकता है: एक साइन किया हुआ अनुरोध अंदर, समाप्त पते बाहर, ग्राहक के डोमेन से सेवा दी गई, जिसमें एक कैश है जिसे हमेशा के लिए रखा जा सकता है।
- नामित रूपांतर और एक HLS सीढ़ी, एक बार बनाई गई और हमेशा के लिए सामग्री-हैश किए गए पते के पीछे कैश की गई।
- क्लाइंट का अपना उपडोमेन: पाठक अपने ब्रांड को देखता है, हमारा नहीं।
- इनटेक पथ में सुरक्षा - पार्स किया गया प्रकार, वायरस स्कैन से इनकार, पुनः-कोडिंग, स्ट्रिप की गई मेटाडेटा, दोनों सिरों पर SVG से इनकार।
- एक संख्या के साथ उत्तर देने वाली मिटाई, ताकि व्यक्तिगत डेटा गेट निष्पादन की जांच कर सके न कि इरादे की।
- अपने डोमेन, अपने छतों और बिना डाउनटाइम के दो-की रोटेशन के साथ मल्टी-टेनेंसी।
- सौवें हिस्से में मापी गई बिलिंग, दिन के अनुसार विभाजित, और एक मुफ्त योजना जो खर्च करने के बजाय रुक जाती है।
18सीखने योग्य बातें
keepix एक ऐसा मामला है जहाँ अधिकांश इंजीनियरिंग यह तय करने में गई कि सेवा क्या करेगी इनकार करने के लिए। कोई मनमाना चौड़ाई नहीं, कोई गणना की गई पते नहीं, कोई SVG नहीं, कोई आउटबाउंड अनुरोध नहीं, सर्व किए गए पथ पर मूल बाइट्स को बनाए रखने के लिए नहीं, मुफ्त योजना पर बिलिंग नहीं। इनमें से प्रत्येक एक संपूर्ण विफलता की श्रेणी को हटाता है बजाय इसके कि एक को संभाले।
हम जो मुख्य पाठ अगले बुनियादी ढांचे के प्रोजेक्ट में ले जाएंगे: ईमानदार उत्तर को सस्ता बनाना. बैचों में सुलह, दिन के अनुसार उपयोग का विभाजन, एक मिटाने की प्रक्रिया जो एक गिनती लौटाती है, एक इनटेक प्रतिक्रिया जो बताती है कि उसने क्या छोड़ा — हर मामले में विकल्प गलत उत्तर नहीं था बल्कि कोई उत्तर नहीं था, और कोई उत्तर वही है जो टीमें चुपचाप स्वीकार कर लेती हैं।
यदि आपको अपने स्वयं के डोमेन के तहत एक मीडिया सेवा की आवश्यकता है, एक फ़ाइल पाइपलाइन जो अन्य लोगों के अपलोड के साथ सुरक्षित होनी चाहिए, या एक API-प्रथम उत्पाद जहां अनुबंध स्क्रीन से अधिक महत्वपूर्ण है, तो यह वह प्रकार का काम है जो हम अंत से अंत तक करते हैं।



