mongodb 的使用

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  指定配置文件,配置文件里设置 dbpathsql

 运行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(索引) 

db.testCollection.ensureIndex( { "Date": 1 }, { expireAfterSeconds: 10 } )  

而后确保每次插入数据的时候有该列,mongodb将会自动为你删除该列 

db.testCollection.insert({"Date" : new Date(),"name":"zs","age":18})  

 

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与内存的话题,你们还能够参考官方文档中的相关介绍。

相关文章
相关标签/搜索