什么事分布式事务: 多个服务同时修改记录时,保证数据的一致性.
现在面试中,分布式系统、分布式事务几乎是标配。而分布式系统、分布式事务本身比较复杂,大家学起来也非常头疼。
首先一张图了解一下分布式部署:
什么是分布式事务?
对于分布式系统而言,需要保证分布式系统中的数据一致性,保证数据在子系统中始终保持一致,避免业务出现问题。分布式系统中对数要么一起成功,要么一起失败,必须是一个整体性的事务。
分布式事务指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。
简单的说,在分布式系统上一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务节点上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。
举个例子:在电商网站中,用户对商品进行下单,需要在订单表中创建一条订单数据,同时需要在库存表中修改当前商品的剩余库存数量,两步操作一个添加,一个修改,我们一定要保证这两步操作一定同时操作成功或失败,否则业务就会出现问题。
任何事务机制在实现时,都应该考虑事务的ACID特性,包括:本地事务、分布式事务。对于分布式事务而言,即使不能都很好的满足,也要考虑支持到什么程度。
分布式思路:
分布式事务场景如何设计系统架构及解决数据一致性问题,个人理解最终方案把握以下原则就可以了,那就是:大事务=小事务(原子事务)+异步(消息通知),解决分布式事务的最好办法其实就是不考虑分布式事务,将一个大的业务进行拆分,整个大的业务流程,转化成若干个小的业务流程,然后通过设计补偿流程从而考虑最终一致性。
What’s 事务
事务(Transaction)及其ACID属性
事务是由一组SQL语句组成的逻辑处理单元,事务具有以下4个属性,通常简称为事务的ACID属性:
原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。
隔离性(Isoation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
持久性(Durabe):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。
通过一个分布式事务场景深入的了解一下:
典型场景:银行转账业务
例如:李雷账户中有500块钱,韩梅梅账户有200块钱,李雷要从自己的账户中转100块钱给韩梅梅,转账(事务)成功执行完成后应该是李雷账户减100变为400,韩梅梅账户加100变为300,不能出现其他情况,即在事务开始和结束时数据都必须保持一致状态(一致性),事务结束时所有的数据及结构都必须是正确的。并且同样的转账操作(同一流水,即一次转账操作)无论执行多少次结果都相同(幂等性)。
电商场景:流量充值业务
再说我们做的一个项目:中国移动-流量充值能力中心,核心业务流程为:
用户进入流量充值商品购买页面,选择流量商品;
购买流量充值商品,有库存限制则判断库存,生成流量购买订单;
选择对应的支付方式(和包、银联、支付宝、微信)进行支付操作;
支付成功后,近实时流量到账即可使用流量商品;
此业务流程看似不是很复杂对吧,不涉及到类似电商业务的实物购买,但是我认为其中的区别并不是很大,只是缺少电商中的物流发货流程,其他流程几乎是一样的,也有库存以及优惠折扣等业务存在。
整个系统交互如下图:
流量中心-架构设计
架构设计思想:在系统初期设计时以及部分硬性环境约束下,我们根据业务拆分为多个子系统(微服务):商品服务、订单服务、库存服务、支付网关、统一接口平台、对账服务、结算服务、网关对接服务等,后续还会增加:账户服务、虚拟货币服务、卡券服务等等…。按照微服务的核心设计思想,所有服务完全独立、隔离,因此所有服务从上至下:请求接入(连接管理)、请求处理(计算服务)、数据存储(存储服务)进行拆分,接入与计算尽最大可能实现无状态,数据存储进行垂直+水平拆分,垂直拆分:商品库-mysql(读多写少,主从架构+读写分离)+redis(读多写少,集群方式)、订单库-mysql(读写均衡,多主多从+水平拆分)、库存专用库-redis(分布式+主备容灾)、外部交易系统-支付网关、外部办理系统-统一接口平台。
Ps:此架构目前已支撑总交易额3.6亿,总订单4680万,日均交易额500万,日订单量50万,后续业务量持续增加的情况下按照微服务思想继续拆分,例如将订单服务再拆分为:下单服务、查单服务,直到根据业务需求与系统关系耦合性拆分到最细粒度为止。
性能扩展:应用层计算服务(无状态应用)通过增加服务节点同比提升运算性能,配套质量(性能)监控服务dubbo monitor及整合Netflix的Hystrix熔断器对业务质量进行管理实现应用层的动态扩缩容。
容量扩展:数据层存储服务(有状态应用)通过对数据水平拆分实现容量的无限扩容,Nosql类方案:Codis中间件;关系型数据库:Mycat数据库分库分表中间件。目前项目中采用twitter的snowflake唯一ID生成器(根据业务场景优化后)自己实现数据的水平拆分和路由规则。
存储性能:Nosql:针对读多写少场景-使用淘宝的Tedis(多写随机读的特性提高性能),读写均衡使用-Codis;Mysql:读多写少场景使用一主多从架构(例如商品信息),读写均衡场景使用多主多从架构(例如订单信息)。
整体拆分原则如下图:
经常被问的面试题:
1、分布式事务与分布式锁的区别?
分布式锁解决的是分布式资源抢占的问题;分布式事务和本地事务是解决流程化提交问题。
2、事务的四个特征?
1、Atomic原子性
事务必须是一个原子的操作序列单元,事务中包含的各项操作在一次执行过程中,要么全部执行成功,要么全部不执行,任何一项失败,整个事务回滚,只有全部都执行成功,整个事务才算成功。
2、Consistency一致性
事务的执行不能破坏数据库数据的完整性和一致性,事务在执行之前和之后,数据库都必须处于一致性状态。
3、Isolation隔离性
在并发环境中,并发的事务是相互隔离的,一个事务的执行不能被其他事务干扰。即不同的事务并发操纵相同的数据时,每个事务都有各自完整的数据空间,即一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能相互干扰。
SQL中的4个事务隔离级别:
(1)读未提交
允许脏读。如果一个事务正在处理某一数据,并对其进行了更新,但同时尚未完成事务,因此事务没有提交,与此同时,允许另一个事务也能够访问该数据。例如A将变量n从0累加到10才提交事务,此时B可能读到n变量从0到10之间的所有中间值。
(2)读已提交
允许不可重复读。只允许读到已经提交的数据。即事务A在将n从0累加到10的过程中,B无法看到n的中间值,之中只能看到10。同时有事务C进行从10到20的累加,此时B在同一个事务内再次读时,读到的是20。
(3)可重复读
允许幻读。保证在事务处理过程中,多次读取同一个数据时,其值都和事务开始时刻时是一致的。禁止脏读、不可重复读。幻读即同样的事务操作,在前后两个时间段内执行对同一个数据项的读取,可能出现不一致的结果。保证B在同一个事务内,多次读取n的值,读到的都是初始值0。幻读,就是不同事务,读到的n的数据可能是0,可能10,可能是20
(4)串行化
最严格的事务,要求所有事务被串行执行,不能并发执行。
如果不对事务进行并发控制,我们看看数据库并发操作是会有那些异常情形
(1)一类丢失更新:两个事物读同一数据,一个修改字段1,一个修改字段2,后提交的恢复了先提交修改的字段。
(2)二类丢失更新:两个事物读同一数据,都修改同一字段,后提交的覆盖了先提交的修改。
(3)脏读:读到了未提交的值,万一该事物回滚,则产生脏读。
(4)不可重复读:两个查询之间,被另外一个事务修改了数据的内容,产生内容的不一致。
(5)幻读:两个查询之间,被另外一个事务插入或删除了记录,产生结果集的不一致。
4、Durability持久性
持久性(durability):持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中对应数据的状态变更就应该是永久性的。
即使发生系统崩溃或机器宕机,只要数据库能够重新启动,那么一定能够将其恢复到事务成功结束时的状态。
。。。。。。。。。。。。。。。。。。
更多面试题下一个文章分享给大家