बहुत अधिक मेमोरी का उपयोग करते हुए MongoDB


28

हम कई हफ्तों से MongoDB का उपयोग कर रहे हैं, हमने जो समग्र प्रवृत्ति देखी है वह यह है कि मोंगोडब बहुत अधिक मेमोरी (इसके डेटासेट + इंडेक्स के पूरे आकार से बहुत अधिक) का उपयोग कर रहा है।

मैं पहले ही इस सवाल और इस सवाल के माध्यम से पढ़ चुका हूं , लेकिन जिस मुद्दे का मैं सामना कर रहा हूं, उस पते पर कोई भी नहीं जा रहा है, वे वास्तव में बता रहे हैं कि पहले से ही प्रलेखन में क्या समझाया गया है।

निम्नलिखित htop और शो dbs कमांड के परिणाम हैं ।

यहाँ छवि विवरण दर्ज करें

शो डीबीएस

मुझे पता है कि मोंगोडब मेमोरी मैप्ड आईओ का उपयोग करता है, इसलिए मूल रूप से ओएस मेमोरी में कैशिंग चीजों को संभालता है, और मोंगॉडब को सैद्धांतिक रूप से इसकी कैश्ड मेमोरी को छोड़ देना चाहिए जब कोई अन्य प्रक्रिया मुफ्त मेमोरी का अनुरोध करती है , लेकिन हमने जो देखा है, वह नहीं करता है।

OOM अन्य महत्वपूर्ण प्रक्रियाओं जैसे कि पोस्टग्रेज, रेडिस इत्यादि को मारना शुरू कर देता है (जैसा कि देखा जा सकता है, इस समस्या को दूर करने के लिए, हमने RAM को 183GB तक बढ़ा दिया है जो अब काम करती है लेकिन बहुत महंगी है। मोंगो की ~ 87GB RAM का उपयोग करना) इसके संपूर्ण डेटासेट के आकार का लगभग 4X)

इसलिए,

  1. क्या यह स्मृति उपयोग वास्तव में अपेक्षित और सामान्य है? (प्रलेखन के अनुसार, WiredTiger अपने कैश के लिए अधिकतम ~ 60% RAM का उपयोग करता है, लेकिन डेटासेट के आकार को देखते हुए, क्या इसमें इतना डेटा भी है कि 86GB रैम लेने में सक्षम हो?)
  2. यहां तक ​​कि अगर स्मृति उपयोग की अपेक्षा की जाती है, तो अन्य प्रक्रिया अधिक मेमोरी के लिए अनुरोध करने की स्थिति में मोंगो को अपनी आबंटित मेमोरी से जाने क्यों नहीं देगी? इससे पहले कि हम रैम को बढ़ाते, विभिन्न प्रकार की अन्य प्रक्रियाओं को लगातार लाइन ओओम द्वारा ही मार दिया जा रहा था, जिसमें मोंगोडब भी शामिल है।

धन्यवाद !


4
हो सकता है कि WiredTiger के इंटर्नल्स पर कुछ प्रस्तुतियां, जैसे mongodb.com/pretations/… , कुछ प्रकाश डाल सकें। मैं उम्मीद करता हूं कि 50% भौतिक RAM का डिफ़ॉल्ट उपयोग केवल एक अनुमान है कि एक समर्पित MongoDB होस्ट पर क्या आवश्यक है, और कई को इसे बदलने की आवश्यकता होगी। FWIW, मुझे विश्वास नहीं है कि cacheSizeGB की स्थापना mongo को "सीमित" कर रही है - विकल्प वहाँ है, इसलिए आपको तैनाती पर नियंत्रण है। कैश के लिए मेमोरी मैंगो "जरूरतों" का निर्धारण करने के लिए आपको अपेक्षित सर्वर लोड के तहत सर्वर कैश आंकड़ों की निगरानी करने की आवश्यकता होगी।

जवाबों:


23

ठीक है, इसलिए loicmathieu और jstell द्वारा दिए गए सुरागों का अनुसरण करने और इसे थोड़ा खोदने के बाद, ये वे चीजें हैं जो मैंने WiredTiger स्टोरेज इंजन का उपयोग करके MongoDB के बारे में पाईं। मैं इसे यहाँ डाल रहा हूँ अगर किसी को एक ही सवाल का सामना करना पड़ा।

स्मृति उपयोग सूत्र जो मैंने उल्लेख किया है, सभी 2012-2014 के थे, सभी पूर्व-तिथि वायर्डटेगर और मूल एमएमएपीवी 1 भंडारण इंजन के व्यवहार का वर्णन कर रहे हैं जिसमें संपीड़न के लिए अलग कैश या समर्थन नहीं है।

WiredTiger कैश सेटिंग्स केवल WiredTiger स्टोरेज इंजन (mongod द्वारा उपयोग की जाने वाली कुल मेमोरी नहीं) द्वारा उपयोग की जाने वाली मेमोरी के आकार को नियंत्रित करती है। कई अन्य चीजें संभवतः एक MongoDB / WiredTiger कॉन्फ़िगरेशन में मेमोरी ले रही हैं, जैसे कि निम्नलिखित:

  • WiredTiger डिस्क भंडारण को संपीड़ित करता है, लेकिन मेमोरी में डेटा असंपीड़ित है।

  • डिफ़ॉल्ट रूप से वायर्डटाइगर प्रत्येक प्रतिबद्ध पर डेटा को fsync नहीं करता है , इसलिए लॉग फाइलें रैम में भी होती हैं जो मेमोरी पर अपना टोल लेती हैं। यह भी उल्लेख किया गया है कि I / O को कुशलतापूर्वक उपयोग करने के लिए, WiredTiger I / O अनुरोधों (कैश मिस) का एक साथ उपयोग करता है, यह भी कुछ RAM लेने के लिए लगता है (वास्तव में गंदे पृष्ठ (जो बदल / अपडेट किए गए हैं) अपडेट की एक सूची है उन पर एक समवर्ती SkipList में संग्रहीत )।

  • वायर्डटाइगर अपने कैश में रिकॉर्ड के कई संस्करण रखता है (मल्टी वर्ज़न कॉन्सिरेन्सी कंट्रोल, ऑपरेशन से पहले अंतिम प्रतिबद्ध संस्करण तक पहुंच पढ़ें)।

  • WiredTiger कैश में डेटा के चेकसम रखता है।

  • MongoDB खुद खुले कनेक्शन, एकत्रीकरण, सर्वरसाइड कोड और आदि को संभालने के लिए मेमोरी की खपत करता है

इन तथ्यों को ध्यान में रखते हुए, भरोसा करना show dbs;तकनीकी रूप से सही नहीं था, क्योंकि यह केवल डेटासेट के संकुचित आकार को दर्शाता है।

पूर्ण डेटासेट आकार प्राप्त करने के लिए निम्न आदेशों का उपयोग किया जा सकता है।

db.getSiblingDB('data_server').stats()
# OR
db.stats()

यह परिणाम निम्न है:

{
    "db" : "data_server",
    "collections" : 11,
    "objects" : 266565289,
    "avgObjSize" : 224.8413545621088,
    "dataSize" : 59934900658, # 60GBs
    "storageSize" : 22959984640,
    "numExtents" : 0,
    "indexes" : 41,
    "indexSize" : 7757348864, # 7.7GBs
    "ok" : 1
}

तो ऐसा लगता है कि वास्तविक डेटासेट आकार + उसके सूचकांक उस मेमोरी के लगभग 68GB ले रहे हैं।

इन सभी को ध्यान में रखते हुए, मुझे लगता है कि मेमोरी का उपयोग अब बहुत अपेक्षित है, अच्छे हिस्से को वायर्डटेगर कैश आकार को सीमित करना पूरी तरह से ठीक है, क्योंकि यह आई / ओ संचालन को बहुत कुशलता से (जैसा कि ऊपर वर्णित है) संभालता है।

इस समस्या को दूर करने के लिए OOM की समस्या भी बनी हुई है, क्योंकि हमारे पास मोंगोडब को लेने के लिए पर्याप्त संसाधन नहीं थे, हमने OOM को समय के लिए महत्वपूर्ण प्रक्रियाओं को मारने से रोकने के लिए oom_score_adj को कम कर दिया (जिसका अर्थ है कि हमने यह कहा है कि हमारी हत्या न करें वांछित प्रक्रियाएं )।


हम एक समान मुद्दा है। MongoDB रैम खाते रहते हैं। समान अनुपात। क्या oom_score_adj समाधान आपके साथ आने के लिए सबसे अच्छी चीज थी?
हार्टेटर

@ हर्टेटर खैर हमने वायर्डटाइगर के कैशसाइज़ को कम कर दिया, अपनी अनुक्रमणिका और अनुक्रमण नीति को प्रबंधित करने के लिए और प्रयास किए, और फिर अंत में, हमने जिन चीज़ों की परवाह की, उनके लिए oom_score_adj को घटाया, मुझे लगता है कि सभी वैसे भी हो सकते हैं।
स्पिकेल

4

मुझे नहीं लगता कि आपको यहां MongoDB के साथ कोई समस्या है, क्योंकि jstell ने आपको बताया कि MongoDB WiredTiger के साथ 50% उपलब्ध मेमोरी का उपयोग करेगा, इसलिए यदि आप अपने सर्वर की रैम को बढ़ाते हैं तो यह अधिक मेमोरी लेगा।

जैसा कि यह DB + अनुक्रमित के आकार से अधिक है, ध्यान रखें कि WiredTiger डेटाबेस को डिस्क पर संपीड़ित करता है और दस्तावेज़ परिवर्तनों को रिकॉर्ड करने के लिए स्नैपशॉट लॉग का भी उपयोग करता है। तो वायर्डटाइगर का वास्तविक आकार शो डीबीएस * कम्प्रेशन_ेशन + स्नैपशॉट लॉग के आकार का उपयोग करके आकार है। इसलिए सटीक अपेक्षित आकार को जानना लगभग असंभव है।

मन में भी रखें उपकरण की तरह है कि top, ps, htopस्मृति वास्तव में आवेदन के द्वारा प्रयोग किया प्रदर्शित नहीं किया था, जानकारी के लिए इस सवाल का SOW refere: https://stackoverflow.com/questions/131303/how-to-measure-actual-memory -उपयोग के- एक आवेदन या प्रक्रिया

अब, अपने मुद्दे पर वापस। आपके पास एक ही होस्ट पर चलने वाले अन्य उपकरण हैं और एक OOM उन्हें मारता है। मैं लिनक्स ओओएम से परिचित नहीं हूं, लेकिन क्या आपको यकीन है कि यह उन लोगों की हत्या करता है, जो मोंगोबीडीबी की वजह से हैं .. या सिर्फ उनकी वजह से (हो सकता है कि यह पोस्टग्रेज को मार दें क्योंकि पोस्टग्रेज ने बहुत अधिक मेमोरी ली थी)।

वैसे भी, एक श्रेष्ठ अभ्यास के रूप में यदि आपके पास एक बड़ा मानगो डेटाबेस है, तो इसे अन्य डेटाबेस के साथ साझा किए गए होस्ट में स्थापित न करें या आपको बहुत सारी कठिनाइयाँ होंगी, अगर आप यहाँ वर्णन करते हैं, तो यह जानने के लिए एक समस्या है। जो वास्तव में मेजबान पर इस मुद्दे का कारण बनता है।


4

डॉक्स

आप MongoDB के लिए बुनियादी स्मृति चिंताओं को पढ़ना पसंद कर सकते हैं और स्मृति उपयोग की जाँच के बारे में यह संक्षिप्त चर्चा भी कर सकते हैं ।

स्मृति उपयोग अवलोकन

आदेश db.serverStatus()( डॉक्स ) विशेष रूप से स्मृति उपयोग का अवलोकन प्रदान कर सकता है:

> db.serverStatus().mem
{ "bits" : 64, "resident" : 27, "virtual" : 397, "supported" : true }

> db.serverStatus().tcmalloc
... not easy to read! ...

> db.serverStatus().tcmalloc.tcmalloc.formattedString
------------------------------------------------
MALLOC:        3416192 (    3.3 MiB) Bytes in use by application
MALLOC: +      4788224 (    4.6 MiB) Bytes in page heap freelist
MALLOC: +       366816 (    0.3 MiB) Bytes in central cache freelist
...
... a bunch of stats in an easier to read format ...

आपके सूचकांक कितने बड़े हैं?

db.stats() सभी अनुक्रमितों के कुल आकार को दिखा सकते हैं, लेकिन हम एकल संग्रह का उपयोग करके विस्तृत जानकारी भी प्राप्त कर सकते हैं db.myCollection.stats()

उदाहरण के लिए, यह आदेश हर संग्रह के लिए अनुक्रमित के आकार की तुलना करेगा :

> db.getCollectionNames().map(name => ({totalIndexSize: db.getCollection(name).stats().totalIndexSize, name: name})).sort((a, b) => a.totalIndexSize - b.totalIndexSize).forEach(printjson)
...
{ "totalIndexSize" : 696320, "name" : "smallCollection" }
{ "totalIndexSize" : 135536640, "name" : "bigCollection" }
{ "totalIndexSize" : 382681088, "name" : "hugeCollection" }
{ "totalIndexSize" : 511901696, "name" : "massiveCollection" }

अब हम उस विशाल संग्रह के विवरण को देख सकते हैं, यह देखने के लिए कि इसके कौन से सूचकांक सबसे महंगे हैं:

> db.massiveCollection.stats().indexSizes
{
        "_id_" : 230862848,
        "groupId_1_userId_1" : 49971200,
        "createTime_1" : 180301824,
        "orderId_1" : 278528,
        "userId_1" : 50155520
}

यह हमें एक बेहतर विचार दे सकता है कि बचत कहां संभव हो सकती है।

(इस मामले में, हमारे पास एक सूचकांक था createTimeजो बहुत बड़ा था - प्रति दस्तावेज एक प्रविष्टि - और हमने फैसला किया कि हम इसके बिना रह सकते हैं।)


क्या इंडेक्स में मेमोरी की बड़ी लागत होती है?
मथियास लिकेगार्ड लोरेनजेन

@MathiasLykkegaardLorenzen यह आपके सर्वर की रैम के सापेक्ष आपके द्वारा अनुक्रमित किए गए फ़ील्ड के लिए अद्वितीय मानों की संख्या पर निर्भर करता है। हमारे मामले में, createTimeसूचकांक समस्याग्रस्त था क्योंकि यह हर एक दस्तावेज़ के लिए अद्वितीय था, और यह संग्रह बहुत बड़ा था। अन्य क्षेत्रों को अनुक्रमित करना ठीक था, क्योंकि कम अद्वितीय मूल्य थे (मानों को क्लस्टर किया गया था)।
joeytwiddle
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.