डेटाबेस को बिना मृत कनेक्शन के जगाना
Mythex पर पब्लिश किए गए ऐप, और उनके डेटाबेस, कोई इस्तेमाल न करे तो सो जाते हैं। जब कोई ऐप जागता, तो वह अपना पहला अनुरोध 10–12 सेकंड तक रोके रखता था, क्योंकि वह उन डेटाबेस कनेक्शनों को दोबारा इस्तेमाल करने की कोशिश करता था जो सब कुछ सोते समय मर चुके थे। अब हम Spring Boot ऐप्स को ऐसी डेटाबेस सेटिंग्स देते हैं जो नींद के बाद भी सुरक्षित हैं, और एजेंट को हर स्टैक के ऐप्स इसी तरह बनाने का निर्देश देते हैं। होस्टिंग प्लेटफ़ॉर्म पर जागने के बाद पहला अनुरोध 12.7 सेकंड से घटकर 2.3 सेकंड हो गया।
ऐप और डेटाबेस क्यों सोते हैं
एक पब्लिश किया गया Mythex ऐप ऐसी मशीन पर चलता है जो कुछ निष्क्रिय मिनटों के बाद सस्पेंड हो जाती है, और उसका डेटाबेस सर्वरलेस Postgres है जो पाँच निष्क्रिय मिनटों के बाद सो जाता है और अगले अनुरोध पर जागता है। यही शांत ऐप को सस्ता रखता है: आप डेटाबेस के वास्तव में इस्तेमाल के लिए शुल्क देते हैं, और सोता हुआ ऐप कंप्यूट पर कुछ खर्च नहीं करता। बिलिंग वाले पक्ष के बारे में हमने डेटाबेस की बिलिंग उनके वास्तविक उपयोग से में लिखा है।
पेंच यह है कि दोनों अलग-अलग सोते हैं, और इस पर असहमत हैं कि कनेक्शन क्या होता है।
लक्षण: पहली विज़िट धीमी
अधिकांश सर्वर ऐप्स एक कनेक्शन पूल रखते हैं: खुले डेटाबेस कनेक्शनों की एक छोटी संख्या तैयार रखी जाती है, ताकि हर अनुरोध नया कनेक्शन खोलने की लागत न चुकाए। एक हमेशा-चालू ऐप के लिए यह सही डिज़ाइन है।
नींद के साथ यह होता है:
- ऐप चल रहा है, उसके पूल में कुछ निष्क्रिय कनेक्शन हैं।
- कोई विज़िट नहीं करता। ऐप की मशीन सस्पेंड हो जाती है, जमी हुई, पूल अपनी स्थिति में।
- डेटाबेस सो जाता है और हर कनेक्शन का अपना सिरा गिरा देता है।
- एक विज़िटर आता है। ऐप ठीक वैसा ही जागता है, पर अब भी ऐसे कनेक्शन थामे हुए जिन्हें डेटाबेस अब नहीं जानता।
- पूल उनमें से एक कनेक्शन देता है। उसे पहले यह पता करना होता है कि वह मर चुका है, उसे आज़माकर और इंतज़ार करके, उसे छोड़ने से पहले।
Spring Boot ऐप में उन मृत कनेक्शनों की जाँच पहले अनुरोध को लगभग 10 सेकंड तक रोकती थी, फिर वह "Connection is not available" के साथ विफल होता। विज़िटर को साइट बस अटकी हुई लगती, और फिर शायद कोई एरर दिखता।
Spring ऐप्स सबसे बुरे क्यों थे
Spring Boot एक लोकप्रिय Java फ़्रेमवर्क है, और यह डिफ़ॉल्ट रूप से HikariCP नामक कनेक्शन पूल इस्तेमाल करता है। Spring इस पूल को सेटिंग्स से कॉन्फ़िगर कर सकता है, जिसमें यह भी शामिल है कि कितने निष्क्रिय कनेक्शन रखे जाएँ।
पर Mythex हर ऐप को उसका डेटाबेस एक ही DATABASE_URL के रूप में देता है, postgresql://user:pass@host/db के फ़ॉर्मेट में। Spring उस फ़ॉर्मेट को सीधे नहीं पढ़ सकता। इसलिए Mythex पर बने Spring ऐप्स उस URL को पार्स करके कोड में अपना पूल खुद बनाते थे, और हाथ से बना पूल Spring की सभी spring.datasource.* सेटिंग्स को अनदेखा करता है। भले ही कोई सही पूल सेटिंग्स जानता, उनके लागू होने की कोई जगह ही नहीं थी।
समाधान, भाग 1: Spring के इस्तेमाल योग्य सेटिंग्स
जब किसी प्रोजेक्ट में डेटाबेस होता है, तो अब उसे Spring के सीधे पढ़ने वाले एनवायरनमेंट वेरिएबल भी मिलते हैं:
SPRING_DATASOURCE_URL,SPRING_DATASOURCE_USERNAMEऔरSPRING_DATASOURCE_PASSWORD, जोDATABASE_URLसे बदले गए हैं (जब तक URL में कुछ और न हो, SSL आवश्यक है)।- नींद के बाद भी बचने वाली पूल सेटिंग्स:
| सेटिंग | मान | क्यों |
|---|---|---|
| न्यूनतम निष्क्रिय कनेक्शन | 0 | अनुरोधों के बीच कुछ भी खुला न रखें, ताकि कुछ मृत न हो सके |
| निष्क्रिय टाइमआउट | 30 सेकंड | न इस्तेमाल होने वाले कनेक्शन जल्दी बंद करें |
| अधिकतम जीवनकाल | 2 मिनट | हर कनेक्शन को पुराना होने से पहले रिटायर करें |
| कनेक्शन टाइमआउट | 5 सेकंड | डेटाबेस धीमा हो तो अनुरोध को लंबे समय तक न रोकें |
कोई निष्क्रिय कनेक्शन न रखे जाने पर, जागा हुआ ऐप मृत कनेक्शनों के बीच से गुज़रने की बजाय एक नया कनेक्शन खोलता है।
इन वेरिएबल्स के मौजूद होने पर Spring पूल को खुद कॉन्फ़िगर करता है, और सेटिंग्स लागू होती हैं। प्रोजेक्ट ने जो कुछ खुद सेट किया है वह हमेशा जीतता है; हम केवल जो गायब है वही भरते हैं। जो ऐप Spring नहीं हैं, वे इन वेरिएबल्स को नज़रअंदाज़ करते हैं।
वह विवरण जिसने लगभग कुछ नहीं किया
Spring एनवायरनमेंट वेरिएबल्स को अपनी सेटिंग्स से एक नियम से मैप करता है, जिसे गलत समझना आसान है। सेटिंग minimum-idle को SPRING_DATASOURCE_HIKARI_MINIMUMIDLE लिखना होगा, डैश हटाकर और शब्द जोड़कर। इसे SPRING_DATASOURCE_HIKARI_MINIMUM_IDLE लिखना, जो अधिक स्वाभाविक लगता है, एक अलग, मौजूद न होने वाली सेटिंग (minimum.idle) से मैप होता है और चुपचाप अनदेखा हो जाता है।
यह ऐसी गलती है जो हर समीक्षा पास कर जाती है और प्रोडक्शन में कुछ नहीं करती। इसलिए एक टेस्ट जाँचता है कि वैल्यू सेट हैं, और कोई वेरिएबल अंडरस्कोर-अलग फ़ॉर्म में नहीं है।
समाधान, भाग 2: बाकी हर स्टैक
Spring अकेला फ़्रेमवर्क नहीं है जिसका पूल हो, और हम हर भाषा की हर लाइब्रेरी को पहले से कॉन्फ़िगर नहीं कर सकते। इसलिए Mythex का एजेंट, जो आपका ऐप लिखता है, अब किसी भी स्टैक के लिए एक स्थायी निर्देश पाता है: पब्लिश किए गए ऐप और उनके डेटाबेस निष्क्रिय होने पर सो जाते हैं, इसलिए जो कनेक्शन खुला रखा गया था वह अगले अनुरोध पर मृत हो सकता है। उसे चाहिए:
- कोई निष्क्रिय डेटाबेस कनेक्शन खुला न रखें, या इस्तेमाल से पहले हर एक की जाँच करें,
- कनेक्शन एरर पर एक बार फिर कोशिश करें, और
- वातावरण में प्लेटफ़ॉर्म द्वारा दी गई डेटाबेस सेटिंग्स इस्तेमाल करें, न कि
DATABASE_URLपार्स करके अपना पूल बनाएँ।
आख़िरी बिंदु भाग 1 के साथ लूप बंद करता है: जो ऐप दी गई सेटिंग्स पर बनता है, वह नींद-सुरक्षित कॉन्फ़िगरेशन अपने आप उठा लेता है।
परिणाम
जिस होस्टिंग प्लेटफ़ॉर्म पर हम पब्लिश किए गए ऐप चलाते हैं, वहाँ मापने पर जागने के बाद पहला अनुरोध 12.7 सेकंड से 2.3 सेकंड हो गया।
हमने क्या सीखा
- हर परत जो सोती है, इस पर सहमत होनी चाहिए कि क्या बचता है। जमे हुए ऐप और सोते डेटाबेस ने हर एक ने अपनी ओर से उचित चुनाव किया। साथ मिलकर, ऐप ऐसी स्थिति लेकर जागा जो अब सच नहीं थी।
- हमेशा-चालू सर्वरों के लिए बने डिफ़ॉल्ट उन ऐप्स के लिए ठीक नहीं बैठते जो शून्य तक स्केल होते हैं। कनेक्शन गरम रखना अच्छा विचार है, जब तक उनके आसपास सब कुछ ठंडा न हो।
- फ़्रेमवर्क को उसका डेटा उसके अपने फ़ॉर्मेट में दें। हमारे लिए एक URL सरल था, पर उसने हर Spring ऐप को हाथ से पूल बनाने पर मजबूर किया जो अपनी ही कॉन्फ़िगरेशन को अनदेखा करता था।
- जाँचें कि कोई सेटिंग उसी स्पेलिंग में है जिसमें फ़्रेमवर्क उसे पढ़ता है। सही वैल्यू गलत नाम के तहत चुपचाप कुछ नहीं करती।
अगर आप Mythex पर डेटाबेस के काम करने के तरीके में नए हैं, तो डेटाबेस डॉक्स और हमारी Postgres क्या है व्याख्या देखें।