MongoDB sử dụng quá nhiều bộ nhớ


28

Chúng tôi đã sử dụng MongoDB trong vài tuần nay, xu hướng chung mà chúng tôi thấy là mongodb đang sử dụng quá nhiều bộ nhớ (nhiều hơn toàn bộ kích thước của tập dữ liệu + chỉ mục của nó).

Tôi đã đọc qua câu hỏi nàycâu hỏi này , nhưng dường như không ai giải quyết được vấn đề mà tôi đang gặp phải, họ thực sự đang giải thích những gì đã được giải thích trong tài liệu.

Sau đây là kết quả của htophiển thị các lệnh dbs .

nhập mô tả hình ảnh ở đây

hiển thị dbs

Tôi biết rằng mongodb sử dụng IO được ánh xạ bộ nhớ, vì vậy về cơ bản, HĐH xử lý các bộ nhớ đệm trong bộ nhớ và mongodb về lý thuyết nên loại bỏ bộ nhớ đệm của nó khi một tiến trình khác yêu cầu bộ nhớ trống , nhưng từ những gì chúng ta đã thấy, thì không.

OOM bắt đầu giết chết các quá trình quan trọng khác, ví dụ như postgres, redis, v.v. (Có thể thấy, để khắc phục vấn đề này, chúng tôi đã tăng RAM lên tới 183GB, hiện hoạt động nhưng khá tốn kém. gần gấp 4 lần kích thước của toàn bộ tập dữ liệu của nó)

Vì thế,

  1. Đây có phải là sử dụng nhiều bộ nhớ thực sự mong đợi và bình thường? (Theo tài liệu, WiredTiger sử dụng tối đa ~ 60% RAM cho bộ nhớ cache, nhưng xem xét kích thước tập dữ liệu, liệu nó có đủ dữ liệu để có thể lấy 86GB RAM không?)
  2. Ngay cả khi việc sử dụng bộ nhớ được mong đợi, tại sao mongo sẽ không bỏ bộ nhớ được phân bổ trong trường hợp một quá trình khác bắt đầu yêu cầu thêm bộ nhớ? Nhiều quá trình chạy khác đã liên tục bị giết bởi linux oom, bao gồm cả mongodb, trước khi chúng tôi tăng RAM và nó làm cho hệ thống hoàn toàn không ổn định.

Cảm ơn !


4
Có lẽ một số bài thuyết trình về nội bộ của WiredTiger, chẳng hạn như mongodb.com/presentations/ , có thể làm sáng tỏ. Tôi hy vọng việc sử dụng mặc định 50% RAM vật lý chỉ là dự đoán về những gì có thể được yêu cầu trên máy chủ MongoDB chuyên dụng và nhiều người sẽ cần phải thay đổi nó. FWIW, tôi không tin rằng việc đặt cacheSizeGB là "giới hạn" mongo - tùy chọn có sẵn để bạn có quyền kiểm soát việc triển khai. Việc xác định dung lượng bộ nhớ mongo "cần" cho bộ nhớ cache sẽ yêu cầu bạn theo dõi số liệu thống kê bộ đệm của máy chủ theo tải máy chủ dự kiến.

Câu trả lời:


23

Được rồi, vì vậy sau khi theo các manh mối được đưa ra bởi loicmathieu và jstell, và đào nó lên một chút, đây là những điều tôi tìm thấy về MongoDB bằng cách sử dụng công cụ lưu trữ WiredTiger. Tôi sẽ đặt nó ở đây nếu bất cứ ai gặp phải những câu hỏi tương tự.

Các luồng sử dụng bộ nhớ mà tôi đã đề cập, tất cả thuộc về 2012-2014, tất cả WiredTiger trước ngày và đang mô tả hành vi của công cụ lưu trữ MMAPV1 ban đầu không có bộ đệm hoặc hỗ trợ nén riêng biệt.

Cài đặt bộ đệm WiredTiger chỉ kiểm soát kích thước bộ nhớ được sử dụng trực tiếp bởi công cụ lưu trữ WiredTiger (không phải tổng bộ nhớ được sử dụng bởi mongod). Nhiều thứ khác có khả năng chiếm bộ nhớ trong cấu hình MongoDB / WiredTiger, chẳng hạn như sau:

  • WiredTiger nén lưu trữ đĩa, nhưng dữ liệu trong bộ nhớ không bị nén.

  • WiredTiger theo mặc định không đồng bộ hóa dữ liệu trên mỗi lần xác nhận , do đó, các tệp nhật ký cũng nằm trong RAM, nó sẽ gây ra bộ nhớ. Người ta cũng đề cập rằng để sử dụng I / O một cách hiệu quả, các yêu cầu I / O của WiredTiger kết hợp với nhau, điều đó dường như cũng mất một số RAM (Trên thực tế, các trang bẩn (các trang đã thay đổi / cập nhật) có một danh sách các bản cập nhật trên chúng được lưu trữ trong SkipList đồng thời ).

  • WiredTiger giữ nhiều phiên bản của các bản ghi trong bộ đệm của nó (Điều khiển đồng thời nhiều phiên bản, đọc các hoạt động truy cập phiên bản đã cam kết cuối cùng trước khi hoạt động).

  • WiredTiger Giữ tổng kiểm tra dữ liệu trong bộ đệm.

  • MongoDB tự tiêu thụ bộ nhớ để xử lý các kết nối mở, quy tụ, mã serverside và vv .

Xem xét những sự thật này, dựa vào show dbs;là không chính xác về mặt kỹ thuật, vì nó chỉ hiển thị kích thước nén của các bộ dữ liệu.

Các lệnh sau có thể được sử dụng để có được kích thước tập dữ liệu đầy đủ.

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

Kết quả này là như sau:

{
    "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
}

Vì vậy, có vẻ như kích thước tập dữ liệu thực tế + các chỉ mục của nó đang chiếm khoảng 68 GB bộ nhớ đó.

Xem xét tất cả những điều này, tôi đoán việc sử dụng bộ nhớ hiện đang được mong đợi, phần tốt là hoàn toàn ổn khi giới hạn kích thước bộ đệm WiredTiger, vì nó xử lý các hoạt động I / O khá hiệu quả (như được mô tả ở trên).

Vẫn còn vấn đề của OOM, để khắc phục vấn đề này, vì chúng tôi không có đủ nguồn lực để loại bỏ mongodb, chúng tôi đã hạ oom_score_adj để ngăn OOM giết các quy trình quan trọng trong thời gian này (Có nghĩa là chúng tôi đã nói với OOM không giết chúng tôi quy trình mong muốn ).


Chúng tôi đã có một vấn đề tương tự. MongoDB tiếp tục ăn RAM. Tỷ lệ tương tự. oom_score_adj Giải pháp có phải là điều tốt nhất bạn quản lý để đưa ra?
Người đánh bóng

@Hartator Vâng, chúng tôi đã giảm cacheSize của Wiredtiger, nỗ lực nhiều hơn trong việc quản lý các chỉ mục và chính sách lập chỉ mục của chúng tôi, và cuối cùng, đã giảm oom_score_adj cho những điều chúng tôi quan tâm, đó là điều tôi đoán mọi cách có thể được thực hiện.
SpiXel

4

Tôi không nghĩ rằng bạn có vấn đề ở đây với MongoDB, vì jstell đã nói với bạn MongoDB với WiredTiger sẽ sử dụng 50% bộ nhớ khả dụng, vì vậy nếu bạn tăng RAM của máy chủ thì sẽ mất thêm bộ nhớ.

Vì sao nó lớn hơn kích thước của các chỉ mục DB +, hãy nhớ rằng WiredTiger nén cơ sở dữ liệu trên đĩa và cũng sử dụng nhật ký chụp nhanh để ghi lại các thay đổi tài liệu. Vì vậy, kích thước thực của WiredTiger là kích thước sử dụng show dbs * compression_ration + kích thước của các bản ghi ảnh chụp nhanh. Vì vậy, gần như không thể biết chính xác kích thước dự kiến.

Giữ cũng nhớ rằng các công cụ thích top, ps, htopkhông hiển thị bộ nhớ thực sự được sử dụng bởi các ứng dụng, refere này câu hỏi SOW để biết chi tiết: https://stackoverflow.com/questions/131303/how-to-measure-actual-memory -usage-of-an-application-or-process

Bây giờ, trở lại vấn đề của bạn. Bạn có các công cụ khác chạy trên cùng một máy chủ và OOM sẽ giết chúng. Tôi không quen thuộc với Linux OOM nhưng bạn có chắc chắn rằng nó giết chết những người đó vì MongoDB hoặc .. chỉ vì chúng (có thể nó giết chết Postgres vì ​​Postgres chiếm quá nhiều bộ nhớ).

Dù sao, như một cách thực hành tốt nhất nếu bạn có cơ sở dữ liệu Mongo lớn, đừng cài đặt nó trong một máy chủ được chia sẻ với các cơ sở dữ liệu khác hoặc bạn sẽ gặp rất nhiều khó khăn, trong trường hợp có một vấn đề như bạn mô tả ở đây, để biết người thực sự gây ra vấn đề trên máy chủ.


4

Tài liệu

Bạn có thể muốn đọc các mối quan tâm bộ nhớ cơ bản cho MongoDB và cả cuộc thảo luận ngắn gọn này về việc kiểm tra việc sử dụng bộ nhớ .

Tổng quan về sử dụng bộ nhớ

Lệnh db.serverStatus()( docs ) có thể cung cấp tổng quan về việc sử dụng bộ nhớ, cụ thể:

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

Chỉ số của bạn lớn như thế nào?

db.stats() có thể hiển thị tổng kích thước của tất cả các chỉ mục, nhưng chúng tôi cũng có thể nhận thông tin chi tiết cho một bộ sưu tập bằng cách sử dụng db.myCollection.stats()

Ví dụ: lệnh này sẽ so sánh kích thước của các chỉ mục cho mỗi bộ sưu tập :

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

Bây giờ chúng ta có thể xem xét các chi tiết cho bộ sưu tập đồ sộ đó, để xem chỉ số nào của nó là tốn kém nhất:

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

Điều này có thể cho chúng ta một ý tưởng tốt hơn về nơi có thể tiết kiệm.

(Trong trường hợp này, chúng tôi đã có một chỉ số createTimekhá lớn - một mục nhập cho mỗi tài liệu - và chúng tôi quyết định chúng tôi có thể sống mà không cần nó.)


Các chỉ số có chi phí bộ nhớ lớn?
Mathias Lykkegaard Lorenzen

@MathiasLykkegaardLorenzen Nó phụ thuộc vào số lượng giá trị duy nhất cho trường bạn đã lập chỉ mục, liên quan đến RAM máy chủ của bạn. Trong trường hợp của chúng tôi, createTimechỉ mục có vấn đề vì nó là duy nhất cho mỗi tài liệu duy nhất và bộ sưu tập đó là rất lớn. Lập chỉ mục cho các trường khác là ổn, vì có ít giá trị duy nhất hơn (các giá trị được nhóm lại).
joeytwiddle
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.