AD

प्रोडक्शन डेटाबेस क्रैश होने से बचाएं: Slow Queries, Deadlocks और Connection Errors के 4 पक्के समाधान

प्रोडक्शन डेटाबेस क्रैश होने से बचाएं: Slow Queries, Deadlocks और Connection Errors के 4 पक्के समाधान

जब कोई वेब ऐप्लिकेशन या मोबाइल ऐप अचानक धीमा हो जाता है या 500 Internal Server Error फेंकने लगता है, तो 90% मामलों में समस्या बैकएंड कोड में नहीं बल्कि डेटाबेस (Database) लेयर में छिपी होती है। प्रोडक्शन में डेटाबेस का धीमा होना या हैंग होना किसी भी डेवलपर और सिस्टम एडमिनिस्ट्रेटर के लिए सबसे बड़ा सिरदर्द बन सकता है।

डेटाबेस परफॉर्मेंस की समस्याओं को केवल सर्वर की RAM या CPU बढ़ाकर हमेशा के लिए ठीक नहीं किया जा सकता। इसके लिए समस्या की जड़ तक पहुंचकर उसे व्यवस्थित तरीके से डीबग करना जरूरी है। इस व्यावहारिक गाइड में हम PostgreSQL, MySQL और MariaDB जैसे रिलेशनल डेटाबेस में आने वाली 4 सबसे आम और गंभीर समस्याओं, उनके पीछे के कारणों और स्टेप-बाय-स्टेप समाधानों को समझेंगे।

समस्या 1: Slow Queries और 100% CPU Usage

यह सबसे आम समस्या है जहां डेटाबेस सर्वर का CPU यूटिलाइजेशन 90% से 100% के बीच पहुंच जाता है और साधारण रीड रिक्वेस्ट्स भी टाइमआउट होने लगती हैं।

लक्षण और संभावित कारण

डैशबोर्ड पर क्वेरी लेटेंसी अचानक 50ms से बढ़कर 5000ms से अधिक हो जाती है। इसके मुख्य कारण हैं:

  • टेबल पर सही Index मौजूद न होना, जिसके कारण इंजन को लाखों पंक्तियों का Full Table Scan (Seq Scan) करना पड़ता है।
  • क्वेरी में SELECT * का अंधाधुंध इस्तेमाल और गैर-जरूरी भारी JOIN लगाना।
  • Non-sargable WHERE क्लॉज, जैसे WHERE YEAR(created_at) = 2024, जो इंडेक्स का उपयोग रोक देता है।

स्टेप-बाय-स्टेप समाधान

स्टेप 1: स्लो क्वेरी की पहचान करें
MySQL में SHOW FULL PROCESSLIST; चलाएं या PostgreSQL में नीचे दी गई क्वेरी से अटकी हुई क्वेरीज देखें:

SELECT pid, now() - pg_stat_activity.query_start AS duration, query 
FROM pg_stat_activity 
WHERE state = 'active' 
ORDER BY duration DESC;

स्टेप 2: EXPLAIN प्लान का विश्लेषण करें
धीमी चल रही क्वेरी के आगे EXPLAIN ANALYZE लगाकर रन करें। चेक करें कि कहीं आउटपुट में 'Seq Scan' या 'Using filesort' तो नहीं दिख रहा।

स्टेप 3: टार्गेटेड इंडेक्स बनाएं
फिल्टर और फॉरेन की (Foreign Key) वाले कॉलम्स पर B-Tree या कवर्ड इंडेक्स जोड़ें:

CREATE INDEX idx_orders_user_created ON orders (user_id, created_at DESC);

स्टेप 4: Non-sargable क्लॉज को सुधारें
फंक्शन-बेस्ड सर्च की जगह रेंज क्वेरी का इस्तेमाल करें, जैसे WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01'।

समस्या 2: Database Deadlocks (जब ट्रांजेक्शन एक-दूसरे को ब्लॉक कर दें)

डेडपैक वह स्थिति है जहां Transaction A किसी रो पर लॉक लेकर बैठा है और Row B की प्रतीक्षा कर रहा है, जबकि उसी समय Transaction B ने Row B को लॉक किया हुआ है और वह Row A को अनलॉक होने का इंतजार कर रहा है। डेटाबेस इंजन इसे हल करने के लिए किसी एक ट्रांजेक्शन को जबरन 'Kill' कर देता है।

लक्षण और संभावित कारण

ऐप्लिकेशन लॉग्स में Deadlock found when trying to get lock; try restarting transaction या ERROR: deadlock detected जैसे एरर दिखाई देते हैं। यह तब होता है जब मल्टीपल बैकएंड थ्रेड्स अलग-अलग क्रम में रिकॉर्ड्स को अपडेट करते हैं।

स्टेप-बाय-स्टेप समाधान

स्टेप 1: लॉक का क्रम एक समान रखें (Consistent Locking Order)
कोडबेस में हमेशा टेबल्स और रोज़ को एक निश्चित क्रम में अपडेट करें। यदि थ्रेड 1 पहले Users और फिर Accounts को लॉक करता है, तो थ्रेड 2 को भी हमेशा Users के बाद ही Accounts को लॉक करना चाहिए।

स्टेप 2: ट्रांजेक्शन का दायरा छोटा करें
ट्रांजेक्शन ब्लॉक (BEGIN ... COMMIT) के अंदर भारी थर्ड-पार्टी API कॉल्स या ईमेल ट्रिगरिंग लॉजिक न रखें। केवल वास्तविक डेटाबेस राइट ऑपरेशन्स को ही ट्रांजेक्शन में लपेटें।

स्टेप 3: Lock Timeout सेट करें
डेटाबेस को अनंत काल तक प्रतीक्षा करने से रोकने के लिए टाइमआउट कॉन्फ़िगर करें:

-- PostgreSQL उदाहरण
SET lock_timeout = '3000ms';

-- MySQL उदाहरण
SET innodb_lock_wait_timeout = 5;

स्टेप 4: ऐप्लिकेशन में Retry Logic जोड़ें
डेडपैक कभी-कभार होना स्वाभाविक है, इसलिए बैकएंड कोड में 3 बार Exponential Backoff के साथ ऑटोमैटिक री-ट्राई लॉजिक लागू करें।

समस्या 3: "Too Many Connections" एरर

अचानक ट्रैफिक बढ़ने पर या माइक्रोसर्विसेज स्केल होने पर डेटाबेस नए कनेक्शन्स स्वीकार करना बंद कर देता है और ऐप्लिकेशन पूरी तरह डाउन हो जाता है।

लक्षण और संभावित कारण

लॉग्स में FATAL: remaining connection slots are reserved for non-replication superuser connections या Error 1040: Too many connections आता है। मुख्य कारण बिना कनेक्शन पूल (Connection Pool) के सीधे डेटाबेस से कनेक्ट करना, कोड में कनेक्शन लीक होना (सफलतापूर्वक Close न करना), या सर्वर की सीमा से अधिक पैरेलल वर्कर्स होना है।

स्टेप-बाय-स्टेप समाधान

स्टेप 1: निष्क्रिय (Idle) कनेक्शन्स को तुरंत हटाएं
ऐसे कनेक्शन्स को पहचानें जो 'Idle in transaction' स्थिति में फंसे हुए हैं और रिसोर्स घेरे हुए हैं:

-- PostgreSQL: 10 मिनट से अधिक पुराने idle कनेक्शन हटाएं
SELECT pg_terminate_backend(pid) 
FROM pg_stat_activity 
WHERE state = 'idle in transaction' 
AND now() - state_change > interval '10 minutes';

स्टेप 2: Connection Pooling लागू करें
ऐप्लिकेशन और डेटाबेस के बीच एक डेडिकेटेड कनेक्शन पूलर लगाएं। PostgreSQL के लिए PgBouncer और MySQL के लिए ProxySQL का उपयोग करें। यह सर्वर पर वास्तविक 100 कनेक्शन्स के साथ बैकएंड के 5000 एक्टिव थ्रेड्स को आसानी से हैंडल कर लेता है।

स्टेप 3: ऐप्लिकेशन पूल लिमिट्स एडजस्ट करें
हर कंटेनर या पॉड (Pod) में 50 कनेक्शन्स खोलने की जगह पूल साइज को 5 से 10 पर सीमित करें (HikariCP या TypeORM में max_connections कम करें)।

समस्या 4: Disk Space Exhaustion और अनियंत्रित WAL/Transaction Logs

डेटाबेस सर्वर की डिस्क अचानक भर जाती है और डेटाबेस सेफ्टी मोड (Read-Only) में चला जाता है या सीधे क्रैश हो जाता है।

लक्षण और संभावित कारण

डिस्क केवल यूजर डेटा से नहीं भरती; बल्कि Write-Ahead Logs (WAL), MySQL के Binary Logs (binlogs), या अधूरी अनकमिटेड फाइल्स के कारण स्पेस खत्म होता है। PostgreSQL में Autovacuum का ठीक से काम न करना 'Table Bloat' पैदा कर देता है।

स्टेप-बाय-स्टेप समाधान

स्टेप 1: भारी लॉग फाइल्स की पहचान करें
सर्वर टर्मिनल पर जाकर चेक करें कि डिस्क कौन सी डायरेक्टरी ले रही है:

df -h
du -sh /var/lib/postgresql/data/* # या /var/lib/mysql/*

स्टेप 2: पुराने Binary Logs को सेफली पर्ज करें
MySQL में सीधे OS से फाइल्स डिलीट न करें, बल्कि डेटाबेस CLI के जरिए साफ करें:

PURGE BINARY LOGS BEFORE NOW() - INTERVAL 3 DAY;

स्टेप 3: PostgreSQL में Autovacuum सेटिंग्स ट्यून करें
अगर भारी डिलीट या अपडेट ऑपरेशन्स के बाद भी स्पेस खाली नहीं हो रहा है, तो टेबल का Bloat हटाने के लिए Vacuum चलाएं:

VACUUM (VERBOSE, ANALYZE) critical_table_name;

स्टेप 4: डिस्क ऑटो-स्केलिंग और अलर्ट्स चालू करें
क्लाउड प्लेटफॉर्म्स (AWS RDS, Supabase, Google Cloud SQL) में हमेशा 'Storage Auto-scaling' इनेबल रखें और डिस्क 80% भरने पर स्लैक/ईमेल अलर्ट सेट करें।

डेटाबेस स्टेबिलिटी के लिए 4 गोल्डन रूल्स

  • हर WHERE क्लॉज पर इंडेक्स न लगाएं: जरूरत से ज्यादा इंडेक्सिंग राइट (INSERT/UPDATE) परफॉर्मेंस को धीमा करती है। केवल फ्रीक्वेंट फिल्टर्स को इंडेक्स करें।
  • पेजिनेशन में OFFSET से बचें: भारी टेबल्स में OFFSET 100000 की जगह Keyset Pagination (Cursor Pagination) का उपयोग करें (जैसे WHERE id > last_seen_id LIMIT 20)।
  • क्वेरी टाइमआउट अनिवार्य करें: कभी भी किसी क्वेरी को अनिश्चित काल तक चलने न दें। statement_timeout को 10-15 सेकंड पर सेट रखें।
  • रेगुलर हेल्थ मॉनिटरिंग: pg_stat_statements या MySQL Performance Schema का उपयोग करके हर हफ्ते टॉप 10 स्लो क्वेरीज की समीक्षा करें।

अक्सर पूछे जाने वाले सवाल (FAQs)

1. क्या RAM बढ़ाने से स्लो क्वेरी की समस्या हमेशा के लिए हल हो सकती है?

नहीं। अगर किसी क्वेरी में 1 करोड़ रोज़ का टेबल स्कैन हो रहा है, तो ज्यादा RAM होने पर भी वह CPU पर भारी लोड डालेगी। हार्डवेयर अपग्रेड करने से पहले इंडेक्सिंग और क्वेरी ऑप्टिमाइजेशन पहली प्राथमिकता होनी चाहिए।

2. PostgreSQL में VACUUM FULL कब चलाना चाहिए?

सामान्य VACUUM टेबल को ब्लॉक नहीं करता, लेकिन VACUUM FULL पूरी टेबल पर एक्सक्लूसिव लॉक लगा देता है, जिससे प्रोडक्शन में अन्य क्वेरीज रुक जाती हैं। इसे केवल मेंटेनेंस विंडो के दौरान ही चलाएं जब कोई एक्टिव यूजर न हो।

3. डेटाबेस कनेक्शन लीक (Connection Leak) का पता कैसे लगाएं?

यदि आपके डेटाबेस में एक्टिव कनेक्शन्स की संख्या लगातार बढ़ती जा रही है और लोड कम होने पर भी नीचे नहीं आ रही, तो यह कनेक्शन लीक है। कोड में सुनिश्चित करें कि हर डेटाबेस कॉल के बाद कनेक्शन finally ब्लॉक में या ORM के डिफ़ॉल्ट हैंडलर द्वारा क्लोज हो रहा हो।

Post a Comment

0 Comments