博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

mongoDB你需要了解的!

Posted on 2014-03-25 16:02  法号戒智  阅读(215)  评论(0)    收藏  举报

1. 数据库会为每个MongoDB数据库连接创建一个队列,存放这个连接的请求,当客户端发送一个请求,会被放到队列的末尾。只有队列的请求都执行完毕,后续的请求才会执行。注意:每个请求都有独立的队列,要是打开两个shell,就有两个数据库连接。在一个shell中执行插入,之后在另一个shell中进行查询不一定能得到插入的文档。然而在同一个shell中,插入后在进行查询一定能查到的。当开发者用一个线程插入数据,用另一个线程检查是否插入成功时,会遇到这样的问题。有那么一两秒的时间,好像根本没有插入数据,但随后又突然冒出来。

2. 使用读写锁(共享-排他锁、多读单写锁),允许对数据库进行并发的读访问,并且对每一个写操作提供排他的访问。当存在一个读锁时,很多读操作均可使用这个锁。当一个写锁出现,一个写操作排他的占有该锁,并且不被其他的读或者写操作共享。锁是偏向于写操作的,即相对于读操作,写操作有更高的优先权。当一个读和写操作同时在等待一个锁时,mongodb优先给写操作分配锁。 在 2.2 版本以前,mongoDB 只有全局锁;在 2.2 版本开始,大部分读写操作只锁一个库,相对之前版本,这个粒度已经下降,例如如果一个 mongod 实例上有 5 个库,如果只对一个库中的一个集合执行写操作,那么在写操作过程中,这个库被锁;而其它 5 个库不影响。相比 RDBMS 来说,这个粒度已经算很大了!

3. MongoDB使用的是内存映射存储引擎,它会把磁盘IO操作转换成内存操作,如果是读操作,内存中的数据起到缓存的作用,如果是写操作,内存还可以把随机的写操作转换成顺序的写操作,总之可以大幅度提升性能。MongoDB并不干涉内存管理工作,而是把这些工作留给操作系统的虚拟缓存管理器去处理,这样的好处是简化了MongoDB的工作,但坏处是你没有方法很方便的控制MongoDB占多大内存,事实上MongoDB会占用所有能用的内存,所以最好不要把别的服务和MongoDB放一起。到底MongoDB配备多大内存合适?宽泛点来说,多多益善,如果要确切点来说,这实际取决于你的数据及索引的大小,内存如果能够装下全部数据加索引是最佳情况。

 

4. 当服务器启动后,将所有数据文件映射到内存,然后由操作系统负责将缓冲数据写入磁盘并将数据调入调出内存页面。这样有若干特性:MongoDB服务器进程的虚拟内存大小通常会非常大,超过整个数据集的大小,这没关系,因为操作系统会处理让哪些数据常驻内存。32位的mongoDB服务器有个限制,每个mongoDB只能处理2GB数据。这是因为所有数据必须能用32位地址访问到。

5. 因为Mongo是用的是内存映射进行存储数据。数据的修改都是在内存中进行的,如果每次修改数据都调用msync函数的话(即把内存中的数据flush到文件中), I/O代价太大。因此,MongoDB每次把修改的数据先写到内存和日志缓存中,每隔100ms(默认的时间间隔)把日志缓存写入到日志文件中。这样即便宕机(Mongo不正常退出,因而没有调用msync函数),导致数据文件的数据和宕机前内存中的数据不一致,但由于日志文件的存在,可以在重启时把未写入到文件中数据重新写到文件中。日志机制中存在的问题。

问题,日志缓存机制。由于日志也是文件,因此如果日志的数据每次都是写入到日志文件中也会造成很大的I/O,因此日志需要缓存,即缓存100ms的日志数据(或者缓存一定量的数据),可见由于日志缓存每隔100ms才刷新到文件这一限制的存在,Mongo也肯能丢失那些只在日志缓存而没有flush到日志文件中的数据。解决方法,在getLastError中加入j参数,当日志缓存flush到文件中才返回上一次修改操作的结果。(加入j参数的getLastError会使下一次刷新日志缓存的时间间隔缩短到原来的1/3)