陈同学
微服务
Accelerator
About
# 理解一致性 最近工作涉及一致性问题,因此对概念加以梳理。将通过一些业务场景抽象出一致性的概念,再聊聊为什么一致性如此重要,最后看看后端常见技术如何保证一致性。 本文不会深究某个技术细节,主要是为了阐述对于一致性概念的理解,文中涉及到的技术概念可自行查阅资料。 ## 不同场景下的一致性 ### 转账场景 这是一个非常经典的场景。假设A有10元,B有0元,A给B转账10元,转账成功后,A有0元,B有10元,我们会说这个结果符合一致性。 假如转账成功后,A扣减了10元,余额为0;B却没有收到钱,余额也为0,我们会说这不符合一致性。 那我们判断符合一致性的依据是什么?表面上看依据是:**转账之后A、B账户总额为10元**。 假如转账10元后,A、B账户余额分别为3元、7元,AB账户金额总和为10元,但我们根据常识就能判断,这不对! 因此,判断一致性的依据可以是:**转账操作,转出方扣减的钱与接收方新增的钱应当相等**。 ### 销售指标场景 > 这个场景完全脱离技术,可以思考 假设某公司销售团队本财年的业绩指标为销售额达到1亿,年底时,若销售额为8千万,Boss可能说还不错;若销售额为1亿,Boss可能开心的在年会表扬,咱圆满的完成了销售任务,团队提成丰厚;若销售额为2亿,Boss可能单独和大家吃饭,再发上高额提成。 那这里有一致性问题吗?一致性的规则又是什么? 我们假定一致性判断规则:**如果销售额达到指标的70%,就符合一致性**。因为销售指标总是夸大的,或者说是个努力的目标,假设达到70%就很不错。 那么,年底销售额8千万、1亿、2亿都符合一致性规则,假如销售额是1千万,公司可能因此垮掉,那么就不符合预期,造成了严重后果。 ### 秒杀场景 假设商品库存100,1万人参与秒杀。 假如卖出商品数量超过100,我们认为这不符合一致性。那这里的一致性规则是:**商品不能超卖,最多卖出100件**。 ## 什么是一致性? > 参考 [Data Consistency Primer](https://msdn.microsoft.com/en-us/library/dn589800.aspx) 通过上面三个场景,可以发现不同场景下 **一致性** 的规则并不相同。换句话说,**一致性指的就是最终的结果是否和设定的规则保持一致!** 因信息技术的发展,现在数据都直接存储计算机中(如数据库、磁盘等),因此`技术人员聊的一致性往往指数据一致性`。 但计算机世界里难免出现问题,如:业务程序BUG、软件崩溃、机房损毁、光缆挖断等,但现实世界(商务世界)中首先是不允许出现数据问题,其次是不关心技术故障。因此,**数据的一致性(即能得到符合规则的结果)就成了重中之重**。 ## 保证数据一致性的技术手段 这里列举一些常见的保证数据一致性的技术手段或理论。 ### 关系型数据库事务的一致性 我们最为熟知的就是事务的ACID特性,即原子性、一致性、隔离性、持久性。 原子性、隔离性、持久性最终的目的就是为了保证一致性。 ### Mysql与一致性 Mysql保证数据一致性的手段很多,例如: * 应用与Myql交互时,通过锁机制保障一致性 例如:更新数据时通过`排他锁` 锁定行记录,保证在数据修改期间没有其他事务更新该纪录。 * Mysql事务的隔离级别 通过不同隔离级别解决并发操作时数据的脏读、幻读、不可重复读问题。 * InnoDB引擎的日志机制 通过undo日志、redo日志来保证事务的原子性和持久性,确保事务要么全部执行,要么全部回滚,同时在故障情况下也能保证数据成功持久化。 ### 乐观锁与悲观锁 乐观锁与悲观锁是一种思想,具体的实现有很多。因我们经常接触到这两种锁机制,因此这里单独拿出来举例。 * 乐观锁例子 表设计时经常会加入 **版本(version)** 字段用于应用层的乐观锁实现,在更新数据之前,我们会比对数据库中记录的版本与当前记录的版本,如果版本一致,说明数据未被修改;否则应用层应当抛出异常。 这种方式避免了我们读到过期的脏数据,从而保证数据一致性。 * 悲观锁例子1 Mysql的排他锁,在修改数据之前直接锁定行记录,在自己操作数据期间不允许其他事务修改数据。 * 悲观锁例子2 Java中的锁机制,例如:synchronized关键字、对象锁、类锁都可以看作悲观锁,通过锁机制保护共享资源(或称为临界区)。 ### 分布式与一致性 分布式场景下,事务的一致性变得更加复杂。 * Mysql这种数据库提供了分布式事务。 * 随着微服务思想的流行,现在越来越多平台基于微服务理念进行实施。此时,更多的是通过最终一致性方案来保障数据的一致性。 ### 并发环境下的一致性 以Java多线程为例,由于线程之间会共享主存,因此非原子操作极容易出现类似于DB的“脏读”情况。A线程把某变量从主存读到工作内存准备修改,B线程立马就把主存的变量值改了,此时A线程工作内存中的变量便成了脏数据。 因此Java提供了`Volatile`关键字,通过保障`可见性`从而保证最终数据的一致性。 ## 总结 为了保障数据一致性,不同的场景下有不同的技术手段。 作为开发人员,一方面需要理解数据一致性的概念,另一方面也可以结合工作或兴趣专门学习某种一致性的技术实现。 技术最终是服务于现实世界,因此技术理念大多也是基于现实场景而产生,理解技术理念时不应局限在纯技术中。
本文由
cyj
创作,可自由转载、引用,但需署名作者且注明文章出处。
文章标题:
理解一致性
文章链接:
https://chenyongjun.vip/articles/23
扫码或搜索 cyjrun 关注微信公众号, 结伴学习, 一起努力