MongoDB використовує занадто багато пам'яті


28

Ми використовуємо MongoDB вже декілька тижнів, загальна тенденція, яку ми бачили, полягає в тому, що mongodb використовує занадто багато пам'яті (набагато більше, ніж весь розмір його набору даних + індекси).

Я вже читав це питання і це питання , але, здається, ніхто не вирішує питання, з яким я стикався, вони фактично пояснюють те, що вже пояснено в документації.

Нижче наведені результати htop та показати dbs- команди.

введіть тут опис зображення

показати dbs

Я знаю, що mongodb використовує IO, відображений на пам’яті, тому в основному ОС обробляє кешування речей у пам'яті, і mongodb теоретично повинен відпускати кешовану пам’ять, коли інший процес вимагає вільної пам’яті , але з того, що ми бачили, він цього не робить.

OOM починає вбивати інші важливі процеси, наприклад, postgres, redis тощо. (Як видно, для подолання цієї проблеми ми збільшили оперативну пам’ять до 183 Гб, що зараз працює, але досить дорого. Монго використовує ~ 87 ГБ оперативної пам’яті, майже 4X розміру всього його набору даних)

Так,

  1. Чи справді очікуване та нормальне таке використання пам'яті? (Відповідно до документації, WiredTiger використовує не більше ~ 60% оперативної пам’яті для свого кешу, але, враховуючи розмір набору даних, чи є у нього навіть достатньо даних, щоб можна було взяти 86 ГБ оперативної пам’яті?)
  2. Навіть якщо очікується використання пам’яті, чому монго не відпустить виділену пам’ять у випадку, якщо інший процес почне запитувати більше пам’яті? Різні інші запущені процеси постійно вбивали linux oom, включаючи саму mongodb, перш ніж ми збільшили оперативну пам’ять, і це зробило систему абсолютно нестабільною.

Спасибі !


4
Можливо, деякі презентації про внутрішні програми WiredTiger, такі як mongodb.com/presentations/… , можуть пролити трохи світла. Я очікую, що використання за замовчуванням 50% фізичної оперативної пам’яті - це лише здогадка про те, що, ймовірно, потрібно на спеціальному хості MongoDB, і багатьом потрібно буде це змінити. FWIW, я не вірю, що встановлення cacheSizeGB "обмежує" монго - варіант є, щоб ви мали контроль над розгортанням. Визначення того, скільки монго пам'яті "потрібно" для кешу, вимагатиме від вас моніторингу статистики кеш-сервера за очікуваного навантаження сервера.

Відповіді:


23

Гаразд, після того, як дотримуватися підказок, наданих loicmathieu та jstell, і трохи перекопавши їх, це те, що я дізнався про MongoDB за допомогою двигуна зберігання WiredTiger. Я викладаю це, якщо хтось стикався з тими ж питаннями.

Про те, що я згадував, використовувались потоки використання пам'яті, які належать до 2012-2014 рр., Усі до дати WiredTiger і описують поведінку оригінального механізму зберігання даних MMAPV1, який не має окремого кешу або підтримки для стиснення.

Налаштування кеш-пам'яті WiredTiger керує лише розміром пам'яті, безпосередньо використовуваною системою зберігання WiredTiger (не загальною пам'яттю, що використовується mongod). Багато інших речей потенційно забирають пам'ять у конфігурації MongoDB / WiredTiger, такі як:

  • WiredTiger стискає дискове сховище, але дані в пам'яті не стискаються.

  • WiredTiger за замовчуванням не синхронізує дані про кожну фіксацію , тому файли журналу також знаходяться в оперативній пам'яті, яка приймає своє значення на пам'ять. Також згадується, що для ефективного використання вводу / виводу WiredTiger з’єднує запити вводу-виводу (кеш пропускає) разом, що також, здається, займає деяку оперативну пам’ять (Насправді брудні сторінки (сторінки, які були змінені / оновлені) мають список оновлень на них зберігається в паралельному пропуску SkipList ).

  • WiredTiger зберігає декілька версій записів у своєму кеші (Multi Version Concurrency Control, операції зчитування доступу до останньої скоєної версії до їх роботи).

  • 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
}

Тож здається, що фактичний розмір набору даних + його індекси займають близько 68 ГБ цієї пам'яті.

Враховуючи все це, я думаю, що використання пам'яті зараз очікується, і хороша частина - це цілком нормально обмежити розмір кешу WiredTiger, оскільки він обробляє операції вводу-виводу досить ефективно (як описано вище).

Також залишається проблема ООМ, щоб подолати це питання, оскільки у нас не було достатньо ресурсів, щоб вивести mongodb, ми знизили oom_score_adj, щоб не допустити, щоб OOM вбивала важливі процеси на даний момент (Це означає, що ми сказали OOM не вбивати наших бажані процеси ).


У нас схожа проблема. MongoDB продовжує їсти оперативну пам'ять. Подібні пропорції. Чи було oom_score_adj рішення найкращим, що вам вдається придумати?
Хартатор

@Hartator Добре, що ми зменшили cacheSize wiredtiger, доклали більше зусиль для управління нашими індексами та політикою індексації, а потім, нарешті, зменшили oom_score_adj для речей, про які ми піклувались, це, мабуть, все, що можна зробити в будь-якому випадку.
SpiXel

4

Я не думаю, що у вас тут проблеми з MongoDB, як jstell сказав вам, що MongoDB з WiredTiger буде використовувати 50% доступної пам’яті, тож якщо ви збільшите оперативну пам’ять вашого сервера, це займе більше пам’яті.

Оскільки це більше, ніж розмір індексів DB +, майте на увазі, що WiredTiger стискає базу даних на диску, а також використовує журнали знімків для запису змін в документі. Отже, реальний розмір WiredTiger - це розмір, використовуючи show dbs * compression_ration + розмір журналів знімків. Тож точно неможливо дізнатися точний очікуваний розмір.

Майте також на увазі , що такі інструменти , як top, ps, htopне проявляла пам'ять дійсно , використовуваний додатком, refere до цього SOW питання для деталей: https://stackoverflow.com/questions/131303/how-to-measure-actual-memory -використання заявки -процесу

Тепер повернемося до вашої проблеми. У вас є інші інструменти, що працюють на тому ж хості, і 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 Це залежить від кількості унікальних значень для поля, яке ви індексували, відносно оперативної пам’яті вашого сервера. У нашому випадку createTimeіндекс був проблематичним, оскільки він був унікальним для кожного окремого документа, і ця колекція була величезною. Індексування інших полів було нормальним, оскільки було менше унікальних значень (значення були кластеризовані).
joeytwiddle
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.