目录 [−]
本文收集了应用MongoDB(以及Spring-data-mongo)的一些技巧,坑和诀窍。 排名不分先后,文末附有出处。
读写锁
MongoDB使用 readers-writer lock来实现并发读而独占写。
自2.2 (事实上2.1.1+)开始实现每个database一个锁(https://jira.mongodb.org/browse/SERVER-4328),同时还有一个全局(global)锁。 以前的版本只有全局锁。
使用下面的方式可以查看锁状态:
- db.serverStatus(),
- db.currentOp(),
- mongotop,
- mongostat, and/or
- the MongoDB Management Service (MMS)
更多信息查看: http://docs.mongodb.org/manual/faq/concurrency/
2.7.8版本实现了基于collection的锁。 https://jira.mongodb.org/browse/SERVER-1240
内存映射文件
MongoDB使用mmap系统调用为数据建立内存映射文件。它使用内存管理处理所有的数据。 如果数据没有被映射到内存文件,那么此数据不能被访问。 MongoDB追求的就是快。
但这也带来页缺失(page fault)的问题。
当要访问的数据不在内存中的时候,就发生页缺失的现象。这将严重影响性能。 在页缺失的情况下执行一个操作可能比正常操作花费4万倍的时间。
使用SSD可以较好的提高性能。
数据文件
MongoDB默认的数据文件在/data/db文件中。包括以下一些文件
- 预分配的文件 (Preallocated data files): 文件名一般是
.0, .1等。 第一个文件64M,第二个128M,最大2G, 之后分配的都是2G。它的主要功能就是避免磁盘碎片。 但是...但是对于一个大的数据库, 它的消耗实在是太大了。如果你正在设计一个大的数据库系统,你必须考虑到这一点。目前有一个商业解决方案叫TokuMX,使用后存储消耗将会减少90%。repairDatabase与compact命令多少也会帮到你。 - 日志文件(oplog):
- journal: 在Mongo应用写操作之前记录往硬盘的写操作
- 空记录: MongoDB记录删除的文档和collection,但是不会主动将它们的空间释放。使用
compact
进行碎片整理,使用repairDatabase
释放空间。
数据复制有限制
MongoDB中数据复制的复制集策略非常棒,很容易配置并且使用起来确实不错。但如果集群的节点有12个以上,那么你就会遇到问题。MongoDB中的复制集有12个节点的限制,这里是问题的描述,你可以追踪这个问题看看是否已经被解决了。
主从复制不会确保高可用性
尽管已经不建议被使用了,不过MongoDB还是提供了另外一种复制策略,即主从复制。它解决了12个节点限制问题,不过却产生了新的问题:如果需要改变集群的主节点,那么你必须得手工完成,感到惊讶?看看这个链接吧。
不要使用32位版本
MongoDB的32位版本也是不建议被使用的,因为你只能处理2GB大小的数据。还记得第一个限制么?这是MongoDB关于该限制的说明。
索引
ensureIndex()
创建索引db.collection.getIndexes()
查看索引db.collection.stats()
查看索引的占用
内存应该足够大到容纳整个索引,否则可能影响性能。
explain
使用explain查找语句的问题db.XXXXXX.explain()
Spring Data Mongo
Prashant Deva是Chronon的创始人与CTO。Deva喜欢尝试各种新鲜技术,在使用了Spring Data MongoDB一段时间后,他认为这个框架在设计上存在着严重的问题,并撰写了文章进行了深入且详尽的分析。
Spring框架开发者们喜欢到处宣扬他们对MongoDB提供的支持,并以此作为优于其他框架的一个资本。不过,如果在真正的项目中使用Spring Data MongoDB的话,你就会发现框架在某些特性上的严重缺失以及设计上的巨大失误。
无法检索部分字段,只能获取整个文档
这是Spring Data MongoDB设计上最大的瑕疵。它试图用SQL数据库中的行对文档进行建模,并且希望你像ORM一样创建“实体”类。这两者根本就不是一回事。文档可要比SQL数据库中的行复杂多了,也大多了。
没有DBRef延迟加载
这个就更加疯狂了。如果通过DBRefs来引用其他文档,那么Spring Data MongoDB就会得到整个文档而不是文档引用。如果通过DBRefs连接了大量文档,那么一个只想获得几个字段的简单查询都会导致获取到整个文档图!
貌似解决了: DATAMONGO-348
不支持游标
想要通过游标遍历集合吗?没门。要么就取出整个集合,要么就转而使用原生的Mongo Java驱动。
不完备的聚合框架支持
Spring Data MongoDB是从不久之前才开始支持MongoDB聚合框架的,就像框架的其他部分一样,这种支持也是个半成品。
不完善的索引支持
虽然可以通过框架将某个字段标记为“加索引的”,但其他操作却根本就不知道这回事。
无法切换数据库
如果使用原生的Mongo驱动,那么切换数据库简直就是小菜一碟,直接调用getDb(dbName)就行了。但如果使用Spring Data MongoDb,那么这几乎是一件无法做到的事情,除非你愿意自己写大量的代码(不过这么做的话在新版框架发布后可能就会出现移植性问题)。
不支持文档的动态特性
使用MongoDB这样的面向文档的数据库最大的原因就在于其动态特性了。比如说同一集合中的文档可以不同,这样同一个集合中就可以有多个版本的文档,然后逐渐升级,文档也可以嵌套。键名不必事先知道,这样就可以直接向文档中插入属性映射。
但事实却是Spring Data MongoDB丢弃了MongoDB的这个最基本的特性,并且试图在其上构建一个确定的、预先定义好的ORM风格的层,这直接造成框架与底层数据库之间的不匹配。