너무 많은 메모리를 사용하는 MongoDB


28

우리는 몇 주 동안 MongoDB를 사용 해 왔으며, 우리가 본 전반적인 추세는 mongodb가 너무 많은 메모리를 사용한다는 것입니다 (데이터 세트 + 인덱스의 전체 크기보다 훨씬 많은 양).

이미 통해 읽은 이 질문이 질문에 , 그러나 아무도 내가, 그들이 실제로 이미 문서에 설명 된 무엇을 설명하고 직면했던 문제를 해결하기 위해 보이지 않는다.

다음은 htopshow dbs 명령 의 결과입니다 .

여기에 이미지 설명을 입력하십시오

dbs를 보여라

mongodb는 메모리 매핑 된 IO를 사용하므로 기본적으로 OS는 메모리의 캐싱을 처리하며 mongodb 는 이론적으로 다른 프로세스가 여유 메모리를 요청할 때 캐시 된 메모리를 제거해야하지만 우리가 본 것에서는 그렇지 않습니다.

OOM은 postgres, redis 등과 같은 다른 중요한 프로세스를 죽이기 시작합니다 (이 문제를 극복하기 위해 RAM이 183GB로 증가했지만 현재는 작동하지만 꽤 비쌉니다. mongo는 ~ 87GB의 램을 사용합니다. 전체 데이터 세트 크기의 거의 4 배)

그래서,

  1. 이 메모리 사용량이 실제로 예상되고 정상입니까? (문서에 따라 WiredTiger는 캐시에 최대 60 %의 RAM을 사용하지만 데이터 세트 크기를 고려할 때 86GB의 RAM을 사용할 수있는 충분한 데이터가 있습니까?)
  2. 메모리 사용량이 예상 되더라도 다른 프로세스가 더 많은 메모리를 요청하기 시작할 때 mongo가 할당 된 메모리를 포기하지 않는 이유는 무엇입니까? RAM을 늘리고 시스템을 완전히 불안정하게 만들기 전에 mongodb 자체를 포함하여 Linux oom에 의해 다양한 다른 실행 프로세스가 지속적으로 중단되었습니다.

감사 !


4
mongodb.com/presentations/… 와 같은 WiredTiger의 내부에 대한 프레젠테이션 중 일부는 약간의 빛을 비출 수 있습니다. 실제 RAM의 50 %를 기본으로 사용하는 것은 전용 MongoDB 호스트에서 필요한 것이 무엇인지 추측 한 것이므로 많은 사람들이이를 변경해야합니다. FWIW, 나는 cacheSizeGB를 설정하는 것이 "제한적"몽고라고 생각하지 않습니다. 옵션은 배포를 제어 할 수 있습니다. 캐시에 필요한 메모리 mongo의 양을 결정하려면 예상되는 서버로드에서 서버 캐시 통계를 모니터해야합니다.

답변:


23

자, loicmathieu와 jstell의 힌트를 따르고 조금 파헤친 후에는 WiredTiger 스토리지 엔진을 사용하여 MongoDB에 대해 알게 된 것입니다. 누군가 같은 질문에 직면하면 여기에 넣겠습니다.

내가 언급 한 메모리 사용 스레드는 모두 2012-2014, 모든 WiredTiger에 속하며 별도의 캐시가 없거나 압축을 지원하지 않는 원래 MMAPV1 스토리지 엔진의 동작을 설명합니다.

WiredTiger 캐시 설정 은 WiredTiger 스토리지 엔진이 직접 사용하는 메모리 크기 만 제어합니다 (mongod가 사용하는 총 메모리는 아님). 다음과 같은 많은 다른 것들이 MongoDB / WiredTiger 구성에서 메모리를 차지하고 있습니다.

  • WiredTiger는 디스크 저장소를 압축하지만 메모리의 데이터는 압축되지 않습니다.

  • WiredTiger는 기본적으로 각 커밋마다 데이터를 동기화하지 않으므로 로그 파일도 RAM에 저장되어 메모리에 영향을줍니다. 또한 I / O를 효율적으로 사용하기 위해 WiredTiger는 I / O 요청 (캐시 누락)을 함께 청크하며 일부 RAM (사실 더러운 페이지 (변경 / 업데이트 된 페이지)에는 업데이트 목록이 있음) Concurrent SkipList에 저장된 ).

  • 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의 메모리를 사용하는 것으로 보입니다.

이 모든 것을 고려할 때, 메모리 사용이 이제 꽤 기대되는 것 같습니다. IdO 작업을 매우 효율적으로 처리하기 때문에 WiredTiger 캐시 크기를 제한하는 것이 좋습니다.

또한 OOM의 문제는 우리가 MongoDB를 꺼내 충분한 자원을 가지고 있지 않았기 때문에,이 문제를 극복하기 위해, 남아, 우리는 낮아 oom_score_adj 우리에게 시간이 의미 (있는 중요한 프로세스를 죽이는 OOM을 방지하기을 죽일하지 OOM 우리 원하는 프로세스 ).


비슷한 문제가 있습니다. MongoDB는 RAM을 계속 먹습니다. 비슷한 비율. 이었다 oom_score_adj 솔루션을 마련하기 위해 당신이 관리하는 가장 좋은 것은?
Hartator

@Hartator 글쎄 우리는 wiredtiger의 cacheSize를 줄이고 인덱스와 인덱싱 정책을 관리하는 데 더 많은 노력을 기울인 다음 마지막으로 관심있는 것들에 대해 oom_score_adj를 줄였습니다.
SpiXel

4

jstell이 WiredTiger를 사용하여 MongoDB가 사용 가능한 메모리의 50 %를 사용하므로 서버의 RAM을 늘리면 더 많은 메모리가 필요하다고 MongoDB에 문제가 있다고 생각하지 않습니다.

DB + 인덱스의 크기보다 큰 이유는 WiredTiger가 디스크의 데이터베이스를 압축하고 스냅 샷 로그를 사용하여 문서 변경 사항을 기록한다는 점을 명심하십시오. 따라서 WiredTiger의 실제 크기는 show dbs * compression_ration + 스냅 샷 로그 크기를 사용하는 크기입니다. 따라서 정확한 예상 크기를 아는 것은 거의 불가능합니다.

도구를 좋아하는 마음도 유지 top, ps, htop, 정말 응용 프로그램에서 사용하는 메모리를 표시 자세한 내용은이 SOW의 질문에 참조하지만하지 않았다 : https://stackoverflow.com/questions/131303/how-to-measure-actual-memory 응용 프로그램 또는 프로세스 사용

이제 문제로 돌아가십시오. 동일한 호스트에서 실행되는 다른 도구가 있으며 OOM이 종료합니다. 나는 Linux OOM에 익숙하지 않지만 MongoDB 또는 .. 때문에 (Postgres가 너무 많은 메모리를 사용했기 때문에 Postgres를 죽일 수 있기 때문에) 죽일 것이라고 확신합니다.

어쨌든, 큰 Mongo 데이터베이스가있는 경우 가장 좋은 방법은 다른 데이터베이스와 공유되는 호스트에 설치하지 마십시오. 그렇지 않으면 여기에 설명 된 것과 같은 문제가있는 경우 알아야 할 많은 어려움이 있습니다. 실제로 호스트에서 문제를 일으키는 사람.


4

문서

MongoDB에 대한 기본 메모리 문제메모리 사용량 확인에 대한 간단한 설명 을 읽을 수 있습니다. .

메모리 사용량 개요

명령 db.serverStatus()( docs )은 특히 메모리 사용에 대한 개요를 제공 할 수 있습니다.

> 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.