mongodb

一、原理简介

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。
他支持的数据结构非常松散,是类似json的bjson格式,因此可以存储比较复杂的数据类型。
Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

1.新的词汇
(1)文档 document 相当于javascript的document 在程序中可以理解为对象
例子: {“name”:”乔布斯”,”age”:53}
上述例子是一个人的对象(Steve Jobs!!!)。名字是“乔布斯”,年龄是53,这就是一个文档。类似于我们关系型数据库中的一行。

(2)集合 collection 一组文档被称作集合,类似于关系型数据库表

2.新的东西
(1)无模式
集合是无模式的,不像关系型数据库一样,订好了几列,那么所有数据都是相同列,相同类型
例子: {“name”:”乔布斯”,”age”:53}
{“company”:”psychcn”}
上述例子是一个集合,它之中的文档可以是松散的,不固定的。

但是这样做的话,数据的分析会很难做,所以说从数据库设计的角度,不建议将不同类型的文档放入一个集合。

(2)ObjectId
在每个文档生成时,假如不指定,MongoDB会默认给当前文档加入一个值“_id”,
例子: {“name”:”乔布斯”,”age”:53} 在数据库中保存后将变为
{
“_id”: ObjectId(“4df80f149fd997035452344d”),
“name”:”乔布斯”,
“age”:53
}

ObjectId在单个集合中唯一。类似于我们的主键。但是它的生成和增长完全是MongoDB提我们做,
我们不用考虑自增和重复。所以在分布式开发中优势很高,MongoDB生来就是为了解决分布式问题而存在的

ObjectId的生成规则
Object为12位数字

0 1 2 3 4 5 6 7 8 9 10 11
时 间 戳 机器 PID 计数器

3.BSON
MongoDB的文档类似于JSON,在概念是也是一样的。
但是JSON的表现能力有限,例如数据类型,JSON只有null,布尔,数字,字符串,数组和对象几种类型。
所以MongoDB在JSON的基础上添加了一些东西(具体参考官方文档)。

3.设计例子
我们设计一个学生,课程两个集合

|———————–|
| db.students |
|name:”学生1″ |
|address: |
| |
| |—————–| |
| |address:”和平西桥”| |
| |city:”北京” | |
| |province:”北京” | |
| |postcode:”100013″| |
| |_________________| |
|scores: |
| for_course: |
| grade:4.0 |
| |
| for_course: |
| grade:3.0 |
|_______________________|

|———————–|
| db.courses |
| |
| |————| |
| |name:”语文” | |
| |____________| |
| |
| |————| |
| |name:”数学” | |
| |____________| |
|_______________________|

一、操作使用

1.增加

拿之前设计好的student举例
db.student.insert({“name”:”学生2″});

2.删除

db.student.remove();
将会删除student集合中所有文档
如果按照条件

db.student.remove({“name”:”学生1″});
将会删除所有name为学生1的文档

如果要整个删除集合,那么使用
db.drop_collection(“student”)要比remove快的多,但是这样会将集合完全删除,包括索引

3.更新

(1) 文档替换
$inc
用新的文档更新现有文档,相当于模式的改变。使用文档替换。具体参见书26页

(2) 修改器
db.student.update({ “name” : “学生1″ },
{ “$set”: { “name” : “学生3″ } })
4.查询

(1) 全部返回
select * from student
db.student.find();

(2) 指定返回某一项
select name from student
db.student.find({} ,{ “name” : 1 })
此时除了name被返回,_id也被返回,可以具体设置让_id不返回

(3) 按照条件返回
select * from student where name=’学生1′
db.student.find({“name”,”学生1″})

(4) 查询条件
小于 “$lt”
小于等于 “$lte”
大于 “$gt”
大于等于 “$gte”

例子,按年龄查找学生,找出18-30岁的学生

select * from student where age >= 18 and agedb.student.find({ “age” : { “$gte” : 18 , “$lte” : 30 } })

或者OR “$in”
select * from student where age in (18,19,20)
select * from student where age=18 or age =19 or age = 20
db.student.find({ “age” : { “$in” : [ 18 , 19 , 20 ] } })

否NOT “$not”
select * from student where age <> 18
db.student.find({ “age” : { “$not” : 18 })

排序 “$sort”
db.student.find({“age” : {“$sort”:1 }}) 升序排序
db.student.find({“age” : {“$sort”:-1 }}) 降序排序

5.特殊查询 (不具体介绍,参见书50-55页)
(1) 正则查询,可以在查询条件中使用正则表达式
(2) 查询数组
(3) 查询内嵌文档,Mongo的特殊查询。可以查询文档的子集

6.分页
limit,skip

db.student.find().limit(100);
db.student.find().skip(100).limit(100)

大数据量时不建议采用skip进行分页。详情参见60页

三、高可用性配置
1.主从复制

因为我没有做这个测试,所以这个在这里不讲解。详情见书

2.副本集(推荐)
副本集(Replica Set) 就是有自动故障恢复功能的主从集群,没有固定的主节点,整个集群会投票选举出一个主节点。
各节点会有各自角色。

副本集会有一个主节点(primary)和一个或多个备份节点(secndary)

节点角色分为三种:
1.standard 常规节点,存储数据副本,参选投票,可能成为活跃节点
2.passive 备份节点,存储数据副本,参选投票,不能成为活跃节点
3.arbiter 仲裁节点, 只参与投票,不存储数据,不能成为活跃节点

故障切换完全是自动的。当一个节点不可使用时,自动切换下一个投票选举出的节点作为主节点
也许投票者的票数会成为平衡状态,所以为了避免这种情况,节点的优先级是不一样的。如果优先级相同,数据较新的节点获胜

配置方法:

创建一个目录为存放数据作为准备

$ mkdir -p /data/node1 (集群中各个计算机都应做设置)

启动之前应当为此副本集起一个名字,譬如我这个副本集的名字叫做cmi

接下来,启动第一台计算机
$ ./mongod –auth –dbpath /data/node1 –port 27017 –replSet cmi

另外可以启动时告诉当前机子还有同伴机子。例如
$ ./mongod –auth –dbpath /data/node1 –port 27017 –replSet cmi/192.168.0.2:27018,192.168.0.3:27019

其他计算机皆可参照以上进行启动

下面,要初始化副本集
用客户端工具连上,使用以下命令
db.runCommand({“replSetInitiate” : {
“_id” : “cmi”,
“members” : [
{
"id" : 1,
"host" : "192.168.0.1:27017"
},
{
"id" : 2,
"host" : "192.168.0.2:27018"
}
]
}})

这样就可以了。
另外可以在配置时将角色配上,
例如priority : 1 被动节点,arbiterOnly : true 仲裁节点

当其中某台宕机时,数据库日志将会出现 某一台Server down的信息
各几秒后将会显示 Master switch 192.168.0.x:27017 to 192.168.0.x:27018 这样的字样,此时假如宕机机器再启动
会发现他已经是secondary状态。

3.oplog
记录所有改变数据库状态的操作
例如插入,更新,删除,所以查询就不在记录范围内
可以使用 –oplogSize 指定大小,单位是MB,建议将oplog设置的足够大,因为当oplog过小,最新的操作就会覆盖老的操作,当数据库并发插入更新量大时,从节点始终不能与主节点数据一致。
会造成数据不一致

3.同步
当从节点第一次启动的时候,将会对主节点的数据进行完整的同步,这回相当耗费资源和时间。同步完成后,从节点查询主节点的oplog,并进行操作,保证数据最新

4.备份
(1) 停机备份
将MongoDB安全停止,将数据目录拷贝进行备份

(2) 不停机备份
使用mogodump
$ ./mongodump -d databasename -o backup
将名称为databasename的数据库备份一份到backup目录

这种备份的办法是工具对运行的MongoDB做完整查询,然后将查询到的所有文档写入磁盘。
所以这种办法进行备份,不能保证数据的实时性。

有一种保证实时性的办法。
使用fsync和锁

执行 db.runCommand({ “fsync”:1 ,”lock” :1 });
此时,MongoDB会锁定数据库,禁止任何插入或修改的动作,并将缓冲区的数据强制写入硬盘。保证当前数据最新。
然后就可以复制一份数据库目录

如果数据库运行在有快照功能的文件系统,例如LVM或EBS,那么快照会非常快。
备份好后进行解锁

db.$cmd.sys.unlock.findOne();

另外,做好使用从属备份,当使用副本集时,基本就可以放心了,可以直接对从服务器进行上述操作

5.恢复
使用mongorestore恢复我们之前的一个数据库备份

$ ./mongorestore -d databasename –drop backup

6.修复
db.repairDatabase()

四、安全

1.增加用户
>use admin
>db.addUser(“abc”,”123″)
2.启动时加入安全验证
–auth

五、其他

1.写入原理
先写入内存,再写入oplog,当到达指定时间后,将数据写入硬盘。
在分布式状态下,宕机神马的,都不怕。但是单机数据可靠性不太好,不过,MongoDB官方在1.8版针对单机可靠性出台一个解决方案
如果在启动MongoDB时加上–dur 则MongoDB 会在进行写操作前记一份日志,这和在其他一些数据库中的binlog 类似,在MongoDB 数据文件损坏的情况下,可以使用此日志来进行恢复。据说其对性能的影响不大。

2.一些需要注意的东西
(1) 启动时加上 –auth来确保数据库必须安全访问
(2) 如果安全需要,那么最好给数据库绑定ip,使用 –bindip
(3) 数据库启动时,会启动一个简单的http服务,作为监控状态使用,端口号比使用的端口大1000,例如默认27017的http端口就在28017 如果不需要此服务,可以使用–nohttpinter-face

3.客户端工具
1.MongoVUE.付费工具,我没使用过
2.Rockmongo 类似于phpmyadmin的工具,我觉得很好用,下载windows版后,会自带一个nginx服务。对中文支持很好

其实官方的自带工具就很好了

六、附录

如何安装和使用MongoDB
1.安装
Windows和linux皆可从官网下载zip或tar.gz包,解压,到bin目录。即可,不需要安装
2.启动
启动前一定要建立一个数据库存放目录
新建一个文件夹
mongod –dbpath 数据库目录 –port 服务监听端口,默认27017 –fork 守护进程方式运行 –auth 需要安全验证 –bindip 绑定ip

其中–dbpath是必须,其他项均可酌情考虑。

3.bin目录中文件说明
mongo 客户端工具,同时也是一个shell,可以运行javascript
mongod 数据库服务主文件
mongodump 数据库备份工具
mongoexport 数据库导出工具,可以导json和csv格式
mongoimport 数据库导入工具
mongorestore 数据库恢复工具
mongostat 数据库监控工具
mongofiles 用户导入导出GirdFS文件工具

4.范例
用一个cmd启动数据库服务,一个启动客户端连接
(1)启动服务端
Windows下。进入bin目录
mongod –dbpath D:/data –port 27017 –auth

(2)使用客户端连接
mongo
use test //切换到数据库
db.auth(“abc”,123) //加入没有加入–auth可以忽略这一步

七、结束语

上述文档就是我自2011年6月8日至2011年6月15日研究MongoDB的主要成果,有一部分我没有太搞明白的地方我没有讲,例如分片。目前来讲我觉得我们不太需要进行分片,可以当数据激增时再使用。
此文档完成基于《MongoDB 技术指南》和mongodb.org官方文档完成。

posted on 2012-06-07 15:28  kudosharry  阅读(350)  评论(0编辑  收藏  举报

导航