学习MongoDB--(8-2):管理(安全认证 & 备份修复)

【安全和认证】

系统管理员的一个重要工作就是确保系统的安全,使MongoDB安全的最好的方式就是在一个可信的环境中运行服务,保证只有可信的机器才能访问它。MongoDB支持对单个连接的认证。

启动MongoDB时,通过使用--auth选项,就可以开启数据库的安全性检查,此时只有经过数据库认证的用户才可以进行读写操作。我们首先要在未开启安全性检查的情况下(不使用--auth选项)向数据库中添加用户:

> use mylearndb;
switched to db mylearndb
> db
mylearndb
> db.addUser("jimmy", "1");
{ "n" : 0, "connectionId" : 1, "err" : null, "ok" : 1 }
{
        "user" : "jimmy",
        "readOnly" : false,
        "pwd" : "265134bf5a25fa7d91d60fba1555ba3b",
        "_id" : ObjectId("50398ec4fe9dca5a555cab3d")
}
> use mytestdb;
switched to db mytestdb
> db
mytestdb
> db.addUser("tom", "1");
{ "n" : 0, "connectionId" : 1, "err" : null, "ok" : 1 }
{
        "user" : "tom",
        "readOnly" : false,
        "pwd" : "95ac6a199add474e22797396497bfa77",
        "_id" : ObjectId("50398ee4fe9dca5a555cab3e")
}
> use admin;
switched to db admin
> db
admin
> db.addUser("Green", "1");
{ "n" : 0, "connectionId" : 1, "err" : null, "ok" : 1 }
{
        "user" : "Green",
        "readOnly" : false,
        "pwd" : "10eadce7fd2701b042e05e1c3f066d5b",
        "_id" : ObjectId("50398f04fe9dca5a555cab3f")
}
>

上面,我们分别向数据库mylearndb, mytestdb, admin 添加了3个用户,这里需要注意,往admin库中添加的用户就是超级用户(数据库管理员),经过认证的数据库管理员,可以操作任何数据库!添加完用户后,我们重启mongod服务,此时要加上--auth选项,开启安全认证,然后测试如下:

> use mylearndb;
switched to db mylearndb
> db.users.insert({"name" : "jimmy", "age":34});
unauthorized
> db.auth("jimmy", "1");
1
> db.users.insert({"name" : "jimmy", "age":34});
> use admin;
switched to db admin
> db.auth("Green", "1");
1
> use mytestdb;
switched to db mytestdb
> db.users.insert({"name":"tom", "age":32});
>

上例中,我们先连接数据库mylearndb,向一个集合插入文档,提示未认证,我们使用相应的用户名密码认证后,插入成功。然后我们切换到admin数据库中,通过了管理员认证,然后我们可以操作各种数据库了,包括还未认证的mytestdb数据库!这里需要注意,在哪个数据库中插入的用户,就要在哪个数据库中认证,因此管理员账号必须在admin数据库下认证!

MongoDB还支持只读用户,调用addUser函数,第三个参数设置为true即可,如下:

> db.addUser("test", "q", true);
{ "n" : 0, "connectionId" : 3, "err" : null, "ok" : 1 }
{
        "user" : "test",
        "readOnly" : true,
        "pwd" : "64a4777ccfe889e32052edcd2b1c46ba",
        "_id" : ObjectId("50399325591704ec2536c2bc")
}
>

在该数据库下,该用户只可以读,不可以进行写操作。

MongoDB将用户信息保存在相应数据库的system.users集合中,如果我们要删除一个用户,直接删除这个集合的相应文档即可!

> use mylearndb;
switched to db mylearndb
> db.system.users.find();
{ "_id" : ObjectId("50398ec4fe9dca5a555cab3d"), "user" : "jimmy", "readOnly" : false, "pwd" : "265134bf5a25fa7d91d60fba1555ba3b" }
{ "_id" : ObjectId("50399325591704ec2536c2bc"), "user" : "test", "readOnly" : true, "pwd" : "64a4777ccfe889e32052edcd2b1c46ba" }
> db.system.users.remove({"user":"test"});
> db.system.users.find();
{ "_id" : ObjectId("50398ec4fe9dca5a555cab3d"), "user" : "jimmy", "readOnly" : false, "pwd" : "265134bf5a25fa7d91d60fba1555ba3b" }
>

MongoDB的认证是与数据库的连接绑定在一起,即在同一个连接下,对一个数据库的验证进行一次即可。如果驱动程序使用了连接池,或因为故障切换到另外一个节点,连接改变了,所有的认证必须重新进行一遍,有些驱动程序将这些透明化,但有些没有,必须显示重新进行认证。这是MongoDB认证的一个弊端,所以建议不启用数据库认证,将用户认证转移到应用层来处理!

除了上面提到的用户认证外,我们使用MongoDB时,还有一些安全点需要进行考虑。比如MongoDB的传输协议默认是不加密的,mongod在启动会同时启动一个http服务(可通过启动选项--nohttpinterface进行关闭),数据库服务器端javascript脚本的执行(可通过--noscripting禁止任何服务器端脚本的执行)等。

【备份】

做备份是管理任何数据库系统的一项非常重要的任务,我们在管理关系型数据库时,就经常将exp/expdp做成系统定时任务来对数据库进行备份。对于MongoDB备份同样重要,并且MongoDB提供了很多中备份方式,这边进行逐一讲解。

一:数据目录直接备份

MongoDB将所有的数据都保存在数据目录中(启动时通过--dbpath指定的那个目录),我们备份数据的最简单方式就是保存这个目录的一个副本即可。但这种方式有一个最显著的问题,就是在运行时的MongoDB数据目录上备份并不安全(除非服务器进行了完整的fsync,并不允许写入,这个我们马上就会说到),有可能我们做得备份本身就是破损的!采用这种方式做备份,最好是将服务器停掉,备份后,再重启!这个在实际应用中是不允许的,因此使用的也很少!

 

二:利用mongodump和mongorestore

MongoDB自带的两个工具。mongodump是一个能在运行时备份数据库的方法,其就是一个客户端,对运行的MongoDB进行查询,然后将数据保存到相应位置即可。向 MongoDB提供的所有工具一样,我们可以通过使用--help选项来看这个工具的具体用法,我们这边演示一下基本的使用方法:

导出:

mongodump -d mylearndb -o E:\mongobak\27017

通过-d选项指定导出的数据库,此处只可以指定一个数据库!在Windows平台下测试,如果不使用-d选项(导出所有数据库),mongodump会在数据库服务器上创建一个名称为“*”的空数据库,导出这个数据库时因为创建同名Windows目录(名为“*”)失败而报错,但不影响其他数据库的导出,建议导出时通过-d指定数据库!-o选项,指定导出的数据库的放置目录,mongodump会在该目录下创建一个于数据库同名的目录,将数据导入在这个目录中。mongodump还支持导出特定集合(-c选项,只可指定一个集合),导出特定文档(-q查询条件)等,需要时可以查阅各选项(通过--help)。

导入:

mongorestore -d mybakdb --drop E:\mongobak\27017\mylearndb

-d选项指明导入的数据库,--drop指名如果有同名集合先将其删除再导入(如果不用该选项,会进行合并),最后跟上要导入的数据库目录即可!会将这个目录的所有集合和数据导入到mybakdb这个数据库中!

使用mongodump虽然可以不用停机备份,但其也有一个缺点,就是无法备份实时数据,尤其当数据库服务在进行大量的写操作时,mongodump只是备份了某一个特定时间点的数据。

 

三:fsync和锁

通过fsync和锁可以在MongoDB运行时,安全有效地使用复制数据目录的方式进行备份!fsync命令会强制服务器将所有缓冲区内容写入到磁盘!通过上锁,可以阻止数据库的进一步写入!下面演示具体做法:

> use admin;
switched to db admin
> db.runCommand({"fsync" : 1, "lock" : 1});
{
        "info" : "now locked against writes, use db.fsyncUnlock() to unlock",
        "seeAlso" : "http://www.mongodb.org/display/DOCS/fsync+Command",
        "ok" : 1
}
>

注意运行fsync命令需要在admin数据库下进行!通过执行上述命令,缓冲区内数据已经被写入磁盘数据库文件中,并且数据库此时无法执行写操作(写操作阻塞)!这样,我们可以很安全地备份数据目录了!备份后,我们通过下面的调用,来解锁:

> use admin;
switched to db admin
> db.$cmd.sys.unlock.findOne();
{ "ok" : 1, "info" : "unlock completed" }
> db.currentOp();
{ "inprog" : [ ] }
>

在admin数据库下解锁。通过执行db.currentOp()来确认解锁成功!通过fsync和写入锁的使用,可以非常安全地备份实时数据,也不用停止数据库服务。但其弊端就是,在备份期间,数据库的写操作请求会阻塞!

 

四:从属备份

上面提到的备份技术已经非常灵活,但默认都是指直接在主服务器上进行!MongoDB更推荐备份工作在从服务器上进行!从服务器上的数据基本上和主服务器是实时同步的,并且从服务器不在乎停机或写阻塞!所以我们可以利用上述3种方式的任意一种在从服务器上进行备份操作!

 

【修复】

做备份是为了以备不测,比如停电,或自然灾害等,不管怎样,数据是安全的!但总有一些意外情况:不测发生了,但我们还没来得及备份!这时数据目录中的数据可能出于损毁状态,如果在这样的数据目录上启动服务,MongoDB会给出特定的提示!MongoDB提供了修复数据目录的启动方式,就是在启动服务时使用选项--repair。修复过程就是,将所有的文档导出后立即导入,忽略无效的错误文档。并且需要将所有的索引重新建立!修复后,我们重新启动服务即可!

对于大数据量的数据库,恢复是一个非常耗时的操作!因为所有数据都需要验证,并且所有索引都需要重新建立!

Shell中通过调用db.repairDatabase()可以在数据库服务运行时修复特定的数据库(也可通过运行命令的方式进行,命令参数为:{"repairDatabase" :1})!

修复数据库是万不得已才进行的,最佳实践是经常备份数据库,并且利用数据库的复制功能(马上会讲到)来实现故障恢复!


 

你可能感兴趣的:(学习MongoDB--(8-2):管理(安全认证 & 备份修复))