MongoDB 默认写入关注保存数据丢失问题与源码简单分析

MongoDB 默认写入关注可能保存数据丢失问题分析

问题描述:

       EDI服务进行优化,将原有MQ发送成功并且DB写入成功,两个条件都达成,响应接收订单数据成功,修改为只有有一个条件成功就响应接收数据成功。只要发送MQ成功,就代表数据已经给下游客单系统,保存DB数据失败可以接受,优先保证数据不阻断。发送MQ失败,保存DB数据成功,代表我们已经接受到订单数据,可以通过容错服务进行后续处理。这样就可以保证MQ与DB只要有任何一个是没问题就不会影响客户订单数据的正常下发。

近期发生MQ服务端忙碌,拒收生成消息。理论上数据应该已经保存到DB。通过容错服务就可以处理。但是客单系统确实没有收到,并且数据库中也并未查询到。ELK确实记录了客户是已经发送订单下发请求并且我们也返回成功了。

经过ELK日志记录排查,可以得到MQ发送失败,DB保存没有抛异常,应该算DB已经保存成功。但是实际却没成功。

经过一番排查,应该是默认的保存数据的写入关注策略问题。

默认写入关注设置为:WriteConcern.NORMAL

 

WriteConcern概述:

WriteConcern.NONE:               没有异常抛出

WriteConcern.NORMAL:           仅抛出网络错误异常,没有服务器错误异常

WriteConcern.SAFE:                 抛出网络错误异常、服务器错误异常;并等待服务器完成写操作。

WriteConcern.MAJORITY:         抛出网络错误异常、服务器错误异常;并等待一个主服务器完成写操作。

WriteConcern.FSYNC_SAFE:      抛出网络错误异常、服务器错误异常;写操作等待服务器将数据刷新到磁盘。

WriteConcern.JOURNAL_SAFE:  抛出网络错误异常、服务器错误异常;写操作等待服务器提交到磁盘的日志文件。

WriteConcern.REPLICAS_SAFE:  抛出网络错误异常、服务器错误异常;等待至少2台服务器完成写操作

Spring MongoDB 设置

       <mongo:client-options write-concern="SAFE " />

Spring data MongoDB

@Autowired
MongoTemplate mongoTemplate;
mongoTemplate.setWriteConcern(WriteConcern.ACKNOWLEDGED);
mongoTemplate.save(data,"ediData");

说明:

@Deprecated
public static final WriteConcern SAFE = ACKNOWLEDGED;

SAFE 已经被弃用,源码可以看到直接设置为了 ACKNOWLEDGED

关于Spring data jap MongoDB MongoRepository 接口的说明与源码分析:

       MongoRepository提供了简单直接的几个方法,其中就有 save 方法。

单条保存源码流程。

           

 

批量保存

 

可以看到如果是新增数据(没有设置ID),用save 其实也是走的 insert方法。
 

Mongodb insert 与 save 的区别说明

  insert:当主键"_id"在集合中存在时,不做任何处理。 抛异常

  save:当主键"_id"在集合中存在时,进行更新。 数据整体都会更新 ,新数据会替换掉原数据 ID 以外的所有数据。如ID 不存在就新增一条数据

       save 方法 需要遍历列表,一个个插入, 而 insert 方法 是直接批量插入  

 

posted @ 2018-10-31 19:16  atliwen  阅读(2212)  评论(0编辑  收藏  举报