执行一次怎么会写入两次数据_NoSQL 数据库应不应该放弃 一致性原则?

在设计系统时,我们总是避免“不一致”现象,然而,若要真正做到这一点,通常需要放弃系统中的其它一些特性,而那些特性却是必不可少的。如此说来,我们就需要放弃一定的一致性来换取其它的特性。因为其它的 那些是必不可少的啊。某些架构师把这当成这种灾难,而笔者却把其视为系统设计中必须面对的平衡。此外,各个领域对“不一致性”的容忍度也不同,所以在决策时要考虑容忍度这一因素。

前面已经提到过,催生NoSQL的主要原因是:需要一种能够运行在大集群上的数据库。但是从关系型数据库迁移到面向集群的Nosql数据库,最大的一个改变就是针对一致性的思考方式。关系型数据库通过“强一致性”避免各种问题,而NoSQL并非如此。

6cfced09ff44eee53a5f84a1e07e3b42.png

1、更新一致性

更新一致性:两个用户同时修改同一份数据,会发生“写冲突”。服务器肯定会以特定顺序处理这两个请求,后者提交更新请求时所依据的数据都不是前者更新过的。

单服务器必定具备更新一致性,可以通过“并发控制机制”来保证一致性,有两种方式:“悲观”方式和“乐观”方式,前者是为了避免冲突,在写入之前先请求加锁,而后者允许冲突,最常见的就是条件更新,即在执行更新操作前先判断数据的当前值是否和上次读入的相同,是则成功更新否则更新失败。单服务器中无论如何数据只能以一种更新顺序被处理,悲观方式和乐观方式都能够用于避免写冲突。

悲观方式

使用写锁大幅降低系统响应能力可能导致死锁

乐观方式

先让冲突发生,再检测顺序自动合并的处理方式极具“领域特定”问题

分布式环境处理写冲突:

1)如果是“对等复制”的分布模型,同一份数据有多个备份,每个服务器处理更新请求的顺序可能不同,无法使用并发控制机制,将最终造成更新后保存的值不相同。这时可以采取一种叫做“写入仲裁”的方式来避免写冲突,即若发生两个相互冲突的写入操作,只有其中一个操作能为超过半数的节点所认可。

2)如果是“主从复制”分布模型,采取的方法是:将某份数据的所有更新操作都交由一个节点执行,通过并发控制机制保证更新一致性。

2、读取一致性

逻辑一致性:某客户端在另一个客户端两次写入操作之间读取数据,则会造成逻辑不一致,即通常所说的“读写冲突”。考虑一个包含商品项和运费的订单,运费是根据订单中商品项计算而来,B用户可以读取订单,而A用户可以更新订单,A用户更新订单时会先更新了其中商品项,再更新运费,恰巧在两个写入操作之间B用户读出订单,就会导致读取不一致问题,这就是读写冲突现象。

关系型数据库通过“事务”这个概念,将两个写入操作封装到一个事务中,确保其它用户读出的数据要么是事务执行之前的值,要么是事务执行之后的值。而大多数NoSQL数据库,尤其是面向聚合的数据库不支持事务,但是聚合数据单元支持“原子更新”,所以聚合内部可以保持读取一致性,可以将商品项和运费都放在一个订单聚合中。很显然我们不可能将所有数据放入一个聚合,当涉及多个聚合的更新操作时,无法保证逻辑一致性。这时两个聚合的更新操作之间会留下一个时间空档,称为“不一致窗口”。

3、复制一致性

一旦引入“复制”机制,将会引发另一中不一致性,即从不同的副本获取同一个数据项时,得到的值不同。假设某个酒店的在线订房,最后只剩下一间房间,分隔伦敦和洛杉矶两地的A和B两夫妻在电话讨论要不要订这间房,此时C在北京将这间房订下,但是这个更新的数据到达洛杉矶副本的时间比到达伦敦副本的时间早,这就导致A和B再次打开浏览器看到不一样的结果,这又是一个读取不一致问题,同样涉及到多个副本的更新操作时,也会留下一个“不一致窗口”。

解决复制一致性:

1)若是“对等复制”分布模型,可以采取一种叫做“读取仲裁”的方式;

2)若是“主从复制”分布模型,只需从主节点读取数据就好了。

当然复制模型中更新操作最终还是会传播到所有副本中,这就是所谓的“最终一致性”,即出现复制不一致时,只要不再继续执行其它的更新操作,那么上一次的更新操作最终总会反应到全部节点中。这里要注意,缓存也是一种“复制”形式。

注意:虽然“复制一致性”和“逻辑一致性”是两个相互独立的问题,但是如果“复制”过程中的“不一致窗口”太长,同样会加剧“逻辑不一致”问题。

4、放宽一致性约束

要真正做到一致性,必须放弃系统中的其他一些特性,而这些特性偏偏可能是必不可少的,因此通常需要针对不同场景牺牲一定的一致性来保障其他特性。比如单服务器关系型数据库中通过事务保证较强的一致性,然而事务系统通常又具备放松“隔离级别”的功能,甚至有的关系型数据库为了追求性能可以完全放弃事务。

CAP理论:这是NoSQL领域中需要放宽一致性约束的原因。此定理的基本表述是:在一致性(Consistency)、可用性(Availability)、分区忍受性(Partitiontolerance)三个属性中,最多只能同时满足其中两个。

 u一致性:即前面提到的更新一致性、读取一致性、复制一致性等。 u可用性:分布式系统中某个无故障节点所接收的每一个请求,无论成功或是失败都必将得到响应。u分区忍受性:发生脑裂是集群仍然可用。脑裂即通信故障导致集群被分割成多个无法相互通信的网络分区。

CAP理论本质:一旦发生脑裂,集群就不可用,这个代价是非常巨大的,因此集群必须要满足“分区忍受性”,即发生脑裂时系统仍然可用。这就是CAP的精髓,CAP又可以表述为:“当分布式系统可能会遭遇脑裂时,我们需要在一致性和可用性之间做一个权衡”。

特别注意,这并不是一个二选一的过程,通常情况下我们都会略微舍弃“一致性”,以获取某种程度的“可用性”,这样产生的系统几部具备完美的可用性也不具备完美的一致性,两种不完美结合起来,却能够满足特定需求。

可用=延迟合理:回顾一下可用性的含义,其实与其考虑如何权衡“一致性”和“可用性”,如何考虑如何权衡“一致性”和“延迟”,因为无故障节点处理请求时,若超过了能忍受的最大延迟时间,我们就应该放弃操作,认为节点不可用。

放弃强一致性:从前面一致性介绍可以看到,要想保证较强的一致性,“主从分布”模型需要针对主节点进行读写,“对等复制”分布模型需要通过仲裁的方式,参与的节点越多,获得的一致性越强,可见这两种模型下要保证较强一致性都需要在“延迟”上做很大的牺牲。加之分布式环境下允许出现“更新不一致”或者“读取不一致”的场景很多。因此在分布式环境下,通常需要牺牲一定的一致性来获得较低的延迟。

此外、延迟还和持久性相关,可以舍弃一部分“持久性”来减小延迟,比如让数据库大部分时间都在内存中运行,更新操作也直接写入内存,并且定期将数据变更写回磁盘。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值