以前用mysql数据库,整天都是写大堆大堆的sql语句,要记住这些sql关键字都要花好几天时间,写的蛋都爆了,当接触到mongodb的时候,发现不用写sql,瞬间觉得高大上,瞬间产生了学习使用它的冲动。 1.mongodb简介 mongodb是一种强大,灵活,可扩展的数据存储方
以前用mysql数据库,整天都是写大堆大堆的sql语句,要记住这些sql关键字都要花好几天时间,写的蛋都爆了,当接触到mongodb的时候,发现不用写sql,瞬间觉得高大上,瞬间产生了学习使用它的冲动。
1.mongodb简介
mongodb是一种强大,灵活,可扩展的数据存储方式。它扩展了关系型数据库的众多有用功能,如辅助索引,范围查询和排序。mongodb的功能非常丰富,比如内置的对mapreduce式聚合的支持,以及对地理空间索引的支持。还有很多很多的特点。。。
对于入门级别的人来说,上面说的这些都是浮云,我现在体会不到它的容量,也体会不到它的横向扩展,更体会不到它的速率,这些都是当我们玩到一定的境界才会关心的问题。我单纯觉得它的好处就是非常容易上手,提供了一系列的api,不用写sql语句。至于它和关系型数据库有什么区别,有哪些优点或者哪些缺点需要怎样改进都是以后的事了。
2.mongodb的安装
mongodb的官网就有下载,根据系统windows还是linux还是别的下载32位还是64位的,然后解压安装。我是在linux上安装的,刚开始是在自己的虚拟机上通过root用yum安装的,后来是通过securecrt连接别的服务器在自己的用户上安装学习的,这样就可以玩自己的mongodb不至于弄挂服务器上面的,但是这样不能通过yum了,源码安装貌似又有很多的软件依赖,所以就在官网上下载了一个linux版的,然后通过sftp上传到服务器上解压后直接使用。
3.mongodb的管理
解压完之后进入bin目录,里面都是一些可执行文件,mongo,mongod,mongodump,mongoexport等,后面再说它们的作用吧。
1).启动和停止mongodb
通过执行mongod来启动mongodb服务器,mongod有很多的配置启动选项的,可以通过mongod --help来查看,其中有一些主要的选项:
--dbpath:指定数据目录,默认是/data/db/。每个mongod进程都需要独立的目录,启动mongod时就会在数据目录中创建mongod.lock文件,防止其他mongod进程使用该数据目录。
--port:指定服务器监听的端口,默认是27017。
--fork:以守护进程的方式运行mongodb。
--logpath:指定日志输出路径,如果不指定则会在终端输出。每次启动都会覆盖原来的日志,如果不想覆盖就要用--logappend选项。
--config:指定配置文件,加载命令行未指定的各种选项。我们可以讲我们需要用到的选项写在某个文件中,然后通过该选项来指定这个文件就不必每次启动mongod时都要写。
比如我的配置文件mongodb.conf有如下配置:
port = 9352#fork = true #为注释#logpath = mongodb.logdbpath = data/db
执行mongod启动mongodb服务器指定配置文件:
[tp0352@server0 bin]$ ./mongod --config mongodb.conf 2014-06-05t17:11:13.118+0800 [initandlisten] mongodb starting : pid=18077 port=9352 dbpath=data/db 64-bit host=server0.1692014-06-05t17:11:13.119+0800 [initandlisten] db version v2.6.12014-06-05t17:11:13.119+0800 [initandlisten] git version: 4b95b086d2374bdcfcdf2249272fb552c9c726e82014-06-05t17:11:13.119+0800 [initandlisten] build info: linux build14.nj1.10gen.cc 2.6.32-431.3.1.el6.x86_64 #1 smp fri jan 3 21:39:27 utc 2014 x86_64 boost_lib_version=1_492014-06-05t17:11:13.119+0800 [initandlisten] allocator: tcmalloc2014-06-05t17:11:13.119+0800 [initandlisten] options: { config: mongodb.conf, net: { port: 9352 }, storage: { dbpath: data/db } }2014-06-05t17:11:13.246+0800 [initandlisten] journal dir=data/db/journal2014-06-05t17:11:13.246+0800 [initandlisten] recover : no journal files present, no recovery needed2014-06-05t17:11:15.333+0800 [initandlisten] preallocateisfaster=true 20.742014-06-05t17:11:17.692+0800 [initandlisten] preallocateisfaster=true 13.722014-06-05t17:11:20.858+0800 [initandlisten] preallocateisfaster=true 23.862014-06-05t17:11:20.858+0800 [initandlisten] preallocateisfaster check took 7.612 secs2014-06-05t17:11:20.858+0800 [initandlisten] preallocating a journal file data/db/journal/prealloc.02014-06-05t17:11:23.121+0800 [initandlisten] file preallocator progress: 492830720/1073741824 45%2014-06-05t17:11:26.424+0800 [initandlisten] file preallocator progress: 681574400/1073741824 63%2014-06-05t17:11:29.004+0800 [initandlisten] file preallocator progress: 964689920/1073741824 89%2014-06-05t17:11:34.558+0800 [initandlisten] preallocating a journal file data/db/journal/prealloc.12014-06-05t17:11:37.089+0800 [initandlisten] file preallocator progress: 524288000/1073741824 48%2014-06-05t17:11:40.090+0800 [initandlisten] file preallocator progress: 807403520/1073741824 75%2014-06-05t17:11:43.063+0800 [initandlisten] file preallocator progress: 1017118720/1073741824 94%2014-06-05t17:11:48.020+0800 [initandlisten] preallocating a journal file data/db/journal/prealloc.22014-06-05t17:11:51.040+0800 [initandlisten] file preallocator progress: 576716800/1073741824 53%2014-06-05t17:11:54.039+0800 [initandlisten] file preallocator progress: 807403520/1073741824 75%2014-06-05t17:11:57.026+0800 [initandlisten] file preallocator progress: 1069547520/1073741824 99%2014-06-05t17:12:01.985+0800 [fileallocator] allocating new datafile data/db/local.ns, filling with zeroes...2014-06-05t17:12:01.985+0800 [fileallocator] creating directory data/db/_tmp2014-06-05t17:12:02.285+0800 [fileallocator] done allocating datafile data/db/local.ns, size: 16mb, took 0.167 secs2014-06-05t17:12:02.315+0800 [fileallocator] allocating new datafile data/db/local.0, filling with zeroes...2014-06-05t17:12:02.413+0800 [fileallocator] done allocating datafile data/db/local.0, size: 64mb, took 0.097 secs2014-06-05t17:12:02.434+0800 [initandlisten] build index on: local.startup_log properties: { v: 1, key: { _id: 1 }, name: _id_, ns: local.startup_log }2014-06-05t17:12:02.434+0800 [initandlisten] added index to empty collection2014-06-05t17:12:02.456+0800 [initandlisten] command local.$cmd command: create { create: startup_log, size: 10485760, capped: true } ntoreturn:1 keyupdates:0 numyields:0 reslen:37 494ms2014-06-05t17:12:02.457+0800 [initandlisten] waiting for connections on port 9352
启动mongodb服务器成功,监听端口9352,等待客户端来连接。如果指定日志文件,这些日志就会被输出到指定的日志文件。如果设置为守护进程,就会创建一个子进程,当mongodb服务器启动完成后父进程就会退出。
让mongodb稳妥的停下来很重要,因为可能有的数据还在缓存没写入磁盘,稳妥停止是先让数据写进磁盘然后再结束mongodb进程。可以直接用ctrl+c来停止mongodb服务器,也可以通过客户端来,mongo是一个javascript shell,启动它的时候会自动连接mongodb服务器,所以mongo也是一个mongodb客户端,它可以运行任何javascript程序,也可以操作数据库。下面来看一下mongo停止mongodb服务器:
[tp0352@server0 bin]$ ./mongo --port 9352mongodb shell version: 2.6.1connecting to: 127.0.0.1:9352/test> show dbsadmin (empty)local 0.078gbtest (empty)> use adminswitched to db admin> db.shutdownserver()2014-06-05t17:21:59.263+0800 dbclientcursor::init call() failedserver should be down...2014-06-05t17:21:59.265+0800 trying reconnect to 127.0.0.1:9352 (127.0.0.1) failed2014-06-05t17:21:59.266+0800 warning: failed to connect to 127.0.0.1:9352, reason: errno:111 connection refused2014-06-05t17:21:59.266+0800 reconnect 127.0.0.1:9352 (127.0.0.1) failed failed couldn't connect to server 127.0.0.1:9352 (127.0.0.1), connection attempt failed> exitbye
从上面可以看出,我们连接到了本地9352端口test数据库,admin就是一个root数据库,这个数据库是用来管理整个mongodb的,不是任何人都可以停止mongodb服务器的,所以要使用admin来执行shutdownserver()来停止。
2).安全和认证
上面通过mongo这个客户端来连接mongodb服务器,没有任何的安全认证,也就是说任何人都可以连上去,当然可以在一个可信环境中运行它,保证只有可信的机器才能访问它,也可以对单个连接的认证。每个mongodb的数据库都可以有许多用户,如果开启了安全性检查,则只有数据库认证用户才能执行相关的操作。admin的用户可以对任何数据库进行读写操作,其他数据库的用户只能执行相关权限的操作。
开启安全检查前,先创建几个用户:
> use adminswitched to db admin> db.adduser(tp, 12345)warning: the 'adduser' shell helper is deprecated. please use 'createuser' insteadsuccessfully added user: { user : tp, roles : [ root ] }> use testswitched to db test> db.adduser(test1, 12345, true)warning: the 'adduser' shell helper is deprecated. please use 'createuser' insteadsuccessfully added user: { user : test1, roles : [ read ] }> db.adduser(test2, 12345)warning: the 'adduser' shell helper is deprecated. please use 'createuser' insteadsuccessfully added user: { user : test2, roles : [ dbowner ] }> use adminswitched to db admin> show collectionssystem.indexessystem.userssystem.version> db.system.users.find(){ _id : admin.tp, user : tp, db : admin, credentials : { mongodb-cr : e4aafd1c8d19d9e490192fe5bf43ffe0 }, roles : [ { role : root, db : admin } ] }{ _id : test.test1, user : test1, db : test, credentials : { mongodb-cr : 2da1438b5a04dd46cfdf97c40a3c6d71 }, roles : [ { role : read, db : test } ] }{ _id : test.test2, user : test2, db : test, credentials : { mongodb-cr : 4accbd2cb1dce25ed8b3b162103b0b87 }, roles : [ { role : dbowner, db : test } ] }
在admin中添加了一个用户tp,在test数据库中添加了两个用户test1和test2,adduser()有三个参数,第一个是用户名,第二个是密码,第三个是只读状态,设置true为只读。从用户集合system.users可以看出,tp是admin数据库中的超级用户,有root权限,test1只有read权限,test2是dbowner,可以读也可以写。adduser还能修改用户密码和只读状态。下面重启mongodb服务器,添加--auth命令选项来开启安全检查,然后再通过mongo来连接:
> show dbs2014-06-05t17:59:57.519+0800 listdatabases failed:{ ok : 0, errmsg : not authorized on admin to execute command { listdatabases: 1.0 }, code : 13} at src/mongo/shell/mongo.js:47> use testswitched to db test> db.auth(test1, 12345)1> show collectionspeoplesystem.indexes> db.people.find(){ _id : objectid(53903f7af73bb0df22f8e4a6), name : mary, age : 10 }> db.people.insert({name : join, age : 20})writeresult({ writeerror : { code : 13, errmsg : not authorized on test to execute command { insert: \people\, documents: [ { _id: objectid('53903fd6959e902814f56d8c'), name: \join\, age: 20.0 } ], ordered: true } }})> db.auth(test2, 12345)1> db.people.find(){ _id : objectid(53903f7af73bb0df22f8e4a6), name : mary, age : 10 }> db.people.insert({name : join, age : 20})writeresult({ ninserted : 1 })> use adminswitched to db admin> db.auth(tp, 12345)1> show dbsadmin 0.078gblocal 0.078gbtest 0.078gb
连接到mongodb服务器后没有进行用户认证,所以什么都不能干,当使用test数据库并进行用户认证后,就可以查看test库中的集合,因为test1只能读不能写,所以find可以成功而insert失败,test2既能读也能写,使用admin数据库进行用户认证后就可以查看所有的数据库列表。其实这样的认证用途不是很大,只是一种方式而已,最安全的方式还是限制访问。
3).数据备份
①.数据文件备份
最简单的备份就是数据文件的备份,就是直接赋值data/db这个目录,因为我们前面已经指定了数据目录就是data/db,那么mongodb多有的数据都在这里,但是有个问题就是最新的数据还在缓存中,没用同步到磁盘,可以先停止shutdownserver()再备份。但是这样会影响mongodb正常的工作。
②.mongodump和mongorestore
bin中还有mongodump和mongorestore两个可执行文件,这个是对mongodb的某个数据库进行备份,可以在mongodb正在运行时进行备份,比如备份test数据库,然后将备份的数据库文件再倒入别的mongodb服务器上。这种备份的方式备份的不是最新数据,只是已经写入mongodb中的数据,可能还有的数据在缓存中没有写入,那么这部分数据就是备份不到的。mongodump和mongorestore也可以通过--help查询所有选项。
[tp0352@server0 bin]$ ./mongodump --port 9352 -d test -o test_dataconnected to: 127.0.0.12014-06-05t19:00:03.381+0800 database: test to test_data/test2014-06-05t19:00:03.411+0800 test.system.indexes to test_data/test/system.indexes.bson2014-06-05t19:00:03.426+0800 1 documents2014-06-05t19:00:03.426+0800 test.test to test_data/test/test.bson2014-06-05t19:00:03.463+0800 1 documents2014-06-05t19:00:03.464+0800 metadata for test.test to test_data/test/test.metadata.json
-d是指定数据库,-o是输出备份文件,上面将test数据库备份为test_data文件。
[tp0352@server0 bin]$ ./mongorestore --port 9352 -d temple --drop test_data/test/connected to: 127.0.0.1:93522014-06-05t19:05:53.454+0800 test_data/test/people.bson2014-06-05t19:05:53.454+0800 going into namespace [temple.people]2014-06-05t19:05:53.454+0800 dropping2 objects found2014-06-05t19:05:53.454+0800 creating index: { key: { _id: 1 }, name: _id_, ns: temple.people }[tp0352@server0 bin]$ ./mongo --port 9352mongodb shell version: 2.6.1connecting to: 127.0.0.1:9352/test> show dbsadmin 0.078gblocal 0.078gbtemple 0.078gbtest 0.078gb
这里将上面备份出来的test数据库现在重新导入到temple数据库,--drop代表如果有了temple数据库则将其中的所有集合删除,不指定就会和原来temple中的集合合并。
③.mongoexport和mongoimport
上面讲到mongodump和mongorestore是备份某个数据库的,那么mongoexport和mongoimport就是备份某个数据库中的某个表,同样可以通过--help来查看所有的选项,当然mongoexport也是可以不统计的备份,但是却不一定是最新数据。
[tp0352@server0 bin]$ ./mongoexport --port 9352 -d test -c people -o prson connected to: 127.0.0.1:9352exported 2 records[tp0352@server0 bin]$ cat prson { _id : { $oid : 53903f7af73bb0df22f8e4a6 }, name : mary, age : 10 }{ _id : { $oid : 53903ff6959e902814f56d8d }, name : join, age : 20 }[tp0352@server0 bin]$ ./mongoimport --port 9352 -d temple -c user prson connected to: 127.0.0.1:93522014-06-05t19:14:00.555+0800 imported 2 objects[tp0352@server0 bin]$ ./mongo --port 9352mongodb shell version: 2.6.1connecting to: 127.0.0.1:9352/test> use templeswitched to db temple> show collectionssystem.indexesuser> db.user.find(){ _id : objectid(53903f7af73bb0df22f8e4a6), name : mary, age : 10 }{ _id : objectid(53903ff6959e902814f56d8d), name : join, age : 20 }
-c表示collection集合,上面将test库中的people集合备份出来为prson文件,然后再导入到temple库中的user集合。
④.fsync和锁
mongodump和mongoexport对都可以不停mongodb服务器来进行备份,但是却失去了获取实时数据的能力,而fsync命令也能在不停mongodb的情况下备份实时数据,它的实现其实就是上锁,阻止对数据库的写入操作,然后将缓冲区的数据写入磁盘,备份后再解锁。在这个期间,任何对数据库的写入操作都会阻塞,直到锁被释放。
> db.runcommand({fsync : 1, lock : 1}){ info : now locked against writes, use db.fsyncunlock() to unlock, seealso : http://dochub.mongodb.org/core/fsynccommand, ok : 1}>>在这之间进行备份,执行任何insert操作都会阻塞>> db.fsyncunlock(){ ok : 1, info : unlock completed }
我觉得其实实时也是相对的,将数据库锁住不让写,那么最新的数据还是没备份到。
