install:html
一、ubuntu用deb安裝。mysql
二、下載壓縮文件,綠色的,不用安裝。 推薦此方法。git
配置dbpath:github
一、用deb安裝的,會在 /etc 目錄下 建立mongodb.conf (若沒自動建立,能夠本身建立),這是默認的配置文件,能夠配置默認的 dbpath 路徑等。算法
二、如果用的解壓版,則即便在 /etc 目錄建立 mongodb.conf 文件也無效,只有在命令行用 --dbpath /Volumes/Data/mongodb
指定。或者用 -f /path/to/mongodb.conf 指定配置文件,配置文件裏設置 dbpath
sql
運行mongodb的方式:mongodb
./bin/mongod -f mongodb.confshell
如下是我本身的 mongodb.conf 文件:數據庫
# https://docs.mongodb.com/v3.2/reference/configuration-options/#security.authorization storage: # 注意dbPath的大小寫 dbPath: "/home/hzh/hzh/soft/mongodb_dbpath" security: authorization: "enabled"
退出mongodb daemon server的方式:json
$ ./mongo
> use admin
> db.shutdownServer()
或者:
$ ./mongod -f ../mongodb.conf --shutdown
或者:
$ mongo --eval "db.getSiblingDB('admin').shutdownServer()"
或者:
kill pid_number
用戶主目錄 ~ 下的 ~/.mongorc.js 配置文件(如下是個人示例):
prompt = function() { var db_user = "error occured"; try { var dbname = db.getName(); var user = db.runCommand({connectionStatus : 1}).authInfo.authenticatedUsers; var user_name = ""; if (user) { user.forEach(function(element) { if (0 == user_name.length) { user_name = element.user; } else { user_name = user_name + "|" + element.user; } }); } var dbname_show = "notSelDb"; if (dbname) { dbname_show = dbname; } var user_show = "noAuth"; if (user_name.length > 0) { user_show = user_name; } db_user = dbname_show + "[" + user_show + "] > "; } catch (e) { } // 捕捉寫入錯誤並打印; 同時有可能在鏈接斷開時自動重連。 try { db.runCommand({getLastError: 1}); } catch (e) { print(e); } return db_user; }
忘記管理密碼後怎麼恢復:
If you have locked yourself out then you need to do the following:
一、Stop your MongoDB instance
二、Remove the --auth and/or --keyfile options from your MongoDB config to disable authentication
三、Start the instance without authentication
四、Edit the users as needed
五、Restart the instance with authentication enabled
若是你刪掉了 admin 數據庫:
Deleting admin db means loosing access to all the databases. how to solve? Enable localhost authentication bypass(if not enabled) and restart mongod. Now create the users again.
從上可看出,安裝完mongodb後,若進而定義了用戶,須要在 MongoDB config 文件裏指定啓動mongodb後必須認證登陸才能訪問數據庫,這才安全。 怎麼啓用認證,只須要在conf配置文件里加入:
security:
authorization: enabled
mongodb的管理工具:
一、https://github.com/Studio3T/robomongo
Robo 3T (formerly Robomongo *) is a shell-centric cross-platform MongoDB management tool. Unlike most other MongoDB admin UI tools, Robo 3T embeds the actual mongo
shell in a tabbed interface with access to a shell command line as well as GUI interaction.
二、https://github.com/mrvautin/adminMongo
adminMongo is a Web based user interface (GUI) to handle all your MongoDB connections/databases needs
mongodb 的用戶管理:
https://docs.mongodb.com/v3.0/tutorial/manage-users-and-roles/
https://docs.mongodb.com/v3.0/reference/built-in-roles/#clusterAdmin
任何database都須要一個用戶來對它進行訪問,若是沒有任何用戶對應此database,你就沒法訪問該database。而任何user都不可能無限制的取得database的權限,所以必須有一個權限系統,也就是role管理。role規定了user對數據庫的訪問權限。一個user能夠被授予多個角色,於是被賦予了對mongodb的資源訪問能力和能實施的行爲。
The admin
database includes the following roles for administering the whole system rather than just a single database.
admin 數據庫裏包含一系列的角色(如: clusterAdmin, clusterManager, clusterMonitor, hostManager),專爲管理整個系統而無論理單個數據庫。
The admin
database provides the following roles that apply to all databases in a mongod
instance and are roughly equivalent to their single-database equivalents
admin 數據庫裏包含一系列的角色(如: readAnyDatabase, readWriteAnyDatabase, userAdminAnyDatabase, dbAdminAnyDatabase),來管理mongod實例中的全部數據庫,至關於把它當成本身的數據庫來管理。
注意:在哪一個database下建立的user,則這個user就只屬於這個database,不屬於其它的任何database,在其它database裏顯示不出不屬於本身的user。
mongoDB 3.0 用戶權限系統:
MongoDB 3.0 安全權限訪問控制,在添加用戶上面3.0版本和以前的版本有很大的區別,這裏就說明下3.0的添加用戶的方法。
環境、測試:
在安裝MongoDB以後,先在conf文件裏關閉auth認證,進入查看數據庫,只有一個local庫,admin庫是不存在的(也有可能存在):
root@zhoujinyi:/usr/local/mongo4# mongo --port=27020 MongoDB shell version: 3.0.4 connecting to: 127.0.0.1:27020/test 2015-06-29T09:31:08.673-0400 I CONTROL [initandlisten] > show dbs; local 0.078GB
如今須要建立一個賬號,該帳號須要有grant權限,即:帳號管理的受權權限。注意一點,賬號是跟着數據庫走的,因此在某數據庫裏受權,必須也在該庫裏驗證(auth)(即登陸)。
> use admin switched to db admin > db.createUser( ... { ... user: "dba", ... pwd: "dba", ... roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] ... } ... ) Successfully added user: { "user" : "dba", "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] }
上面加粗的就是執行的命令:
user:用戶名
pwd:密碼
roles:指定用戶的角色,能夠用一個空數組給新用戶設定空角色;在roles字段,能夠指定內置角色和用戶定義的角色。role裏的角色能夠選:
Built-In Roles(內置角色): 1. 數據庫用戶角色:read、readWrite; 2. 數據庫管理角色:dbAdmin、dbOwner、userAdmin; 3. 集羣管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager; 4. 備份恢復角色:backup、restore; 5. 全部數據庫角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase 6. 超級用戶角色:root // 這裏還有幾個角色間接或直接提供了系統超級用戶的訪問(dbOwner 、userAdmin、userAdminAnyDatabase) 7. 內部角色:__system
具體角色:
Read:容許用戶讀取指定數據庫
readWrite:容許用戶讀寫指定數據庫
dbAdmin:容許用戶在指定數據庫中執行管理函數,如索引建立、刪除,查看統計或訪問system.profile
userAdmin:容許用戶向system.users集合寫入,能夠找指定數據庫裏建立、刪除和管理用戶
clusterAdmin:只在admin數據庫中可用,賦予用戶全部分片和複製集相關函數的管理權限。
readAnyDatabase:只在admin數據庫中可用,賦予用戶全部數據庫的讀權限
readWriteAnyDatabase:只在admin數據庫中可用,賦予用戶全部數據庫的讀寫權限
userAdminAnyDatabase:只在admin數據庫中可用,賦予用戶全部數據庫的userAdmin權限
dbAdminAnyDatabase:只在admin數據庫中可用,賦予用戶全部數據庫的dbAdmin權限。
root:只在admin數據庫中可用。超級帳號,超級權限
剛創建了 userAdminAnyDatabase 角色,用來管理用戶,能夠經過這個角色來建立、刪除用戶。驗證:須要開啓auth參數。
root@zhoujinyi:/usr/local/mongo4# mongo --port=27020 MongoDB shell version: 3.0.4 connecting to: 127.0.0.1:27020/test > show dbs; ####沒有認證,致使沒權限。 2015-06-29T10:02:16.634-0400 E QUERY Error: listDatabases failed:{ "ok" : 0, "errmsg" : "not authorized on admin to execute command { listDatabases: 1.0 }", "code" : 13 } at Error (<</span>anonymous>) at Mongo.getDBs (src/mongo/shell/mongo.js:47:15) at shellHelper.show (src/mongo/shell/utils.js:630:33) at shellHelper (src/mongo/shell/utils.js:524:36) at (shellhelp2):1:1 at src/mongo/shell/mongo.js:47 > use admin #認證,由於在admin下面添加的賬號,因此要到admin下面認證。 switched to db admin > db.auth('dba','dba') # db.logout() 是登出當前認證了的用戶 (##注意,每一個用戶都是隻屬於某個數據庫的,沒切換到哪一個數據庫,你沒法對屬於該數據庫的用戶進行登陸與登出) 1 > show dbs; admin 0.078GB local 0.078GB > use test #在test庫裏建立賬號 switched to db test > db.createUser( ... { ... user: "zjyr", ... pwd: "zjyr", ... roles: [ ... { role: "read", db: "test" } #只讀賬號 ... ] ... } ... ) Successfully added user: { "user" : "zjyr", "roles" : [ { "role" : "read", "db" : "test" } ] } > db.createUser( ... { ... user: "zjy", ... pwd: "zjy", ... roles: [ ... { role: "readWrite", db: "test" } #讀寫賬號 ... ] ... } ... ) Successfully added user: { "user" : "zjy", "roles" : [ { "role" : "readWrite", #讀寫帳號 "db" : "test" } ] } > show users; #查看當前庫下的用戶 { "_id" : "test.zjyr", "user" : "zjyr", "db" : "test", "roles" : [ { "role" : "read", "db" : "test" } ] } { "_id" : "test.zjy", "user" : "zjy", "db" : "test", "roles" : [ { "role" : "readWrite", "db" : "test" } ] }
上面建立了2個賬號,如今驗證下:驗證前提須要一個集合(collection)
> db.abc.insert({"a":1,"b":2}) #插入失敗,沒有權限,userAdminAnyDatabase 權限只是針對用戶管理的,對其餘是沒有權限的。 WriteResult({ "writeError" : { "code" : 13, "errmsg" : "not authorized on test to execute command { insert: "abc", documents: [ { _id: ObjectId('55915185d629831d887ce2cb'), a: 1.0, b: 2.0 } ], ordered: true }" } }) > bye root@zhoujinyi:/usr/local/mongo4# mongo --port=27020 MongoDB shell version: 3.0.4 connecting to: 127.0.0.1:27020/test > use test switched to db test > db.auth('zjy','zjy') #用建立的readWrite賬號進行寫入 1 > db.abc.insert({"a":1,"b":2}) WriteResult({ "nInserted" : 1 }) > db.abc.insert({"a":11,"b":22}) WriteResult({ "nInserted" : 1 }) > db.abc.insert({"a":111,"b":222}) WriteResult({ "nInserted" : 1 }) > db.abc.find() { "_id" : ObjectId("559151a1b78649ebd8316853"), "a" : 1, "b" : 2 } { "_id" : ObjectId("559151cab78649ebd8316854"), "a" : 11, "b" : 22 } { "_id" : ObjectId("559151ceb78649ebd8316855"), "a" : 111, "b" : 222 } > db.auth('zjyr','zjyr') #切換到只有read權限的賬號 1 > db.abc.insert({"a":1111,"b":2222}) #不能寫入 WriteResult({ "writeError" : { "code" : 13, "errmsg" : "not authorized on test to execute command { insert: "abc", documents: [ { _id: ObjectId('559151ebb78649ebd8316856'), a: 1111.0, b: 2222.0 } ], ordered: true }" } }) > db.abc.find() #能夠查看 { "_id" : ObjectId("559151a1b78649ebd8316853"), "a" : 1, "b" : 2 } { "_id" : ObjectId("559151cab78649ebd8316854"), "a" : 11, "b" : 22 } { "_id" : ObjectId("559151ceb78649ebd8316855"), "a" : 111, "b" : 222 }
有沒有一個超級權限?不只能夠受權,並且也能夠對集合進行任意操做?答案是確定的,只是不建議使用。那就是role角色設置成root。
> db.auth('dba','dba') 1 > db.createUser( ... { ... user: "zhoujinyi", ... pwd: "zhoujinyi", ... roles: [ ... { role: "root", db: "admin" } #超級root賬號 ... ] ... } ... ) Successfully added user: { "user" : "zhoujinyi", "roles" : [ { "role" : "root", "db" : "admin" } ] } > > show users; #查看當前庫下的用戶 { "_id" : "admin.dba", "user" : "dba", "db" : "admin", "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] } { "_id" : "admin.zhoujinyi", "user" : "zhoujinyi", "db" : "admin", "roles" : [ { "role" : "root", "db" : "admin" } ] } > use admin switched to db admin > db.auth('zhoujinyi','zhoujinyi') 1 > use test switched to db test > db.abc.insert({"a":1,"b":2}) WriteResult({ "nInserted" : 1 }) > db.abc.insert({"a":1111,"b":2222}) #權限都有 WriteResult({ "nInserted" : 1 }) > db.abc.find() { "_id" : ObjectId("5591539bb78649ebd8316857"), "a" : 1, "b" : 2 } { "_id" : ObjectId("559153a0b78649ebd8316858"), "a" : 1111, "b" : 2222 } > db.abc.remove({}) WriteResult({ "nRemoved" : 2 })
由於賬號都是在當前須要受權的數據庫下受權的,那要是不在當前數據庫下會怎麼樣?
> db admin > db.createUser( ... { ... user: "dxy", ... pwd: "dxy", ... roles: [ ... { role: "readWrite", db: "test" }, #在當前庫下建立其餘庫的賬號,在admin庫下建立test、abc庫的賬號 ... { role: "readWrite", db: "abc" } ... ] ... } ... ) Successfully added user: { "user" : "dxy", "roles" : [ { "role" : "readWrite", "db" : "test" }, { "role" : "readWrite", "db" : "abc" } ] } > > show users; { "_id" : "admin.dba", "user" : "dba", "db" : "admin", "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] } { "_id" : "admin.zhoujinyi", "user" : "zhoujinyi", "db" : "admin", "roles" : [ { "role" : "root", "db" : "admin" } ] } { "_id" : "admin.dxy", "user" : "dxy", "db" : "admin", "roles" : [ { "role" : "readWrite", "db" : "test" }, { "role" : "readWrite", "db" : "abc" } ] } > use test switched to db test > db.auth('dxy','dxy') #在admin下建立的賬號,不能直接在其餘庫驗證, Error: 18 Authentication failed. 0 > use admin switched to db admin #只能在賬號建立庫下認證,再去其餘庫進行操做。 > db.auth('dxy','dxy') 1 > use test switched to db test > db.abc.insert({"a":1111,"b":2222}) WriteResult({ "nInserted" : 1 }) > use abc switched to db abc > db.abc.insert({"a":1111,"b":2222}) WriteResult({ "nInserted" : 1 })
上面更加進一步說明數據庫的用戶賬號(user)是跟着數據庫走的,哪一個數據庫裏建立的用戶必須到哪一個數據庫下去認證登陸登出。
建立了這麼多賬號,怎麼查看全部賬號?
> use admin switched to db admin > db.auth('dba','dba') 1 > db.system.users.find().pretty() { "_id" : "admin.dba", "user" : "dba", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "KfDUzCOIUo7WVjFr64ZOcQ==", "storedKey" : "t4sPsKG2dXnZztVYj5EgdUzT9sc=", "serverKey" : "2vCGiq9NIc1zKqeEL6VvO4rP26A=" } }, "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] } { "_id" : "test.zjyr", "user" : "zjyr", "db" : "test", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "h1gOW3J7wzJuTqgmmQgJKQ==", "storedKey" : "7lkoANdxM2py0qiDBzFaZYPp1cM=", "serverKey" : "Qyu6IRNyaKLUvqJ2CAa/tQYY36c=" } }, "roles" : [ { "role" : "read", "db" : "test" } ] } { "_id" : "test.zjy", "user" : "zjy", "db" : "test", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "afwaKuTYPWwbDBduQ4Hm7g==", "storedKey" : "ebb2LYLn4hiOVlZqgrAKBdStfn8=", "serverKey" : "LG2qWwuuV+FNMmr9lWs+Rb3DIhQ=" } }, "roles" : [ { "role" : "readWrite", "db" : "test" } ] } { "_id" : "admin.zhoujinyi", "user" : "zhoujinyi", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "pE2cSOYtBOYevk8tqrwbSQ==", "storedKey" : "TwMxdnlB5Eiaqg4tNh9ByNuUp9A=", "serverKey" : "Mofr9ohVlFfR6/md4LMRkOhXouc=" } }, "roles" : [ { "role" : "root", "db" : "admin" } ] } { "_id" : "admin.dxy", "user" : "dxy", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "XD6smcWX4tdg/ZJPoLxxRg==", "storedKey" : "F4uiayykHDp/r9krAKZjdr+gqjM=", "serverKey" : "Kf51IU9J3RIrB8CFn5Z5hEKMSkw=" } }, "roles" : [ { "role" : "readWrite", "db" : "test" }, { "role" : "readWrite", "db" : "abc" } ] } > db.system.users.find().count() 5
備份還原使用那個角色的賬號?以前建立的賬號zjy:test庫讀寫權限;zjyr:test庫讀權限
root@zhoujinyi:~# mongodump --port=27020 -uzjyr -pzjyr --db=test -o backup #只要讀權限就能夠備份 2015-06-29T11:20:04.864-0400 writing test.abc to backup/test/abc.bson 2015-06-29T11:20:04.865-0400 writing test.abc metadata to backup/test/abc.metadata.json 2015-06-29T11:20:04.866-0400 done dumping test.abc 2015-06-29T11:20:04.867-0400 writing test.system.indexes to backup/test/system.indexes.bson root@zhoujinyi:~# mongorestore --port=27020 -uzjy -pzjy --db=test backup/test/ #讀寫權限能夠進行還原 2015-06-29T11:20:26.607-0400 building a list of collections to restore from backup/test/ dir 2015-06-29T11:20:26.609-0400 reading metadata file from backup/test/abc.metadata.json 2015-06-29T11:20:26.609-0400 restoring test.abc from file backup/test/abc.bson 2015-06-29T11:20:26.611-0400 error: E11000 duplicate key error index: test.abc.$_id_ dup key: { : ObjectId('559154efb78649ebd831685a') } 2015-06-29T11:20:26.611-0400 restoring indexes for collection test.abc from metadata 2015-06-29T11:20:26.612-0400 finished restoring test.abc 2015-06-29T11:20:26.612-0400 done
mongodb 的性能簡介:
使用mongodb最多的是用於查詢,確實,做爲nosql數據庫,查詢的效率確實高於關係型數據庫,這個無可厚非,可是咱們仍是有必要用到關係型數據庫,sql server, MySQL 或者 Oracle。畢竟關係型數據庫存在了這麼多年,仍是比較穩定和安全的。我如今作的是全部的數據都存了兩份,一份是放在mysql裏面,一份是放在mongodb裏面,可是放在mysql裏面的數據只是插入,沒有用於查詢,查詢通常都在mongodb裏面查詢,除非特殊的狀況,我纔會去mysql裏面查詢數據,通常這樣的數據就是屬於比較敏感的數據,仍是查詢mysql比較靠譜,可是有的數據,我就沒有存在mysql裏面了,直接存在mongodb裏面,就好比,向用戶的評論這些東西,不必存在數據庫。
使用mongodb,我用的比較多的仍是他的集合查詢,mongodb的查詢配合linq,簡直不要太爽了,有興趣的朋友能夠去看一下,相關的文章。
寫到這裏,我還想談一下,我設計數據庫的思路。我通常設計數據庫,無論什麼表都有一個ID,主鍵ID, 這個ID是自增加的,我設計的一個方針就是,儘可能避免表與表之間的join查詢,若是每一個表搞個ID,又是主鍵,查詢起來仍是比較節省性能的。join查詢,表與表之間的關聯,又耗性能不說,還把數據庫設計的至關之複雜,增長了開發的難度。
mongodb 的索引的失效機制大概是這樣的:
爲集合建立一個indexes(索引)
而後確保每次插入數據的時候有該列,mongodb將會自動爲你刪除該列
mongodb 的緩存大小(working set size):
mongodb 是不能配置緩存大小的,一直吃內存。由於MongoDB並不干涉內存管理工做,而是把這些工做留給操做系統的虛擬內存管理器去處理,這樣作的好處是簡化了MongoDB的工做,但壞處是你沒有方法很方便的控制MongoDB佔多大內存,幸運的是虛擬內存管理器的存在讓咱們多數時候並不須要關心這個問題。
如下是詳情:
但凡初次接觸MongoDB的人,無不驚訝於它對內存的貪得無厭,至於箇中原因,我先講講Linux是如何管理內存的,再說說MongoDB是如何使用內存的,答案天然就清楚了。
聽說帶着問題學習更有效,那就先看一個MongoDB服務器的top命令結果:
shell> top -p $(pidof mongod)
Mem: 32872124k total, 30065320k used, 2806804k free, 245020k buffers
Swap: 2097144k total, 100k used, 2097044k free, 26482048k cached
VIRT RES SHR %MEM
1892g 21g 21g 69.6
這臺MongoDB服務器有沒有性能問題?你們能夠一邊思考一邊繼續閱讀。
先講講Linux是如何管理內存的
在Linux裏(別的系統也差很少),內存有物理內存和虛擬內存之說,物理內存是什麼天然無需解釋,虛擬內存實際是物理內存的抽象,多數狀況下,出於方便性的考慮,程序訪問的都是虛擬內存地址,而後操做系統會經過Page Table機制把它翻譯成物理內存地址,詳細說明能夠參考Understanding Memory和Understanding Virtual Memory,至於程序是如何使用虛擬內存的,能夠參考Playing with Virtual Memory,這裏就很少費口舌了。
不少人會把虛擬內存和Swap混爲一談,實際上Swap只是虛擬內存引伸出的一種技術而已:操做系統一旦物理內存不足,爲了騰出內存空間存放新內容,就會把當前物理內存中的內容放到交換分區裏,稍後用到的時候再取回來,須要注意的是,Swap的使用可能會帶來性能問題,偶爾爲之無需緊張,糟糕的是物理內存和交換分區頻繁的發生數據交換,這被稱之爲Swap顛簸,一旦發生這種狀況,先要明確是什麼緣由形成的,若是是內存不足就好辦了,加內存就能夠解決,不過有的時候即便內存充足也可能會出現這種問題,好比MySQL就有可能出現這樣的狀況,一個可選的解決方法是限制使用Swap:
shell> sysctl -w vm.swappiness=0
查看內存狀況最經常使用的是free命令:
shell> free -m
total used free shared buffers cached
Mem: 32101 29377 2723 0 239 25880
-/+ buffers/cache: 3258 28842
Swap: 2047 0 2047
新手看到used一欄數值偏大,free一欄數值偏小,每每會認爲內存要用光了。其實並不是如此,之因此這樣是由於每當咱們操做文件的時候,Linux都會盡量的把文件緩存到內存裏,這樣下次訪問的時候,就能夠直接從內存中取結果,因此cached一欄的數值很是的大,不過不用擔憂,這部份內存是可回收的,操做系統的虛擬內存管理器會按照LRU算法淘汰冷數據。還有一個buffers,也是可回收的,不過它是保留給塊設備使用的。
知道了原理,咱們就能夠推算出系統可用的內存是free + buffers + cached:
shell> echo $((2723 + 239 + 25880))
28842
至於系統實際使用的內存是used – buffers – cached:
shell> echo $((29377 - 239 - 25880))
3258
除了free命令,還可使用sar命令:
shell> sar -r
kbmemfree kbmemused %memused kbbuffers kbcached
3224392 29647732 90.19 246116 26070160
shell> sar -W
pswpin/s pswpout/s
0.00 0.00
但願你沒有被%memused嚇到,若是不幸言中,重讀本文。
再說說MongoDB是如何使用內存的
目前,MongoDB使用的是內存映射存儲引擎,它會把數據文件映射到內存中,若是是讀操做,內存中的數據起到緩存的做用,若是是寫操做,內存還能夠把隨機的寫操做轉換成順序的寫操做,總之能夠大幅度提高性能。MongoDB並不干涉內存管理工做,而是把這些工做留給操做系統的虛擬內存管理器去處理,這樣作的好處是簡化了MongoDB的工做,但壞處是你沒有方法很方便的控制MongoDB佔多大內存,幸運的是虛擬內存管理器的存在讓咱們多數時候並不須要關心這個問題。
MongoDB的內存使用機制讓它在緩存重建方面更有優點,簡而言之:若是重啓進程,那麼緩存依然有效,若是重啓系統,那麼能夠經過拷貝數據文件到/dev/null的方式來重建緩存,更詳細的描述請參考:Cache Reheating – Not to be Ignored。
有時候,即使MongoDB使用的是64位操做系統,也可能會遭遇OOM問題,出現這種狀況,多半是由於限制了內存的大小所致,能夠這樣查看當前值:
shell> ulimit -a | grep memory
多數操做系統缺省都是把它設置成unlimited的,若是你的操做系統不是,能夠這樣修改:
shell> ulimit -m unlimited
shell> ulimit -v unlimited
注:ulimit的使用是有上下文的,最好放在MongoDB的啓動腳本里。
有時候,MongoDB鏈接數過多的話,會拖累性能,能夠經過serverStatus查詢鏈接數:
mongo> db.serverStatus().connections
每一個鏈接都是一個線程,須要一個Stack,Linux下缺省的Stack設置通常比較大:
shell> ulimit -a | grep stack
stack size (kbytes, -s) 10240
至於MongoDB實際使用的Stack大小,能夠用以下命令確認(單位:K):
shell> cat /proc/$(pidof mongod)/limits | grep stack | awk -F 'size' '{print int($NF)/1024}'
若是Stack過大(好比:10240K)的話沒有意義,簡單對照命令結果中的Size和Rss:
shell> cat /proc/$(pidof mongod)/smaps | grep 10240 -A 10
全部鏈接消耗的內存加起來會至關驚人,推薦把Stack設置小一點,好比說1024:
shell> ulimit -s 1024
注:從MongoDB1.8.3開始,MongoDB會在啓動時自動設置Stack。
有時候,出於某些緣由,你可能想釋放掉MongoDB佔用的內存,不過前面說了,內存管理工做是由虛擬內存管理器控制的,幸虧可使用MongoDB內置的closeAllDatabases命令達到目的:
mongo> use admin
mongo> db.runCommand({closeAllDatabases:1})
另外,經過調整內核參數drop_caches也能夠釋放緩存:
shell> sysctl -w vm.drop_caches=1
平時能夠經過mongo命令行來監控MongoDB的內存使用狀況,以下所示:
mongo> db.serverStatus().mem:
{
"resident" : 22346,
"virtual" : 1938524,
"mapped" : 962283
}
還能夠經過mongostat命令來監控MongoDB的內存使用狀況,以下所示:
shell> mongostat
mapped vsize res faults
940g 1893g 21.9g 0
其中內存相關字段的含義是:
mapped:映射到內存的數據大小
visze:佔用的虛擬內存大小
res:佔用的物理內存大小
注:若是操做不能在內存中完成,結果faults列的數值不會是0,視大小可能有性能問題。
在上面的結果中,vsize是mapped的兩倍,而mapped等於數據文件的大小,因此說vsize是數據文件的兩倍,之因此會這樣,是由於本例中,MongoDB開啓了journal,須要在內存裏多映射一次數據文件,若是關閉journal,則vsize和mapped大體至關。
若是想驗證這一點,能夠在開啓或關閉journal後,經過pmap命令來觀察文件映射狀況:
shell> pmap $(pidof mongod)
到底MongoDB配備多大內存合適?寬泛點來講,多多益善,若是要確切點來講,這實際取決於你的數據及索引的大小,內存若是可以裝下所有數據加索引是最佳狀況,不過不少時候,數據都會比內存大,好比本文所涉及的MongoDB實例:
mongo> db.stats()
{
"dataSize" : 1004862191980,
"indexSize" : 1335929664
}
本例中索引只有1G多,內存徹底能裝下,而數據文件則達到了1T,估計很難找到這麼大內存,此時保證內存能裝下熱數據便可,至於熱數據是多少,取決於具體的應用,你也能夠經過觀察faults的大小來判斷當前內存是否可以裝下熱數據,若是faults持續變大,就說明當前內存已經不能知足熱數據的大小了。如此一來內存大小就明確了:內存 > 索引 + 熱數據,最好有點富餘,畢竟操做系統自己正常運轉也須要消耗一部份內存。
關於MongoDB與內存的話題,你們還能夠參考官方文檔中的相關介紹。