HICSC
MongoDB多文档事务

前面提到过,MongoDB从4.0开始支持复制集下的多文档事务,从4.2开始支持分片集群下的多文档事务。至此,MongoDB才算是完全支持多文档事务。但这并不代表大家可以毫无节制地使用它,相反,对事务的使用原则应该是:能不用就不用。因为事务的底层实现就是使用锁,而分布式环境下的事务,还有复杂的节点协调机制,额外开销巨大,对性能存在严重的影响。因此,我们应当尽量通过合理的文档设计,来规避使用事务的必要性。

多文档事务

MongoDB的多文档事务可以跨文档、集合以及数据库。当事务提交时,将执行并保存在事务中所做的所有数据更新。如果事务中有任何操作失败,事务中止,事务中所有数据更新操作都将被丢弃。在事务提交之前,事务中的写入或更新操作在事务外部不可见。

MongoDB的事务错误处理机制也不同于关系数据库:

MongoDB默认事务隔离级别是读已提交,即事务完成前,事务外的操作对该事务所做的修改不可访问。而事务内部则是可重复读级别,即事务内可以读到该事务内之前的所有修改,这点其实跟关系数据库是一致的。

MongoDB多文档事务的使用方式也与关系数据库非常相似,都是类似的3段式流程:

try (ClientSession clientSession = client.startSession()) { 
        // 开启事务
        clientSession.startTransaction(); 
        // 操作数据
        collection.insertOne(clientSession, docOne); 
        collection.insertOne(clientSession, docTwo); 
        // 提交事务
        clientSession.commitTransaction(); 
} 

最后是使用多文档事务的几点注意事项:

  1. MongoDB4.2开始才是全面支持多文档事务,且需要与之匹配的驱动,在使用前请确保使用正确的版本和驱动
  2. 在Spring项目中开启多文档事务,与使用MySQL的关系型数据库类似,只需要在合适的位置正确使用注解即可
  3. 事务默认在60s内完成,否则将被取消
  4. 事务会影响chunk迁移效率,正在迁移的chunk也可能造成事务提交失败(重试即可)
  5. 多文档事务中的读操作必须使用主节点读
  6. ReadConcern只应该在事务级别设置,不能设置在每次读写操作上

事务操作的最佳实践

连接到 MongoDB
// 连接到复制集 
mongodb://节点1,节点2,节点3.../database?[options]
// 连接到分片集 
mongodb://mongos1,mongos2,mongos3.../database?[options] 

常见的连接字符串参数有:

不要在mongos前面使用负载均衡

基于前面提到的原因,驱动已经知晓在不同的mongos之间实现负载均衡,而复制集则需要根据节点的角色来选择发送请求的目标。如果在mongos或复制集上层部署负载均衡:

因此,不要在mongos或复制集上层放置负载均衡器,让驱动处理负载均衡和自动故障恢复。

查询以及索引
写入
文档结构
分页问题
事务

除了前面的连接字符串和负载相关的内容,有没有发现,这些最佳实践其实也适用于MySQL等关系数据库,甚至它们在原理上都是类似的,比如分页问题,在MySQL(innodb)中计算count也是一样的耗时;数据量大时,skip一个很大的页码页非常慢。再比如事务问题,都是尽量不使用事务,如必须使用也需要尽量缩小事务的范围。

本文内容参考:极客时间 - MongoDB高手课,对原课程中的相关内容作了增补

Comments

Post a Message

人生在世,错别字在所难免,无需纠正。

提交评论