定义
先来说一下标题中的一些词的定义:
微服务
微服务是一种系统的架构设计方式,微服务将传统的单应用程序的功能拆分成多个微小的应用程序,每块微服务各完成一定的功能业务。
微服务的优点:
- 微服务比起传统单应用程序更加轻量化,每个模块可以由单独的开发团队开发,每个团队可以有不同的技术栈,降低了粒度,提高了开发效率,更加适合于敏捷开发;
- 微服务将各个系统的模块拆分开,每个模块可以独立的开发,运行和部署,使得整个系统间耦合性大大降低;
- 微服务的各个功能模块可以独立部署,为系统的横向扩展提供了可能,增加了整个系统的吞吐量。
微服务的缺点:
- 采用微服务的设计架构相较于传统的单应用程序,其系统复杂程度更高,升级到微服务后,就引入了很多单应用程序不会涉及到的问题,而本文要讲的分布式事务就是其中一个;
- 微服务的多个模块独立部署和运行,这大大增加了运维的成本。
分布式
分布式顾名思义,其实就是将各个系统组件分开部署,是一种部署方式,我们的微服务即是采用分布式这样的部署方式,因此分布式部署是微服务应用程序的一种表现。但请注意,采用分布式部署的系统不一定是微服务应用。
事务
事务给我们最直观的感受就是一系列操作要么全部执行,要么一个都不执行。举个例子:
你去银行取钱,要么是钱取出来了,余额扣掉了,要么是ATM机没现钞了,余额没有扣掉。
这样的话才显得正常,如果取了钱不扣余额或者是没有取到钱但是余额却扣除了,这其实就是没有事务的支持。但是事务不仅仅如此。
说到事务,我们接触的最多的应该是数据库的事务。(还记得innodb和myisam对事务支持的区别吗)
首当其冲的是数据库事务的特性,acid你们都还记得吗?
-
A(原子性Atomicity)
学过化学的都知道,原子是一次反应的最小单位,任何原子都是最小不可分割的,事务同样也是。原子性要求一系列的事务的执行不可分割,要么全部执行,要么都不执行。 -
C(一致性Consistency)
一致性要求事务的前后状态都是满足数据库的结构要求并且数据正确的。举个例子:用户A准备从银行取100元,他的账号中余额有99元,我们的数据库规定余额最小不能为负数,那么在执行事务后,他的账户余额将变成-1元,这是不符合一致性原则的,因此此次事务将失败回滚。 -
I(隔离性Isolation)
隔离性要求事务间的操作相互独立,即数据库事务隔离级别最小为读已提交,各个事务需要互不影响。举个例子:用户A准备从银行取100元,用户B也准备从银行取100元,他们各自取出钱后扣取了各自账号的余额,完成取钱过程。 -
D(持久性Durability)
持久性要求事务的结果是持久化的,即使数据库宕机后也能保证此次的数据不会丢失,举个例子:用户A准备从银行取100元,他取出钱后扣取了账号的余额,完成取钱过程。在这之后数据库因为某种原因宕机了,在系统恢复之后,这次的取钱记录仍然在数据库中可查并且他的余额是正确的。
数据库事务为我们提供了十分方便的事务解决方案,我们仅需要在应用层中对数据库的事务源进行管理,就可以很轻松的实现事务。
这个即是单应用事务,这种事务实现起来是十分简单的,事务由本地事务管理器实现,这种事务是强一致性的,即一旦事务提交,所有的读都能立即读到最新数据。
分布式事务
如果我们的系统采用分布式部署,这时候就会引入分布式事务的问题。相较于单应用的本地事务,分布式事务的实现需要更加复杂的系统设计,下面看两种分布式事务的场景:
单应用多数据源
对于在单应用中使用了多数据源的情况,多数据源之间就存在了分布式事务的问题,这种情况就需要使用事务管理器对多个数据源进行同意的管理,这个系统复杂度还不算高。举个例子:
用户A在中国银行执行行内转账,从自己的账户中转100元到用户B的账户中去。(我们假设银行业务系统中内部转账功能是单应用模块多数据源的)此时用户A的账户信息在数据库A中,而用户B的账户信息在数据库B中,此时数据库A和B就会存在分布式事务的问题。
多应用多数据源
一旦涉及到某个业务需要多个系统模块或多个应用来完成,且每个模块或应用都使用不同的数据源,这时候如果要解决事务问题就会比较复杂。举个例子:
用户A在中国银行执行跨行转账,从自己的中国银行账户中转100元到自己的邮政银行账户中去。此时中国银行内部需要调用自身的扣余额接口和邮政银行的增余额接口,此时就会面临涉及到多个应用的分布式问题。
解决方案
对于单应用而言,数据库的事务支持满足我们的需求已经绰绰有余,但是对于微服务,数据库的acid已经不能满足。
这时候有人提出了新的理论:CAP理论
- C(一致性Consistency)
一致性要求分布式系统间的数据在一个节点写入后,能够立即在其他节点读出来。 - A(可用性Availability)
可用性要求分布式系统提供的每一个服务都处于可用的状态,必须在有限的时间内返回合适的响应(注意不是超时或者错误响应) - P(分区容错性Partition tolerance)
分区容错性要求系统某些节点在网络异常的情况下,整个系统仍然能够提供满足CA的服务。
但是CAP理论对于分布式系统而言,现在还没有一套架构能够同时满足CAP的三个要求。因此对于分布式来说,一般的都是满足BASE理论:
- BA(Basically Available基本可用)
在分布式系统出现问题时,允许部分服务不可用,而核心功能可用。 - S(Soft state软状态)
相对于CAP中的C,允许系统存在中间状态。 - E(Eventually consistent 最终一致性)
对于系统的中间状态,要求其在一定时间内到达最终状态且各个节点数据一致。
对于CAP理论来说,目前的分布式系统还不能完全满足(满足CP如eureka,满足AP如zookeeper),因此对于分布式系统我们要求必须遵循base理论。我们的分布式事务解决方案即是遵循BASE理论,采用最终以执行原则来实现事务。
2pc
2pc是解决单应用多数据源的解决方案。参与者A和B分别是分布式的两个数据源,协调者是用来管理参与者A,B的事务管理器。参与者A和B作为数据源,遵循了XA协议
A协议由Tuxedo首先提出的,并交给X/Open组织,作为资源管理器(数据库)与事务管理器的接口标准。目前,Oracle、Informix、DB2和Sybase等各大数据库厂家都提供对XA的支持。XA协议采用两阶段提交方式来管理分布式事务。XA接口提供资源管理器与事务管理器之间进行通信的标准接口。 ————百度百科
我们常用的mysql的innodb引擎就是遵循了XA协议的,因此我们的协调者通过XA提供的接口与数据库通讯,藉此实现分布式事务的管理。
直接上架构图:

2pc优点:
- 1.架构简单,与参与者通讯由XA保证
- 2.不需要更改原先系统逻辑
2pc缺点:
- 1.数据库层的事务,锁粒度难以控制
- 2.在通知所有参与者后需要同步等待参与者的执行结果,效率低
- 3.协调过程期间所有参与者需锁定事务资源直到收到协调者决断结果,整个过程任何一个节点故障或网络波动均会导致事务锁的长期占用,成本高,可用性低。
- 4.决断结果可能出现消息丢失导致数据幂等问题
TCC
2pc是基于数据库层面的事务,那么涉及到应用层事务,我们就可以用tcc(try/confirm/cancel),直接上图:

参与者A,B是两个不同的应用,当有事务发起者执行某逻辑而调用参与者A,B时,事务发起者会首先调用A,B的try接口(这就需要应用的支持),事务发起者在通知try完成后等待反馈,根据反馈的结果决定下一步是执行confirm还是cancel。
TCC优点:
- 1.执行流程简单
- 2.应用层的事务操作,可以自定义事务锁粒度。
TCC缺点:
- 1.需要参与者提供相应的try,confirm,cancel接口,存在局限性
- 2.整个过程认为confirm/cancel是一定成功的,若要增加可用性只能采取重试或人工补偿
本地消息表
本地消息表提供了一种更加简单的架构方式,巧妙地将分布式事务问题转化成本地事务问题从而解决分布式事务,直接上图:

本地消息表需要在每一个业务逻辑上增加一张事务记录表,每次执行分布式事务时,将分布式事务存储到事务记录表中,通过本地事务来确保其他业务与本地事务表的正确执行。同时采用MQ推送机制,将事务记录表中的待完成事务通知对应的事务参与者执行,并进行适当的重试机制,在成功执行后将这条事务标记为已完成状态。为确保高可用,还可用对事务记录表定时扫描并执行。
本地消息表优点:
- 1.分布式事务本地化
本地消息表缺点:
- 1.每个服务需要额外创建本地消息表,增加了复杂度
- 2.需要定时任务扫描本地消息表并执行重试补偿或人工修正操作
- 3.柔性事务,没有强一致性
RocketMQ
rocketMQ提供了分布式事务解决方案,其原理就是本地消息表,只是MQ中代替应用程序存放了本地消息表。
结语
本地事务问题已经是比较影响系统性能的,更不用说分布式事务了,一旦上升到分布式事务问题,系统会因此付出较大的性能代价。分布式事务解决方案中基本都是在将分布式事务转化为本地事务。因此,如果业务涉及到分布式事务问题,采用分布式事务前最好先思考一遍,是不是真的需要事务,能不能避免分布式事务,因为分布式事务代价高,架构复杂,难于管理维护。
探讨微服务架构下分布式事务的挑战与解决方案,包括2PC、TCC、本地消息表及RocketMQ的应用。
1843

被折叠的 条评论
为什么被折叠?



