MongoDB学习笔记(八):管理

1.启动停止 & 运行监控 

【启动MongoDB】 

执行mongod命令,启动mongod进程,就会启动MongoDB数据库服务。我们在命令行窗口中运行mongod --help可以看到这个命令有大量可选的option,我们这里重点介绍几个: 

1》 --dbpath:指定数据目录,每一个mongod进程都要有一个独立的数据目录,如果不指定这个选项,默认的数据目录是/data/db/(Windows下是C:\data\db\)。当mongod启动后,会在数据目录中创建mongod.lock文件,这个文件可以防止别的mongod进程再次使用这个目录作为数据目录。 

2》 --port:指定数据库服务监听端口号,默认为27017,如果同一台服务器要启动多个mongod进程,这些进程要分别指定不同端口。 

3》 --fork:以守护进程的形式运行MongoDB,Windows平台不支持这个参数,Linux和Unix平台支持! 

4》 --logpath:指定日志输出路径 

5》 --config:指定配置文件,通过该配置文件配置上述各类信息。

1. E:\mongodb\mongodb-win32-x86_64-2.0.6\bin>mongod --dbpath E:\mongoddata --port 27777 --logpath E:\mongodlog\log1.log
2. all output going to: E:\mongodlog\log1.log

上面我们启动了一个指定数据目录、日志输出目录并且监听端口在27777上的mongod服务!我们再通过配置文件的形式启动一个,配置文件的内容是:

01. #mongod启动配置文件
02.  
03. port = 27777 #指定端口
04.  
05. dbpath = E:\mongoddata #指定数据目录
06.  
07. logpath = E:\mongodlog\log1.log #指定日志输出目录
08.  
09. # 对于如--fork这类的开关选项,在配置文件中使用要指定值为true,fork = true
1. E:\mongodb\mongodb-win32-x86_64-2.0.6\bin>mongod --config E:\config.conf
2. all output going to: E:\mongodlog\log1.log

上述即通过配置文件启动了mongod服务。我们前面也介绍了,Windows平台中,通过--install选项,还可以将mongod以服务的形式进行安装,这里就不在演示了。 

【停止MongoDB】 

Windows平台上,如果mongod服务是作为前台进程运行在服务器上(即cmd窗口的形式),可以直接ctrl + c的方式结束,如果mongod是以服务的形式运行,可以到“服务”管理窗口进行结束,或在命令行中,通过net stop mongodb来结束服务(通过net start mongodb来启动服务)。Linux/Unix平台,则通过kill命令来关闭服务。 

--注意:MongoDB权威指南还提到了在admin数据库下,通过运行shutdown({"shutdown" : 1})命令的方式,或在shell中调用其包装函数db.shutdownServer()的形式停止服务,经试验,这种方式在Windows平台上,在关闭掉服务后,都会再次重启服务,不会将服务完全停止掉! 

【运行监控】 

默认情况下,启动mongod服务的同时,会启动一个非常基本的http服务器,该服务器监听的端口总是mongod服务监听端口+1000, 通过浏览器可以访问这个http服务,这里会列举出当前mongod服务的一些运行信息。 

除了上述这种方式外,shell中通过运行serverStatus命令同样可以查看mongod的运行信息:

01. > db.runCommand({"serverStatus" : 1})
02. {
03. "host" : "liuxj-PC",
04. "version" : "2.0.6",
05. "process" : "mongod",
06. "uptime" : 1012,
07. "uptimeEstimate" : 674,
08. "localTime" : ISODate("2012-08-25T07:08:07.120Z"),
09. "globalLock" : {
10. "totalTime" : 1011540200,
11. "lockTime" : 0,
12. "ratio" : 0,
13. "currentQueue" : {
14. "total" : 0,
15. "readers" : 0,
16. "writers" : 0
17. },
18. "activeClients" : {
19. "total" : 0,
20. "readers" : 0,
21. "writers" : 0
22. }
23. },
24. "mem" : {
25. "bits" : 64,
26. "resident" : 20,
27. "virtual" : 61,
28. "supported" : true,
29. "mapped" : 0,
30. "mappedWithJournal" : 0
31. },
32. "connections" : {
33. "current" : 1,
34. "available" : 19999
35. },
36. "extra_info" : {
37. "note" : "fields vary by platform",
38. "page_faults" : 5381,
39. "usagePageFileMB" : 20,
40. "totalPageFileMB" : 4094,
41. "availPageFileMB" : 2603,
42. "ramMB" : 2047
43. },
44. "indexCounters" : {
45. "note" : "not supported on this platform"
46. },
47. "backgroundFlushing" : {
48. "flushes" : 16,
49. "total_ms" : 0,
50. "average_ms" : 0,
51. "last_ms" : 0,
52. "last_finished" : ISODate("2012-08-25T07:07:15.749Z")
53. },
54. "cursors" : {
55. "totalOpen" : 0,
56. "clientCursors_size" : 0,
57. "timedOut" : 0
58. },
59. "network" : {
60. "bytesIn" : 157,
61. "bytesOut" : 186,
62. "numRequests" : 2
63. },
64. "opcounters" : {
65. "insert" : 0,
66. "query" : 1,
67. "update" : 0,
68. "delete" : 0,
69. "getmore" : 0,
70. "command" : 3
71. },
72. "asserts" : {
73. "regular" : 0,
74. "warning" : 0,
75. "msg" : 0,
76. "user" : 0,
77. "rollovers" : 0
78. },
79. "writeBacksQueued" : false,
80. "dur" : {
81. "commits" : 22,
82. "journaledMB" : 0,
83. "writeToDataFilesMB" : 0,
84. "compression" : 0,
85. "commitsInWriteLock" : 0,
86. "earlyCommits" : 0,
87. "timeMs" : {
88. "dt" : 3104,
89. "prepLogBuffer" : 0,
90. "writeToJournal" : 0,
91. "writeToDataFiles" : 0,
92. "remapPrivateView" : 0
93. }
94. },
95. "ok" : 1
96. }
97. >

上面返回的文档,就是当前服务器的相关运行信息,基本上都是顾名思义的,我们解释其中几个,"globalLock"表示了全局写入锁占用服务器多少时间(微妙),“mem”代表了服务器内存映射了多少数据,服务器进程的常驻内存和虚拟内存的占用情况(MB),“backgroundFlushing”表示后台做了多少次fsync(后面后讲到)及用了多少时间,“opcounters”表示各种操作执行的次数,“asserts”:统计了断言的次数。这些统计信息从mongod服务起来后就开始进行,如果数字超过一定范围,就会复位,一旦某个计数器复位,所有计数器同时复位,asserts中的rollovers键对应的值会加1。 

上面提到的两种监控方式给出的都是静态信息,MongoDB还给出了一个工具 mongostat(bin目录中),这个工具动态给出当前数据库服务的相关信息,每秒钟刷新一次,以列表的形式展现:

01. insert  query update delete getmore command flushes mapped  vsize    res faults locked % idx miss %     qr|qw   ar|aw  netIn netOut  conn       time
02. 0      0      0      0       0       1       0     0m    62m    20m      0        0          0       0|0     0|0    62b     1k     2   15:20:36
03. 0      0      0      0       0       1       0     0m    62m    20m      0        0          0       0|0     0|0    62b     1k     2   15:20:37
04. 0      0      0      0       0       1       0     0m    62m    20m      0        0          0       0|0     0|0    62b     1k     2   15:20:38
05. 0      0      0      0       0       1       0     0m    62m    20m      0        0          0       0|0     0|0    62b     1k     2   15:20:39
06. 0      0      0      0       0       1       0     0m    62m    20m      0        0          0       0|0     0|0    62b     1k     2   15:20:40
07. 0      0      0      0       0       1       0     0m    62m    20m      0        0          0       0|0     0|0    62b     1k     2   15:20:41
08. 0      0      0      0       0       1       0     0m    62m    20m      0        0          0       0|0     0|0    62b     1k     2   15:20:42
09. 0      0      0      0       0       1       0     0m    62m    20m      0        0          0       0|0     0|0    62b     1k     2   15:20:43
10. 0      0      0      0       0       1       0     0m    62m    20m      0        0          0       0|0     0|0    62b     1k     2   15:20:44
11. 0      0      0      0       0       1       0     0m    62m    20m      0        0          0       0|0     0|0    62b     1k     2   15:20:45
12. insert  query update delete getmore command flushes mapped  vsize    res faults locked % idx miss %     qr|qw   ar|aw  netIn netOut  conn       time
13. 0      0      0      0       0       1       0     0m    62m    20m      0        0          0       0|0     0|0    62b     1k     2   15:20:46
14. 0      0      0      0       0       1       0     0m    62m    20m      0        0          0       0|0     0|0    62b     1k     2   15:20:47
15. 0      0      0      0       0       1       0     0m    62m    20m      0        0          0       0|0     0|0    62b     1k     2   15:20:48
16. 0      0      0      0       0       1       0     0m    62m    20m      0        0          0       0|0     0|0    62b     1k     2   15:20:49

现在除了MongoDB本身提供的多种监控方式外,还有很多第三方插件可以做这个事情(通过执行serverStatus命令或访问http://ip:port/_status来获取数据,并给出各种易用的展示),如Nagios, Munin, Ganglia, Cacti。最后给大家一个网址:http://www.mongodb.org/display/DOCS/Monitoring+and+Diagnostics 这里可以查看监控相关的文档和工具。

2.安全认证 

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

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

01. > use mylearndb;
02. switched to db mylearndb
03. > db
04. mylearndb
05. > db.addUser("jimmy", "1");
06. { "n" : 0, "connectionId" : 1, "err" : null, "ok" : 1 }
07. {
08. "user" : "jimmy",
09. "readOnly" : false,
10. "pwd" : "265134bf5a25fa7d91d60fba1555ba3b",
11. "_id" : ObjectId("50398ec4fe9dca5a555cab3d")
12. }
13. > use mytestdb;
14. switched to db mytestdb
15. > db
16. mytestdb
17. > db.addUser("tom", "1");
18. { "n" : 0, "connectionId" : 1, "err" : null, "ok" : 1 }
19. {
20. "user" : "tom",
21. "readOnly" : false,
22. "pwd" : "95ac6a199add474e22797396497bfa77",
23. "_id" : ObjectId("50398ee4fe9dca5a555cab3e")
24. }
25. > use admin;
26. switched to db admin
27. > db
28. admin
29. > db.addUser("Green", "1");
30. { "n" : 0, "connectionId" : 1, "err" : null, "ok" : 1 }
31. {
32. "user" : "Green",
33. "readOnly" : false,
34. "pwd" : "10eadce7fd2701b042e05e1c3f066d5b",
35. "_id" : ObjectId("50398f04fe9dca5a555cab3f")
36. }
37. >

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

01. > use mylearndb;
02. switched to db mylearndb
03. > db.users.insert({"name" : "jimmy", "age":34});
04. unauthorized
05. > db.auth("jimmy", "1");
06. 1
07. > db.users.insert({"name" : "jimmy", "age":34});
08. > use admin;
09. switched to db admin
10. > db.auth("Green", "1");
11. 1
12. > use mytestdb;
13. switched to db mytestdb
14. > db.users.insert({"name":"tom", "age":32});
15. >

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

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

01. > db.addUser("test", "q", true);
02. { "n" : 0, "connectionId" : 3, "err" : null, "ok" : 1 }
03. {
04. "user" : "test",
05. "readOnly" : true,
06. "pwd" : "64a4777ccfe889e32052edcd2b1c46ba",
07. "_id" : ObjectId("50399325591704ec2536c2bc")
08. }
09. >

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

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

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

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

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

3.备份 

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

一:数据目录直接备份 

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



二:利用mongodump和mongorestore 

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

导出

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

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

导入:

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

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

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

4.fsync和锁 

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

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

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

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

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

5.修复 

做备份是为了以备不测,比如停电,或自然灾害等,不管怎样,数据是安全的!但总有一些意外情况:不测发生了,但我们还没来得及备份!这时数据目录中的数据可能出于损毁状态,如果在这样的数据目录上启动服务,MongoDB会给出特定的提示!MongoDB提供了修复数据目录的启动方式,就是在启动服务时使用选项--repair。修复过程就是,将所有的文档导出后立即导入,忽略无效的错误文档。并且需要将所有的索引重新建立!修复后,我们重新启动服务即可! 
对于大数据量的数据库,恢复是一个非常耗时的操作!因为所有数据都需要验证,并且所有索引都需要重新建立! 
Shell中通过调用db.repairDatabase()可以在数据库服务运行时修复特定的数据库(也可通过运行命令的方式进行,命令参数为:{"repairDatabase" :1})! 
修复数据库是万不得已才进行的,最佳实践是经常备份数据库,并且利用数据库的复制功能(马上会讲到)来实现故障恢复!

猜你喜欢

转载自jorwen-fang.iteye.com/blog/2031488