Mongodb GetLastError写入安全机制

默北 mongodb218,1471字数 2965阅读9分53秒阅读模式

一、简介

很多人抱怨mongodb是内存数据库,也没有事务,会不安全,其实这都是对Mongodb的误解,Mongodb有完整的redolog,binlog和持久化机制,不必太担心数据丢失问题。文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

journal是Mongodb中的redo log,而Oplog则是负责复制的binlog(对应Mysql)。文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

在google.groupuser上,mongo的开发者有一段这样的解释:文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

#########
By default:
Collection data (including oplog) is fsynced to disk every 60 seconds.
Write operations are fsynced to journal file every 100 milliseconds.
Note, oplog is available right away in memory for slaves to read. Oplog is a capped collection
so a new oplog is never created, old data just rolls off.
GetLastError with params:
(no params) = return after data updated in memory.
fsync: true:
with --journal = wait for next fsync to journal file (up to 100 milliseconds);
without --journal = force fsync of collection data to disk then return.
w: 2 = wait for data to be updated in memory on at least two replicas.
########文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

可以看到:文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

1、如果打开journal,那么即使断电也只会丢失100ms的数据,这对大多数应用来说都可以容忍了。从1.9.2+,mongodb都会默认打开journal功能,以确保数据安全。而且journal的刷新时间是可以改变的,2-300ms的范围,使用 --journalCommitInterval 命令。文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

2、Oplog和数据刷新到磁盘的时间是60s,对于复制来说,不用等到oplog刷新磁盘,在内存中就可以直接复制到Sencondary节点。文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

GetLastError Command文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

getLastError 是Mongodb的一个命令,从名字上看,它好像是取得最后一个error,但其实它是Mongodb的一种客户端阻塞方式。用这个命令来获得写操作是否成功的信息。文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

getlastError有几个参数:j,w,fsync。在大多数的语言驱动中,这个命令是被包装成writeConcern类,比如java。文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

二、什么时候使用这个命令:文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

1、Mongodb的写操作默认是没有任何返回值的,这减少了写操作的等待时间,也就是说,不管有没有写入到磁盘或者有没有遇到错误,它都不会报错。但一般我们是不放心这么做的,这时候就调用getlastError命令,得到返回值。文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

以java为例,举个例子:当我们为字段建立了一个唯一索引,针对这个字段我们插入两条相同的数据,不设置WriterConcern或者设置WriterConcern.NORMAL模式,这时候即便抛出异常,也不会得到任何错误。insert()函数在java中的返回值是WriteResult类,文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

WriteResult( CommandResult o , WriteConcern concern ){
        _lastErrorResult = o;
        _lastConcern = concern;
        _lazy = false;
        _port = null;
        _db = null;
    }

这个类实际上包装了getlastError的返回值,但是这时候WriteResult的_lastErrorResult属性实际上是空的。因为dup key错误是server error,只有在WriterConcern.SAFE或更高级别的模式下,才会得到server error。文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

2、在多线程模式下读写Mongodb的时候,如果这些读写操作是有逻辑顺序的,那么这时候也有必要调用getlasterror命令,用以确保上个操作执行完下个操作才能执行,因为两次执行的连接有可能是不同的。在大多数情况下,我们都会使用连接池去连接mongodb,所以这是需要注意的。文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

举个例子:我们之前遇到这个异常"The connection may have been used since this write, cannot obtain a result",异常原因有两个,连接池数量太小,竞争太激烈,没有设置writerConcern.SAFE。
参见:https://groups.google.com/forum/?fromgroups=#!topic/mongodb-user/xzw0Cb831VY
PS:在java等语言中,是不需要显示调用这个命令的,只需要设置WriterConcern即可。文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

三、getlastError最佳实践文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

1、如果没有特殊要求,最低级别也要使用WriterConcern.SAFE,即w=1。文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

2、对于不重要的数据,比如log日志,可以使用WriterConcern.NONE或者WriterConcern.NORMAL,即w=-1或者w=0,省去等待网络的时间。文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

3、对大量的不连续的数据写入,如果每次写入都调用getLastError会降低性能,因为等待网络的时间太长,这种情况下,可以每过N次调用一下getLastError。但是在Shard结构上,这种方式不一定确保之前的写入是成功的。文章源自运维生存时间-https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/

4、对连续的批量写入(batchs of write),要在批量写入结束的时候调用getlastError,这不仅能确保最后一次写入正确,而且也能确保所有的写入都能到达服务器。如果连续写入上万条记录而不调用getlastError,那么不能确保在同一个TCP socket里所有的写入都成功。这在并发的情况下可能就会有问题。避免这个并发问题,可以参考如何在一个链接(请求)里完成批量操作,URL:java driver concurrency
http://www.mongodb.org/display/DOCS/Java+Driver+Concurrency

5、对数据安全要求非常高的的配置:j=true,w="majority" db.runCommand({getlasterror:1,j:true,w:'majority',wtimeout:10000})
java语言可以在MongoOption中设置,MongoOption中的这些设置是全局的,对于单独的一个(连接)操作,还可以分别设置。

参考:
1、http://www.mongodb.org/display/DOCS/Journaling
2、http://www.mongodb.org/display/DOCS/Java+Driver+Concurrency
3、http://www.mongodb.org/display/DOCS/getLastError+Command
转自:http://blog.chinaunix.net/uid-15795819-id-3373361.html

 

weinxin
我的微信
微信公众号
扫一扫关注运维生存时间公众号,获取最新技术文章~
默北
  • 本文由 发表于 29/06/2014 01:00:08
  • 转载请务必保留本文链接:https://www.ttlsa.com/mongodb/mongodb-getlasterror-write-security-mechanism/
评论  2  访客  0

    来自外部的引用

评论已关闭!