एका इंडेक्स नसलेल्या कॉलममुळे आमचा डेटाबेस कसा कोलमडला
एका गहाळ इंडेक्समुळे ८ ms चालणाऱ्या API चे रूपांतर ८ सेकंदांच्या भयावह अनुभवात झाले.
आम्ही एका मोठ्या रिलीजपूर्वी लोड टेस्ट (load test) केली. १०० रेकॉर्ड्ससह लोकल डेव्हलपमेंटमध्ये सर्व काही व्यवस्थित चालले होते. त्यानंतर, आम्ही प्रोडक्शन-साईज डेटा मधील १५ लाख (1.5 million) रो (rows) वर ५०० युजर्सचे सिम्युलेशन केले.
निकाल अत्यंत वाईट होते:
- API रिस्पॉन्स टाइम ४५ ms वरून ८,००० ms पर्यंत वाढला.
- डेटाबेस CPU १००% वर पोहोचला.
- कनेक्शन पूल संपले (exhausted), ज्यामुळे टाइमआउट एरर्स (timeout errors) येऊ लागले.
आम्ही स्लो-क्वेरी लॉग (slow-query log) तपासला आणि आम्हाला असा एक एंडपॉइंट (endpoint) सापडला जो युजर आयडी (user ID) आणि स्टेटस (status) नुसार ऑर्डर हिस्ट्री शोधत होता.
PostgreSQL वर EXPLAIN ANALYZE चालवल्यावर 'Sequential Scan' दिसून आला. user_id वर कोणताही इंडेक्स नसल्यामुळे, इंजिन प्रत्येक विनंतीसाठी (request) सर्व १५ लाख रो वाचत होते.
१०० एकाच वेळी येणाऱ्या (concurrent) विनंत्यांसह, त्याने एकाच वेळी १५ कोटी (150 million) रो स्कॅन केले.
यावर उपाय शोधण्यासाठी फक्त पाच मिनिटे लागली.
user_id वर साधा इंडेक्स देण्याऐवजी, आम्ही (user_id, status, created_at DESC) वर एक कंपोझिट इंडेक्स (composite index) तयार केला. यामुळे डेटाबेसला खालील गोष्टी करणे शक्य झाले:
user_idनुसार फिल्टर करणे.statusनुसार फिल्टर करणे.- नवीनतम रो (rows) त्वरित परत करणे.
- अतिरिक्त सॉर्टिंग स्टेप्स वगळणे.
आम्ही CREATE INDEX CONCURRENTLY वापरला जेणेकरून ऑपरेशन दरम्यान टेबल अनलॉक राहील.
उपाय केल्यानंतर:
- क्वेरी टाइम ८,१५० ms वरून ०.१४ ms पर्यंत खाली आला.
- API लेटन्सी (latency) ८ सेकंदांवरून १२ ms पर्यंत कमी झाली.
- CPU वापर १००% वरून ८% च्या खाली आला.
शिकायला मिळालेले धडे:
- लोकल टेस्टिंग दिशाभूल करणारे असू शकते; १०० रो (rows) हे लाखो रो चे प्रतिनिधित्व करत नाहीत.
- तुमच्या फॉरेन कीज (foreign keys) ला इंडेक्स करा—बहुतेक ORMs हे टाळतात.
- अधिक हार्डवेअर खरेदी करण्यापूर्वी
EXPLAIN ANALYZEचालवून पहा. - तुम्ही प्रत्यक्षात चालवत असलेल्या क्वेरीजच्या (queries) आधारे इंडेक्स डिझाइन करा.
सर्वात आधी सर्व्हर्स स्केल करू नका. क्वेरीज स्केल करा.
