mongodb有一个write concern的设置,作用是保障write operation的可靠性。一般是在client driver里设置的,和db.getLastError()方法关系很大

一般来说,所有的mongo driver,在执行一个写操作(insert、update、delete)之后,都会立刻调用db.getLastError()方法。这样才有机会知道刚才的写操作是否成功,如果捕获到错误,就可以进行相应的处理。处理逻辑也是完全由client决定的,比如写入日志、抛出错误、等待一段时间再次尝试写入等。作为mongodb server并不关心,server只负责通知client发生了错误

这里有2点需要注意:

1、db.getLastError()方法是由driver负责调用的,所以业务代码不需要去显式调用。这点后面还会专门提到

2、driver一定会调用db.getLastError()函数,但是并不一定能捕获到错误。这主要取决于write concern的设置级别,这也是本文的主题

write concern:0(Unacknowledged)

此级别调用的时序图如下:

driver调用了getLastError()之后,mongod立刻返回结果,然后才实际进行写操作。所以getLastError()的返回值一定是null,即使之后的Apply发生了错误,driver也不知道。使用这个级别的write concern,driver的写入调用立刻返回,所以性能是最好的,但是可靠性是最差的,因此并不推荐使用。在各平台最新版本的driver中,也不再以0作为默认级别。其实还有一个w:-1的级别,是error ignored,基本上和w:0差不多。区别在于,w:-1不会捕获任何错误,而w:0可以捕获network error

write concern:1(acknowledged)

此级别调用的时序图如下:

和Unacknowledged的区别是,现在mongod只有在Apply(实际写入操作)完成之后,才会返回getLastError()的响应。所以如果写入时发生错误,driver就能捕获到,并进行处理。这个级别的write concern具备基本可靠性,也是目前mongodb的默认设置级别

write concern:1 & journal:true(Jounaled)

此级别调用的时序图如下:

Acknowledged级别的write concern也不是绝对可靠的。因为mongodb的Apply操作,是将数据写入内存,定期通过fsync写入硬盘。如果在Apply之后,fsync之前mongod挂了,或者甚至server挂了,那持久化实际上是失败的。但是在w:1的级别下,driver无法捕获到这种情况下的error(因为response在apply之后就已经返回到driver)

mongod解决这个问题的办法是使用Journal机制,写操作在写入内存之后,还会写到journal文件中,这样如果mongod非正常down掉,重启以后就可以根据journal文件中的内容,来还原写操作。在64位的mongod下,journal默认是打开的。但是32位的版本,需要用--journal参数来启动

在driver层面,则是除了设置w:1之外,再设置journal:true或j:true,来捕获这个情况下的error

write concern:2(Replica Acknowledged)

这个级别只在replica set的部署模式下生效

这个级别下,只有secondary从primary完成了复制之后,getLastError()的结果才会返回。也可以同时设置journal:true或j:true,则还要等journal写入也成功后才会返回。但是注意,只要primary的journal写入就会返回,而不需要等待secondary的journal也写入。类似的也可以设置w:3,表示至少要有3个节点有数据;或者w:majority,表示>1/2的节点有数据。一般小规模的集群就是3节点部署,所以配置w:2就可以了

建议

设置write concern级别,其实就是在写操作的性能和可靠性之间做权衡。写操作的等待时间越长,可靠性就越好。对于非关键数据,建议使用默认的w:1就可以了,对于关键数据,则使用w:1 & j:true比较好。这里要注意,journal无论如何都是建议打开的,设置j:true,只是说driver调用getLastError()之后是否要等待journal写入完成再返回。并不是说不设置j:true就关闭了server端的journal

关于getLastError()

一般来说,开发者写的代码,不需要自行调用db.getLastError()函数,driver在每一个写操作之后,都会立刻自动调用该方法

  1. db.collection("test", {}, function (err, collection) {
  2. collection.insert({name: "world peace"}, function (err, result) {
  3. assert.equal(null, err);
  4. console.log(result);
  5. db.close();
  6. })
  7. });

这段代码,driver在insert()之后,隐式调用db.getLastError(),如果捕获到任何错误,就会赋给回调函数中的err参数。区别就在于是否能够捕获到错误。在w:-1时,err永远是null(没有机会捕获到error);在w:0时,一般也捕获不到,除了network error;在w:1时,如果mongod apply发生错误,就会传递给err参数了。代码都是一样的,区别就在于设置的write concern级别

mongodb write 【摘自网上,只为记录,学习】的更多相关文章

  1. 开始记录学习java的笔记

    今天开始记录学习java的笔记,加油

  2. 用mongodb 固定集合实现只保留固定数量的记录,自动淘汰老旧数据

    在一个保存report记录的场景中,我们使用MongoDB进行数据存储 example: db: report Collection: daily_report 创建db:  use report; ...

  3. php redis 【摘自网上,只为参考】

    ubuntu下安装php redis sudo apt-get install redis-server 测试redis是否安装成功:注意:要开启redis redis-cliset test hel ...

  4. redis【摘自网上,只为以后查看】

    ubuntu安装启动redis 1.下载安装 cd /tmp wget http://redis.googlecode.com/files/redis-2.2.13.tar.gz tar -zxf r ...

  5. C# 连接mongodb副本集+分片读写分离及学习资料

    一.副本集配置 搭建完毕,1台主实例.1台从实例.1台仲裁实例.mongodb建议副本集中的机器数量为奇数,即至少需要3台实例 二.副本集连接字符串 1.读 mongodb://secondary.c ...

  6. 借网上盛传2000w记录介绍多进程处理

    2000w的数据在网上搞得沸沸扬扬,作为技术宅的我们也来凑凑热闹.据了解网上有两个版一个是数据库文件另一个是CSV文件的,前者大小有好几个G后者才几百M.对于不是土豪的我们当然下载几百M的.至于在哪下 ...

  7. MongoDB中的映射,限制记录和记录拼排序 文档的插入查询更新删除操作

    映射 在 MongoDB 中,映射(Projection)指的是只选择文档中的必要数据,而非全部数据.如果文档有 5 个字段,而你只需要显示 3 个,则只需选择 3 个字段即可. find() 方法 ...

  8. mongodb副本集原理及部署记录

    工作原理 1.副本集之间的复制是通过oplog日志现实的.备份节点通过查询这个集合就可以知道需要进行复制的操作 2.oplog是节点中local库中的一个固定的集合,在默认情况下oplog初始化大小为 ...

  9. [转载]作为理工科学生,我们为什么要练就好的文笔?我们需要发blog来记录学习历程?

    文/JoeyChen 工程师该怎样才能突破自己的能力瓶颈?写 blog! 工程师该怎样精进自己在职涯上所需要的能力?写 blog! 工程师该怎样才能保持学习与成长的动能?写 blog! 工程师该怎样才 ...

随机推荐

  1. Add And Reset a Federation Server to a Federation Server Farm adfs ad

    Applies To: Active Directory Federation Services (AD FS) 2.0 After you install the Active Directory ...

  2. centos6.4 yum kvm

    1. 安装软件包:   yum -y install virt-manager; yum install qemu-kvm  yum install libvirt yum install libvi ...

  3. 微软2016校园招聘4月在线笔试 ABC

    题目链接:http://hihocoder.com/contest/mstest2016april1/problems 第一题:输入N,P,W,H,代表有N段文字,每段有ai个字,每行有⌊W/S⌋个字 ...

  4. ldconfig及 LD_LIBRARY_PATH

    dconfig及 LD_LIBRARY_PATH 1. 往/lib和/usr/lib里面加东西,是不用修改/etc/ld.so.conf的,但是完了之后要调一下ldconfig,不然这个library ...

  5. A Tour of Go Range

    The range form of the for loop iterates over a slice or map. package main import "fmt" , , ...

  6. NSThread常见方法

    // CACurrentMediaTime:获取绝对时间:从新世纪到现在的绝对时间,常用来计算耗时操作的时间差(结束时间 - 开始时间) double start = CACurrentMediaTi ...

  7. C#使用Windows API实现桌面上的遮罩层(鼠标穿透)

    C#使用Windows API实现桌面上的遮罩层(鼠标穿透) C#实现实现桌面上的遮罩层(鼠标穿透)主要通过一下几个API函数来实现:GetWindowLong,SetWindowLong,SetLa ...

  8. SQL Server 2000的安全配置

    SQL Server 2000的安全配置 数据库是电子商务.金融连同ERP系统的基础,通常都保存着重要的商业伙伴和客户信息.大多数企业.组织连同政府 部门的电子数据都保存在各种数据库中,他们用这些数据 ...

  9. ios 解决有关火星坐标的问题

    CLLocationManager 定位获取CLLocation 是地球坐标,而MKMapView 获取的是天朝火星坐标,这就导致了使用定位的时候,显示用户的蓝点和当前定位信息偏差(因为蓝点是调用了M ...

  10. cocos2d-x增加控制台程序代码

    #include "main.h" #include "AppDelegate.h" #include "CCEGLView.h" USIN ...