MongoDB chiếm nhiều RAM ?


A. Giới thiệu :
MongoDB là một trong những NoSQL(Not oly SQL) database được biết đến nhiều hiện nay , đặc trưng với cách lưu trữ dạng binary Json (BSON)cũng như khả năng truy vấn uyển chuyển (các NoSQL khác thường giới hạn điều này ) . Shell script tương tác bằng javascript . Do đó nó hay đi chung với Node.js :)
Tuy nhiên , có một vấn đề là mongoDb sử dụng nhiều dung lượng RAM (do cơ chế caching của nó). Giải pháp là phải tăng dung lượng RAM cho server đó , cũng như là monitoring cẩn thận để không xảy ra tình trạng này . Nhưng còn giải pháp nào khác nữa không ?
Đầu tiên cần tìm hiểu các nguyên nhân MongoDB chiếm nhiều RAM như vậy , từ đó mới có cách giải quyết triệt để . Dưới đây là một số nguyên nhân mà tôi đã tìm hiểu được .
B. Nguyên nhân :
1. Index :
 MongoDb có tốc độ đọc (read) nhanh , nếu ta biết cách tạo index hiệu quả . MongoDB dùng B-tree index (nhanh hơn table scans). Tuy nhiên index này lại nằm trên RAM . Khi bạn dùng câu lệnh "remove" để xóa các document trong một collection bất kỳ , thì mongoDB không xóa các dữ liệu liên quan đến index của các document đó :( . Dữ liệu xóa đi của các collection cũng không được giải phóng trở về cho hệ điều hành. Do đó ta phải chạy "repair" (mongod, tắt replicaSet) thì mongoDb mới tự xây dựng lại các index mới .
2. Working set :
Ý tưởng của working set là nó sẽ chứa những dữ liệu cần thiết của mongoDb để tại 1 thời điểm , ta có thể truy cập lấy những dữ liệu cần thiết này . Tuy nhiên , chúng ta đang ở trường hợp giả định rằng tất cả dữ liệu trong database sẽ được cậo nhật ở cùng một thời điểm , do đó tất cả dữ liệu trong mongoDb sẽ được caching. (Thật )
RAM sẽ chứa các active document và index đã sử dụng . Khi RAM bị quá tải , mongoDB sẽ tự động xóa bớt các dữ liệu này , nhưng theo kinh nghiệm thì performance lúc này cực kỳ thấp , có khi là server chạy mongoDb bị đơ luôn đấy chứ . 
Bạn sẽ đặt câu hỏi , là sao MongoDB giống caching thế nhỉ ? Ừ thì nó cũng là caching đấy .
Cơ chế : page fault
Muốn xem các thống kê trên working set : db.foo.stats()
3. Connection overhead :
4. Storage engine:
Được gọi là MongoMemMapped_RecStore . Nó sử dụng memory-mapped file cho tất cả các thao tác I/O (đọc cơ chế Memory-mapped file) . Do đó bộ quản lý bộ nhớ ảo (virtual memory manager) của hệ điều hành chịu trách nhiệm caching . Điều này dẫn tới những hệ quả sau :
  • Không có sự phân tách giữ file system cache và database cache , chúng là một .
  • MongoDb có thể sử dụng tất cả free memory trên server dành để cache mà không cần phải cấu hình kích thước cache (muốn cấu hình lắm cũng không được ).
  • Kích thước virtual memory và RSS (Resident Set Size) sẽ rất lớn dành cho mongod. Lúc bắt đầu sẽ như thế . Virtual memory space sẽ lớn hơn kích thước của các datafile open và mapped . Resident size sẽ thay đổi tùy thuộc vào lượng memory không được sử dụng bởi các process khác trên cùng 1 máy (vẫn chưa hiểu Resident size)
  • Hành vi caching (sử dụng luật LRU và lazy page write) được điều khiển bởi hệ điều hành . Chất lượng của các hiện thực Virtual Memory Manager (VMM) thay đổi theo hệ điều hành .
  • Đến 10/2010 , một storage engine thay thế (CachedBasicRecStore) , không sử dụng memory-mapped file , đang được phát triển . Engine này có page cache của riêng nó ??? (mình cũng chưa hiểu nhưng nói chung là chưa sử dụng cơ chế này) Với loại này , database sẽ có quyền điều khiển hơn chính xác số lần đọc và ghi , và cache theo luật LRU.
  • Nói chung là memory-mapped Store vẫn làm việc khá tốt . Store thay thế kể trên sẽ hữu ích hơn trong trường hợp VMM của hệ điều hành không tốt lắm.
C. Giải pháp :
- Câu hỏi đặt ra là có thể có 1 tham số để cấu hình cho mongod nhằm giới hạn dung lượng RAM mà nó sử dụng được không ? Đang tiếc là theo như tôi tìm hiểu thì không được ? Theo như thread này , thì nguyên nhân thuộc về cơ chế Memory-mapped file , thì vấn đề này do hệ điều hành quản lý :( . Nếu có thời gian thì nên đọc kỹ phần này để thấy rõ cơ chế memory-mapped file có những điểm mạnh và yếu nào về hiệu năng hệ thống hơn so với việc sử dụng phương pháp red/write I/O truyền thống . Có một cách là bạn sử dụng ảo hóa , chạy máy ảo thì khỏi lo gì hết .
- Để làm cho MongoDb nhanh hơn , chúng ta phải cung cấp đủ RAM : working set size + index size= RAM size .
Chú ý là khi chúng ta remove/drop dữ liệu, collection mongo thì nó không thực sự giải phóng không gian đĩa đã bị chiếm bởi các dữ liệu này (tức là kích thước của các data file không hề giảm), chỉ khi nào ta dùng lệnh repair hoặc là drop cả database thì mới có thể giải phóng được vùng dữ liệu này .
- Monitoring : ghi log lại serverStatus , hoặc tìm kiếm một công cụ monitoring MongoDb thích hợp ....
Ta có thể sử dụng một số tiện ích sẵn có của hệ thống :
Ví dụ :
  • Đầu tiên cần biết mongod đang chạy có cấu hình run-time như thế nào > use admin , >db.runCommand("getCmdLineOpts")
  • dùng htop : để xem những tiến trình mongod đang chiếm dụng RAM như thế nào
  • dùng free -tm : kiểm tra xem cahe memory , đó cũng là lượng memory mà mongoDb đang chiếm giữ .
  • dùng vmstat : thông tin về virtual memory . Do mongoDb sử dụng cơ chế memory-mapped file , nên có thể xem những thông tin này .
  • Dùng mongostat (tool có sẵn của mongoDb).
  • Nếu muốn theo dõi mongod đang ở port nào(chạy bằng quyền root) : netstat -tulpena | grep mongo
  • Sử dụng db.serverStatus() : có nhiều thông tin , nhưng ta chú ý theo dõi số lượng connection của mongoDb .Mặc định là 819 connections (khoảng 80% số lượng open-file qui định trong /etc/security/limit.conf
  • Kiểm tra : ulimit -a | egrep virtual\|open . Nếu virtual memory không được cấu hình unlimited mà là một con số nhỏ thì dễ gây ra tình trạng Out Of Memory Error khi mà virtual memory cấu hình không đủ cho MongoDb
  • Thông tin về kích thước collection :Object.bsonsize(db.whatever.findOne())
  • > db.test.save({"name": "blahh"})
    > Object.bsonsize(db.test.findOne({"name":"blahh"}))
    38
  • Thông tin về kích thước collection cũng như index của nó ở đây . Đoạn script để xem tất cả thống kê của db và collections .
-Sử dụng replica Set để "scaling" read
- Sử dụng sharding để "scaling" write
- Sử dụng capped collection cho trường hợp những dữ liệu cũ không cần dùng nữa .

D. Tài liệu tham khảo :
1. http://www.markus-gattol.name/ws/mongodb.html#sec3 . Tài liệu này có liệt kê chi tiết đầy đủ các ý tưởng của mongoDb cũng như là link các tài liệu tương ứng (giống như kiểu index lại nhưng có thêm những mô tả cho dễ hiểu).
2. http://www.mongodb.org/display/DOCS/Excessive+Disk+Space