当前位置: 首页 > 科技观察

一起来学习下mongodb卷的事务

时间:2023-03-12 08:19:32 科技观察

前言Transaction是mongoDB中非常核心的一个功能。4.0版本之前,mongoDB只支持单文档的事务。在4.0和4.2版本之后,支持副本集事务和split,也可以说是大部分数据库中非常重要的功能,值得单独开一章来讲解。那么“mongoDB中如何合理使用事务来保证数据安全”呢?后面会从读、写、多文档事务三个方向进行讲解。写事务使用writeConcern来确保数据准确地放在磁盘上。writeConcern中有两个选项。w(决定一条数据落在多少个节点才算真正写入成功)。0:不关心(最不安全)。Number:写入n个节点才算成功(自定义)。majority:写入至少一半的节点被认为是成功的(推荐,性能和安全平衡)。all:全部写完才算成功(性能差,很安全,但只要有一个失败,就失败)。j(决定什么才是真正的成功)。true:写入日志日志被认为是成功的。false:认为写入内存成功。db.collection.insert({a:1},{writeConcen:{w:"majority",j:true});对于一些“常用数据可以使用w:1保证最佳性能”,对于“重要数据可以使用w:majority保证数据安全”。读取事务readPreference以确定从哪里读取。readPreference有几个属性。primary:只从主节点读取。primaryPreferred:先读取主节点,如果宕机再读取从节点。secondary:只从从节点读取。secondaryPreferred:先读从节点,挂了再读主节点。nearest:读取最近的节点。“primiry和primaryPreferred适用于对延迟敏感的读取数据”,比如订单信息。“secondary和secondaryPreferred适用于延迟敏感度要求低的数据”,比如日志信息。“nearest适用于业务领域广泛的应用”,比如向全球节点同步业务信息,“中国用户访问中国节点,俄罗斯用户访问俄罗斯节点”,nearest的判断也比较很简单,直接用mongo服务器上应用的ping时间来判断。当然,还有一种方法可以“标记服务器”,例如将读取操作定向到标记为“name”:“a”和“key”:“person”:db的辅助节点集合。collection.find({}).readPref("secondary",[{"name":"a","key":"person"}])readConcern来判断可以读取什么样的数据。readConcern有几个属性。可用:读取所有可用数据。loacl:读取所有只属于当前分片的可用数据。majority:读取大多数节点写入的数据。“通过快照维护多个不同的版本,使用MVCC来实现”,每个被大多数节点确认的数据都是一个快照。linearizable:文档可以线性读取。有时会阻塞,这保证了如果一个线程已经写完并通知其他线程,那么其他线程就可以看到这些变化。如果某个时刻你的副本集中有两个primary节点(一个还没有降级),你从旧的primary节点上读取,同时新的primary节点上有新的数据,你读取的数据是旧数据。snapshot:读取快照中的数据(类似于serializable)。loacl和available的区别体现在分片集群中的chunk迁移上。如果读shard2,loacl读不到x,available可以。多文档事务mongoDB4.0版本支持副本集的多文档事务。4.2版mongoDB支持分片集群中的多文档事务。也就是说,mongoDB在4.2版本就具备了与mysql等关系型数据库相同的事务能力,从业务选型的角度为mongoDB增添了浓墨重彩的一笔。在整个数据库的分布式事务中,最值得一提的就是时间问题。我们先看看会存在哪些问题。例如,有两个操作发送到节点a和b。客户端向节点a和b发送a=1。a=1的节点操作。客户端向节点a和b发送a=a+1。a节点操作a=a+1,b节点由于业务网络等原因先执行a=a+1,然后操作a=1。最后发现a和b两个节点的数据不一致,那么mongo是怎么解决的呢?一般有两种方式:“全局定时”:;例如,我们可以使用GPS时钟或NTP服务点等全球定时。“逻辑时钟”:即我们使用部分时间戳来进化。这称为逻辑时钟。Mongo使用“混合逻辑时钟”:在这种混合逻辑时钟中,将物理时钟和逻辑时钟混合在一起,做一个全局时间进行处理。我们的混合逻辑时钟将采用本地推进方法。这就是刚才说的验收时间。它会比较本地时间戳,然后比较本地时间戳、本地真实物理时间和收到最短请求的时间,“取三者中最大的时间作为本地时间的推进”,需要注意的是,这个时间戳的分布取决于oplog的时间戳。只是“当oplog真正写入数据时,本地逻辑时钟会提前”。在整个混合逻辑时钟中,在整个集群中采用了一种动态推进的方式,“每一次发送和接收的请求都会根据请求中的时间推进本地时钟”,这样在全局的情况下,每个节点的混合逻辑时钟最终会收敛,趋向于相同的地址,并趋向于相同的时间。这样的话,刚才说的时间偏差就不存在了,分布式事务才能在集群中做。下面说说mongo提交交易的流程。MongoDb的分布式事务和mysql一样,也是基于“两阶段协议”。第一阶段是准备阶段。在准备过程中,所有协调器都会向所有节点发送准备命令,所有节点收到该命令后都会返回自己的准备时间戳,然后协调器节点将决定选择最大的准备时间作为提交时间戳。协调者与所有分片之间的通信将促使所有交易参与者获得一个协调的HLC。在这种逻辑时钟一致性的情况下,提交时间戳是全局顺序一致的。第二阶段是提交阶段。协调器会把刚才提交的ts作为提交时间戳的时间戳,然后广播给所有节点。需要注意的一点是,在读取带有preparetimestamp的事务时,如果当前事务处于prepare状态,并且不确定自己读取的时间戳和prepare状态的大小,则需要等待事务.等到事务被提交或中止,它才会被处理。这就是我刚才说的。https://mongoing.com/archives/77608。巨人的肩膀。mongoDB实现整个事务的方式是按照“读提交”的关系来设计的,也就是说客户端在读取数据时,只能读取事务节点之前已经提交的数据。