MongoDB ใช้หน่วยความจำมากเกินไป


28

เราใช้ MongoDB เป็นเวลาหลายสัปดาห์แล้วแนวโน้มโดยรวมที่เราเห็นคือ mongodb ใช้หน่วยความจำมากเกินไป (มากกว่าขนาดของชุดข้อมูล + ดัชนีทั้งหมด)

ฉันได้อ่านคำถามนี้แล้วและคำถามนี้แต่ดูเหมือนจะไม่มีใครตอบปัญหาที่ฉันพบพวกเขากำลังอธิบายสิ่งที่อธิบายไว้ในเอกสารแล้ว

ต่อไปนี้เป็นผลลัพธ์ของhtopและแสดงคำสั่งdbs

ป้อนคำอธิบายรูปภาพที่นี่

แสดง dbs

ฉันรู้ว่า mongodb ใช้หน่วยความจำที่แมป IO ดังนั้นโดยทั่วไประบบปฏิบัติการจะจัดการกับการแคชสิ่งต่าง ๆ ในหน่วยความจำและ mongodb ในทางทฤษฎีควรปล่อยหน่วยความจำแคชในทางทฤษฎีเมื่อกระบวนการอื่นร้องขอหน่วยความจำที่ว่างแต่จากสิ่งที่เราเห็น

OOM เริ่มฆ่ากระบวนการที่สำคัญอื่น ๆ เช่น postgres, redis และอื่น ๆ (ดังที่เห็นได้ว่าเพื่อเอาชนะปัญหานี้เราได้เพิ่ม RAM เป็น 183GB ซึ่งตอนนี้ใช้งานได้ แต่มีราคาแพงมาก mongo ใช้ ram ~ 87GB เกือบ 4X ของขนาดของชุดข้อมูลทั้งหมด)

ดังนั้น,

  1. นี่เป็นการใช้งานหน่วยความจำมากมายที่คาดหวังและปกติหรือไม่? (ตามเอกสารประกอบ WiredTiger ใช้ RAM ส่วนใหญ่ประมาณ ~ 60% สำหรับแคช แต่เมื่อพิจารณาขนาดชุดข้อมูลแล้วยังมีข้อมูลเพียงพอที่จะใช้ RAM ขนาด 86GB ได้หรือไม่)
  2. แม้ว่าคาดว่าจะมีการใช้หน่วยความจำทำไม mongo ไม่ปล่อยหน่วยความจำที่จัดสรรในกรณีที่กระบวนการอื่นเริ่มร้องขอหน่วยความจำเพิ่มเติม กระบวนการทำงานอื่น ๆ อีกมากมายถูก linux oom ถูกฆ่าอย่างต่อเนื่องรวมถึง mongodb เองก่อนที่เราจะเพิ่มแรมและมันทำให้ระบบไม่เสถียรอย่างสมบูรณ์

ขอบคุณมาก!


4
บางทีการนำเสนอบางอย่างเกี่ยวกับ internals ของ WiredTiger เช่นmongodb.com/presentations/ ......อาจทำให้บางส่วนมีปัญหา ฉันคาดว่าการใช้งานเริ่มต้นของ 50% ของ RAM ที่มีอยู่จริงเป็นเพียงการคาดเดาสิ่งที่จำเป็นสำหรับโฮสต์ MongoDB โดยเฉพาะและหลายคนจะต้องเปลี่ยนมัน FWIW ฉันไม่เชื่อว่าการตั้งค่า cacheSizeGB คือ "จำกัด " Mongo - ตัวเลือกอยู่ที่นั่นเพื่อให้คุณสามารถควบคุมการปรับใช้ การพิจารณาว่า "ความต้องการ" ของหน่วยความจำขนาดเท่าไรสำหรับแคชจะทำให้คุณต้องตรวจสอบสถิติแคชของเซิร์ฟเวอร์ภายใต้การโหลดเซิร์ฟเวอร์ที่คาดไว้

คำตอบ:


23

โอเคดังนั้นหลังจากติดตามเบาะแสที่ได้รับจาก loicmathieu และ jstell และขุดมันขึ้นมาเล็กน้อยสิ่งเหล่านี้เป็นสิ่งที่ฉันค้นพบเกี่ยวกับ MongoDB โดยใช้เครื่องมือจัดเก็บแบบใช้สายของ WiredTiger ฉันจะวางไว้ที่นี่ถ้าใครพบคำถามเดียวกัน

เธรดการใช้งานหน่วยความจำที่ฉันกล่าวถึงทั้งหมดเป็นของ 2012-2014 ทุก WiredTiger วันที่ล่วงหน้าและกำลังอธิบายพฤติกรรมของเครื่องมือจัดเก็บ MMAPV1 ดั้งเดิมซึ่งไม่มีแคชแยกต่างหากหรือสนับสนุนการบีบอัด

การตั้งค่าแคช WiredTiger จะควบคุมขนาดของหน่วยความจำที่ใช้โดยตรงโดยเอ็นจิ้นการเก็บข้อมูล WiredTiger โดยตรง (ไม่ใช่หน่วยความจำทั้งหมดที่ใช้โดย Mongo) มีสิ่งอื่น ๆ อีกมากมายที่อาจรับหน่วยความจำในการกำหนดค่า MongoDB / WiredTiger เช่นต่อไปนี้

  • WiredTiger บีบอัดที่เก็บข้อมูลในดิสก์ แต่ข้อมูลในหน่วยความจำจะไม่ถูกบีบอัด

  • WiredTiger โดยค่าเริ่มต้นจะไม่ทำการซิงค์ข้อมูลในแต่ละการกระทำดังนั้นไฟล์บันทึกจะอยู่ใน RAM ซึ่งเก็บค่าผ่านทางหน่วยความจำ มีการกล่าวถึงด้วยว่าในการใช้ I / O ได้อย่างมีประสิทธิภาพ WiredTiger จะทำการร้องขอ I / O (แคชที่หายไป) เข้าด้วยกันซึ่งดูเหมือนว่าจะใช้ RAM บางอัน (อันที่จริงแล้วหน้าเว็บสกปรก (หน้าเว็บที่มีการเปลี่ยนแปลง ที่จัดเก็บไว้ในรายการข้ามที่เกิด ขึ้นพร้อมกัน )

  • WiredTiger เก็บบันทึกหลาย ๆ รุ่นไว้ในแคช (การควบคุมการทำงานพร้อมกันหลายรุ่น, อ่านการดำเนินการเข้าถึงรุ่นที่ได้ทำไว้ล่าสุดก่อนที่จะดำเนินการ)

  • 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

เมื่อพิจารณาทั้งหมดเหล่านี้ฉันเดาว่าการใช้หน่วยความจำคาดว่าน่าจะดีส่วนที่ดีคือมันโอเคอย่างสมบูรณ์ในการ จำกัด ขนาดแคช WiredTiger เนื่องจากจัดการกับการทำงานของ I / O ได้อย่างมีประสิทธิภาพ (ดังที่อธิบายไว้ด้านบน)

นอกจากนี้ยังมีปัญหาของ OOM ที่จะเอาชนะปัญหานี้เนื่องจากเราไม่มีทรัพยากรเพียงพอที่จะนำ mongodb ออกมาเราจึงลดoom_score_adjเพื่อป้องกัน OOM จากการฆ่ากระบวนการที่สำคัญในขณะนั้น (หมายความว่าเราบอกOOMว่าจะไม่ฆ่าเรา กระบวนการที่ต้องการ )


เรามีปัญหาที่คล้ายกัน MongoDB กิน RAM ต่อไปเรื่อย ๆ สัดส่วนใกล้เคียงกัน เป็นoom_score_adj วิธีการแก้ปัญหาสิ่งที่ดีที่สุดให้คุณจัดการที่จะเกิดขึ้นด้วย?
Hartator

@Hartator เราลด cacheSize ของ wiredtiger ให้มากขึ้นพยายามจัดการดัชนีของเราและนโยบายการจัดทำดัชนีจากนั้นในที่สุดก็ลด oom_score_adj สำหรับสิ่งที่เราดูแล
SpiXel

4

ฉันไม่คิดว่าคุณมีปัญหากับ MongoDB อย่างที่ jstell บอกคุณ MongoDB กับ WiredTiger จะใช้หน่วยความจำที่มีอยู่ 50% ดังนั้นถ้าคุณเพิ่ม RAM ของเซิร์ฟเวอร์มันจะใช้หน่วยความจำมากขึ้น

เหตุใดขนาดของดัชนี DB + มากกว่าขนาดที่คุณใช้โปรดจำไว้ว่า WiredTiger บีบอัดฐานข้อมูลบนดิสก์และใช้สแนปชอตบันทึกเพื่อบันทึกการเปลี่ยนแปลงเอกสาร ขนาดที่แท้จริงของ WiredTiger คือขนาดที่ใช้แสดง dbs * compression_ration + ขนาดของบันทึกสแน็ปช็อต ดังนั้นแทบจะเป็นไปไม่ได้เลยที่จะรู้ขนาดที่แน่นอน

เก็บไว้ในใจว่าเครื่องมือชอบtop, ps, htopไม่ได้แสดงหน่วยความจำที่ใช้จริงๆโดยการประยุกต์ใช้ refere คำถาม SOW นี้สำหรับรายละเอียด: https://stackoverflow.com/questions/131303/how-to-measure-actual-memory -usage ของใช้แอพลิเคชันหรือกระบวนการ

ตอนนี้กลับไปที่ปัญหาของคุณ คุณมีเครื่องมืออื่น ๆ ที่ทำงานบนโฮสต์เดียวกันและ OOM ฆ่าพวกเขา ฉันไม่คุ้นเคยกับ Linux OOM แต่คุณแน่ใจหรือว่าจะฆ่าพวกนั้นเพราะ MongoDB หรือ .. เพียงเพราะพวกเขา (อาจฆ่า Postgres เพราะ Postgres ใช้หน่วยความจำมากเกินไป)

อย่างไรก็ตามวิธีปฏิบัติที่ดีที่สุดถ้าคุณมีฐานข้อมูล Mongo ขนาดใหญ่อย่าติดตั้งไว้ในโฮสต์ที่แชร์กับฐานข้อมูลอื่นหรือคุณจะมีปัญหามากในกรณีที่มีปัญหาเหมือนที่คุณอธิบายไว้ที่นี่ ใครเป็นผู้ทำให้เกิดปัญหากับโฮสต์


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ซึ่งค่อนข้างใหญ่ - หนึ่งรายการต่อเอกสาร - และเราตัดสินใจว่าเราจะอยู่ได้โดยปราศจากมัน)


ดัชนีมีต้นทุนหน่วยความจำขนาดใหญ่หรือไม่
Mathias Lykkegaard Lorenzen

@MathiasLykkegaardLorenzen ขึ้นอยู่กับจำนวนของค่าที่ไม่ซ้ำกันสำหรับฟิลด์ที่คุณจัดทำดัชนีซึ่งสัมพันธ์กับ RAM ของเซิร์ฟเวอร์ของคุณ ในกรณีของเราcreateTimeดัชนีนั้นมีปัญหาเพราะมันไม่เหมือนกันสำหรับเอกสารทุกฉบับและการรวบรวมนั้นมีขนาดใหญ่มาก การทำดัชนีเขตข้อมูลอื่นก็โอเคเนื่องจากมีค่าที่ไม่ซ้ำกันน้อยกว่า (ค่าที่ทำคลัสเตอร์)
joeytwiddle
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.