`
tianya_xiaocao
  • 浏览: 10885 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

(Nosql)MongoDB读书总结

 
阅读更多

张振华:Jack


一:MongoDB解决了些什么问题?
1:大数据时代的问题;
二:MongoDB的优点:
1:丰富的数据模型,易于变化模型(这个没理解)!
2:随着数据量的增加便于扩展和集群;
3:分布式的,大数据量的查询比较快,以空间换性能的方式;
4: JSON的文档(对象)数据库
5:扩展,集群,备份容易;
三:与关系型数据库相比,MongoDB的缺点:
1:mongodb不支持事务操作。
所以事务要求严格的系统(如果银行系统)肯定不能用它。(这点和优点①是对应的)
2:mongodb占用内存空间过大。
关于其原因,在官方的FAQ中,提到有如下几个方面:
1、空间的预分配:为避免形成过多的硬盘碎片,mongodb每次空间不足时都会申请生成一大块的硬盘空间,而且申请的量从64M、128M、256M那 样的指数递增,直到2G为单个文件的最大体积。随着数据量的增加,你可以在其数据目录里看到这些整块生成容量不断递增的文件。
2、字段名所占用的空间:为了保持每个记录内的结构信息用于查询,mongodb需要把每个字段的key-value都以BSON的形式存储,如果 value域相对于key域并不大,比如存放数值型的数据,则数据的overhead是最大的。一种减少空间占用的方法是把字段名尽量取短一些,这样占用 空间就小了,但这就要求在易读性与空间占用上作为权衡了。我曾建议作者把字段名作个index,每个字段名用一个字节表示,这样就不用担心字段名取多长 了。但作者的担忧也不无道理,这种索引方式需要每次查询得到结果后把索引值跟原值作一个替换,再发送到客户端,这个替换也是挺耗费时间的。现在的实现算是 拿空间来换取时间吧。
3、删除记录不释放空间:这很容易理解,为避免记录删除后的数据的大规模挪动,原记录空间不删除,只标记“已删除”即可,以后还可以重复利用。
4、可以定期运行db.repairDatabase()来整理记录,但这个过程会比较缓慢
3:MongoDB没有如MySQL那样成熟的维护工具,这对于开发和IT运营都是个值得注意的地方。
四:MongoDB规范:
文档保留的一些关键字和字符和约定
1:区分大小写;
2:区分值的类型(如:字符窜和数字);
3:同一个文档不能有同一个key;
4:区分文档中key的先后顺序;
5:键key不能以\0空白符结尾;
6:. % _ 保留字符;
集合的命名规范:
1:集合名不能是空字符串;
2:集合名不能以\0空字符作为结尾;
3:集合名不能以system.开头,系统保留字符;
4:集合名中不能还有$最为命名方式,系统保留;
数据库命名规范:(UTF-8字符串)
1:全部小写;
2:最多64字节;
3:不能使空字符串;
4:不能含有空格$.\/(\0空白符);
5:保留字符串有(admin,local,config)
五:MongoDB的一些关键语法:
1)基本操作:insert,remove,update,findOne,upsert,findAndModify
2)修改器的使用:$set,$unset,$inc,$push,$ne,$addToSet,$each
$pop,$pull,
3)$定位符,用来表示已经找到位置的元素的值;
4)安全性:getLastError ,注意事务安全(离玄之箭式的更改数据操作)和捕获异常错误;
5) 注意其不同的数据库连接照成的数据的不一致性,注意连接池的配法;
6)find($lt <,$let <=,$gt >, $gte >=, $ne =,$in,$or),Null 查询的时候也会返回不存在此列的值,配合($exists)使用;find().skip();find().limit();find().sort(); 尽量避免skip 大量数据,会出现性能问题,有绕道的解决方法;
7)数组的查询($all,$size,$slice--分页用;$elemMatch)
8)分页的做法:?????????
9)createCollection(固定集合),converToCapped(转换成固定集合),
10)mongofiles (GridFS)文件的存储put,list, get;
六:MongoDB的一些常用工具:
安 装:mongodb-win32-x86_64-2.4.3.zip 直接解压即可;
运行 :D:\workspace\mongodb2.4.3\bin>mongod.exe --dbpathc:/data/db
可以将很多参数放入到conf中用 --config启动
监控工具:http://docs.mongodb.org/manual/administration/monitoring/
客户端:MongoVUE;
开机启动:vi /etc/rc.local加入下述代码然后再保存即可。

#add mongonDB service
/opt/mongodb/bin/mongod --dbpath=/data/mongoDB/db --logpath=/data/mongoDB/mongodb.log

作为服务启动:在后台安静启动

./mongod --fork --quiet -journal -maxConns=2400 -rest --dbpath=/data/mongoDB/db --logpath=/data/mongoDB/mongodb.log
[root@zwinv bin]# ./startup.sh
about to fork child process, waiting until server is ready for connections.
forked process: 8431
all output going to: /data/mongoDB/mongodb.log
log file [/data/mongoDB/mongodb.log] exists; copied to temporary file [/data/mongoDB/mongodb.log.2013-05-07T09-06-27]
child process started successfully, parent exiting
[root@zwinv bin]# pwd
/opt/mongodb_2.4.3/bin
[root@zwinv bin]# cat startup.sh
./mongod --fork --quiet -journal -maxConns=2400 -rest --dbpath=/data/mongoDB/db --logpath=/data/mongoDB/mongodb.log

七:系统工程师要了解的:
1:主从复制

2: 副本集;

3:分片配置:1)自动分片;addshard 添加片;
2)切分数据:enablesharding 开启分切功能, shardcollection对集合进行分切;

线上配置的终极理解:

MongoDB的原理:
1)传输格式是Bson;
2)传输协议是mongo封与TCP/ip 协议之上装;
3)有命名空间文件(local.ns)和数据文件(local.0,local.1)
4)使用内存映射储存引擎,
MongoDB的以下这些场景都有用武之地:
1)账户和用户资料
2)CMS
3)表格数据处理
4)用户生成的内容系统
5)消息系统
6)系统设置
7)任何形式的日志数据系统
8)图形数据系统
9)基于地理位置的数据系统
java中的一些调用方法:及其写法:
MongoDB常遇到的问题如下:
有待工作中添加..........

MongoDB是如何使用内存的

目前,MongoDB使用的是内存映射存储引擎,它会把磁盘IO操作转换成内存操作,如果是读操作,内存中的数据起到缓存的作用,如果是写操作,内存还可以把随机的写操作转换成顺序的写操作,总之可以大幅度提升性能。MongoDB并不干涉内存管理工作,而是把这些工作留给操作系统的虚拟内存管理器去处理,这样的好处是简化了MongoDB的工作,但坏处是你没有方法很方便的控制MongoDB占多大内存,事实上MongoDB会占用所有能用的内存,所以最好不要把别的服务和MongoDB放一起。

有时候,即便MongoDB使用的是64位操作系统,也可能会遭遇臭名昭著的OOM问题,出现这种情况,多半是因为限制了虚拟内存的大小所致,可以这样查看当前值:

shell>ulimit-a|grep'virtual'

多数操作系统缺省都是把它设置成unlimited的,如果你的操作系统不是,可以这样修改:

shell>ulimit-vunlimited

有时候,MongoDB连接数过多的话,也可能影响性能,连接数可以这样查询:

mongo>db.serverStatus().connections

每个连接都是一个线程,需要一个Stack,而Linux下缺省的Stack设置一般比较大:

#ulimit-a|grepstack
stacksize(kbytes,-s)10240

所有连接消耗的内存加起来会相当惊人,推荐把Stack设置小一点,比如说1024:

shell>ulimit-s1024

注:ulimit的使用是有上下文的,最好放在MongoDB的启动脚本里。

有时候,出于某些原因,你可能想释放掉MongoDB占用的内存,不过前面说了,内存管理工作是由虚拟内存管理器控制的,所以通常你只能通过重启服务来释放内存,你一定不齿于这样的方法,幸好可以使用MongoDB内置的closeAllDatabases命令达到目的:

mongo>useadmin
mongo>db.runCommand({closeAllDatabases:1})

另外,通过调整内核参数drop_caches也可以释放缓存:

shell>sysctl-wvm.drop_caches=1

平时可以通过mongo命令行来监控MongoDB的内存使用情况,如下所示:

mongo>db.serverStatus().mem:
{
"resident":22346,
"virtual":1938524,
"mapped":962283
}

还可以通过mongostat命令来监控MongoDB的内存使用情况,如下所示:

shell>mongostat
mappedvsizeresfaults
940g1893g21.9g0

其中内存相关字段的含义是:

    • mapped:映射到内存的数据大小
    • visze:占用的虚拟内存大小
    • res:占用的物理内存大小

注:如果操作不能在内存中完成,结果faults列的数值不会是0,视大小可能有性能问题。

在上面的结果中,vsize是mapped的两倍,而mapped等于数据文件的大小,所以说vsize是数据文件的两倍,之所以会这样,是因为本例中,MongoDB开启了journal,需要在内存里多映射一次数据文件,如果关闭journal,则vsize和mapped大致相当。

如果想验证这一点,可以在开启或关闭journal后,通过pmap命令来观察文件映射情况:

shell>pmap$(pidofmongod)

到底MongoDB配备多大内存合适?宽泛点来说,多多益善,如果要确切点来说,这实际取决于你的数据及索引的大小,内存如果能够装下全部数据加索引是最佳情况,不过很多时候,数据都会比内存大,比如本文所涉及的MongoDB实例:

mongo>db.stats()
{
"dataSize":1004862191980,
"indexSize":1335929664
}

本例中索引只有1G多,内存完全能装下,而数据文件则达到了1T,估计很难找到这么大内存,此时保证内存能装下热数据即可,至于热数据是多少,取决于具体的应用。如此一来内存大小就明确了:内存 > 索引 + 热数据,最好有点富余,因为前面提到过,连接本身也要消耗一定的内存,另外,操作系统本身正常运转也需要消耗一部分内存。

MongoDB 深入
1.MongoDB shell
mongo其实是数据库shell.一般假定它和mongod运行在同一台机器上,还假定了mongod绑定了默认端口.
如果不是这样的话,可以在启动时指定这些参数,让shell连接另一台服务器:
mongo 192.168.10.10:10000
这样就会连接运行在192.168.10.10上端口为10000的mongod
shell默认连接test数据库,要使用别的数据库,在服务器地址后添加斜杠和数据库名:
mongo 192.168.10.10:10000/refactor
这样会连接192.168.10.10:10000上的refactor数据库
也可以用--nodb选项启动shell,而不连接任何数据库,而只是试试javascript
mongo --nodb
db绝不是仅有的数据库,从shell中可以连接任意多的数据库,这对多个服务器的环境很方便.调用connect(),
并将结果赋值给变量.如在分片环境中,可能想用mongos表示mongos服务器,还想要有每个片的连接,可以
如下操作:
mongos=connect("127.0.0.1:10000")
shard0=connect("127.0.0.1:10001")
shard1=connect("127.0.0.1:10002")
这样就能将mongos,shard0,shard1作为db变量使用.

shell工具
对于管理多个数据库,有多个数据库变量就比简单的db有用处,如在分片中,
要维护一个单独的只想配置服务器的变量:
config=db.getSisterDB("config")
config.shards.find()

2.BSON
MongoDB的文档是个抽象概念,其具体的呈现形式取决与使用的驱动和编程语言.
因为MongoDB中的通信大量依赖于文档,所以需要一种所有驱动,工具和进程都能共享的文档表达方式.
这种表达方式叫Binary JSON(BSON)
BSON是轻量级的二进制格式,能将MongoDB的所有文档表示为自己字符串.数据库能理解BSON,存在磁盘上的文档
也是这种格式.
当驱动要插入文档,或者将文档作为查询条件,驱动会将文档转化成BSON,然后再发往服务器.同样,返回到客户端的文档
也是BSON格式的字符串.驱动需要将这些数据解码,编程本机的文档表示,最后返回给客户端.
用BSON的三个主要原因:
a.效率
BSON设计用来更有效的表示数据,暂用更好的空间.最差的情况下,BSON比JSON效率略低,最好的情况下(
比如存放二进制数据或着大多数),BSON要比JSON要高效的多.
b.可遍历行
有些时候BSON牺牲了空间效率,换取更容易遍历的格式.如,在字符串前面加入其长度,而不是在结尾处使用一个终结符
这对MongoDB的内嵌文档很有用.
c.性能
BSON编码和解码速度都很快.它用C风格的表现方式表示类型,在大多数编程语言中都很快.

2.MongoDB的传输协议
驱动在TCP/IP协议的基础上简单封装了MongoDB传输协议,用来与MongoDB交互.
MongoDB的传输协议基本上是对一个简单封装的BSON数据,如,插入消息会有20字节的头部数据(包括
告知服务器执行写入操作的代码,以及消息长度,要插入的集合名,要插入的BSON文档列表)

3.数据文件
MongoDB的数据目录中,每个数据库都有几个独立的文件.每个数据有一个.ns文件和若干数据文件,数据文件以
递增的数字结尾,所以,数据库refactor会被存放在refactor.ns,refactor.0,refactor.1等文件中.
每个新的以数字结尾的数据文件大小会加倍,直到达到最大值2GB.这是为了让小数据库不浪费太多的磁盘空间,
同时让大数据库使用磁盘上连续的空间.
MongoDB为了保证性能还会预分配数据文件(可以用--norealloc关闭这一功能).预分配在后台完成,有数据文件
被填满时就会自动启动.这意味着MongoDB服务器总是视图在每一个数据库保留一个额外的空数据文件来避免
文件分配产生的阻塞.

4.命名空间和数据域
在数据文件内部,每个数据库都是按照 命名空间 组织的,一种类别的数据与其它类别的分开存放.每个集合的文档都有
自己的命名空间,索引也是.命名空间的元数据存放在数据库的.ns文件中.
每个命名空间的数据都被分成若干组,放到数据文件的某一个区域内,这个区域成为数据域.
如图:
数据库foo有3个数据文件,其中第3个是预分配的空文件.前两个数据文件被分成几个数据域,属于几个不同的命名空间

每个命名空间可以有几个不同的数据域,在磁盘上不必连续.类似于数据库的数据文件,每次新分配的命名空间
的数据域大小也会增加.这是为了平衡命名空间浪费的控件和尽量让一个命名空间的数据连续做出的这种.
图中还有个特殊的命名空间$freelist,存放这不再使用的数据域(如删除集合或索引产生的数据域).
当命名空间分配新的数据域时,系统会先查找空闲列表,看看有没有适合大小的数据域可用

5.内从映射存储引擎
MongoDB默认的存储引擎是内存映射引擎,当服务器启动后,将所有数据文件映射到内存,然后由操作系统来
负责将缓冲数据写入磁盘并将数据调入调出内存页面
这样的移情有若干重要的特性:
a)MongoDB管理内存的代码非常精炼,原因是将大部分工作交给了操作系统.
b)MongoDB服务器进程的虚拟大小通常会非常大,超过整个数据集的大小,这没关系,
因为操作系统会处理让那些数据常驻内存.
c)MongoDB不能控制数据写入到磁盘的顺序,也就不能用预写日志提供单机的持久性.
d)32位的MongoDB服务器有个限制,每个mongod最多处理2GB数据,这是因为所有数据必须能用32
位地址访问到.

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics