分布式事务

ACID和BASE

ACID是指原子性(Atomic)、一致性(Consistency)、隔离性(Isolation)、持久性(Duration)。

  • 原子性 事务中的所有操作要么都成功要么都失败
  • 一致性 外界访问数据库中的数据时,不会访问到事物的中间状态,只会访问到最终的状态
  • 隔离性 事务之间不会相互影响,避免脏读、幻读给业务带来数据不一致问题
  • 持久性 事务一旦执行成功,其最终状态会被持久化存储下来,不会失效。

BASE是指基本可用(Base Available)、柔性状态(Soft State)、最终一致性(Eventual Consistency)。

  • 基本可用 是指分布式系统出现故障时,允许损失部分可用性,保障系统基本可用。
  • 柔性状态 是指允许系统出现中间状态,而该中间系统并不会影响系统的整体可用性。
  • 最终一致性 系统在经过一段时间之后,系统中的所有副本最终会达到一致的状态。

ACID和BASE代表了两种截然相反的设计哲学。ACID是传统数据库常用的设计理念,追求强一致性模型;BASE支持的是高效的分布式数据库,通过牺牲强一致性来获得高可用性。不同的业务场景对数据的一致性要求不一样,因此这两种设计理念也可能会结合在一起使用。

分布式系统内通信和单机内通信的最大区别是:单机不会丢信息,而分布式系统可能会丢失。一台机器通过网络向另外一台机器发送消息的结果可能是成功、失败、不知道成没成功,这也是分布式系统数据同步代价高昂的原因。

共识算法

副本的一致性。Paxos、Zab、Raft解决的是副本在多节点的同步问题。读写流量走的都是leader。这会产生一些问题:

  • 如果直接读取follower,可能读取的不是最新数据
  • 如果为了最新的数据,读写流量都走leader,则leader的负载会远高于follower
  • 如果出现了网络分区,出现两个leader,则从leader读取的数据也可能不是最新的

柔性事务如何解决分布式事务问题

引入日志和补偿机制

类似传统数据库,柔性事务的原子性也是由日志来保证,例如mysql的事务。事务日志记录事务的状态、参与者。参与者节点记录当前操作的对应的REDO或者UNDO日志。当事务重试、回滚时,可以根据这些日志最终将数据恢复到一致状态。

为了避免单点故障,事务日志是记录在分布式节点上的。REDO/UNDO日志一般记录在业务数据库(参与者节点)上的,可以保证节点操作与日志记录同时成功或者失败。当事务失败时,可以根据日志记录找回事务当前的执行状态,来决定是重试异常步骤(正向补偿),还是回滚(反向补偿)。

可靠消息传递

在分布式环境下,由于“网络危险期”的存在,节点间的消息传递可能出现成功、失败、不知道成功还是失败三种状态。这给分布式事务的处理带来了非常大难题,解决这个问题就需要使节点之间的消息能可靠的进行传递。

当出现不知道成功还是失败的状态时,只有两种处理方法:1. 重复投递一次(至少一次);2. 不重复投递 (至多一次)。在分布式事务处理过程中显然不能使用第二种处理方法,不然会丢失数据,就只能选择第一种方法。

至少一次的处理方法虽然不会丢失数据,但可能会使一条消息被重复处理。这也会造成问题,例如重复添加记录、重复扣款。这就需要处理程序必须实现幂等操作,对一个数据处理一次和多次结果一样。幂等的实现方式有很多种,需要结合业务来实现。如果是插入数据库,可以根据主键来实现幂等;如果是确定性计算并且数据是覆盖操作,则原生就是幂等的;消息里有唯一主键,消息处理程序根据唯一主键来进行去重。

实现无锁

不是特别明白这个处理方式和分布式事务的关系在哪里,这个处理方式只是为了高性能而已

造成数据库性能和吞吐的瓶颈主要是强事务(传统数据库的事务、阶段提交)带来的资源锁。因此避免事务的加锁是数据库高性能的关键,尤其是长时间事务。无锁是一个解决方法,但是事务隔离是仍然要考虑的一个问题。如果没有事务隔离,可能会出现数据的脏读、幻读,这在业务是不可接受的事情。

实现事务隔离的方法有多种,选择何种隔离方法应结合业务。

  • 事务避免进行回滚 当事务异常时,如果不进行回滚也能满足业务的要求,也就是事务的中间状态即使被外界感知到也不会影响到业务的正常流程。由于事务不会回滚,因此不会出现脏读。
  • 辅助业务变化明细表
  • 乐观锁

TODO: 对无锁的实现方式和分布式事务之间的关系,以及分布式无锁化的实现方式需要进一步查询资料。

分布式事务的实现方法

分布式事务的实现可以具体场景的维度来分析,分布式数据库的事务实现方法(tidb、zookeeper)和业务场景上(交易场景)的分布式事务可能就截然不同。

像tidb、zookeeper要求的是强一致性,中间状态不会被外部感知到,会损耗部分性能来达到数据的强一致性。而业务场景上,对性能要求很高,通常可以将一个大的事务分割成很多小的事务,中间状态可以被外部感知到,只要达到最终的一致性就可以。交易场景下,就可以分割成下单、扣减库存、支付等更细粒度的场景。所以在谈一个分布式事务的时候,应该具体问题具体分析。

强一致性分布式事务和柔性分布式事务的实现也不是完全对立的。一个大的分布式事务局部也可能会使用强一致性事务,而在全局上还是柔性分布式事务的实现方法。例如一个交易场景中,库存修改和日志的记录就是强一致性的。

柔性分布式事务的实现

消息分布式事务

淘宝TXC事务框架


参考

  1. 企业IT架构转型之道_阿里巴巴中台战略思想与架构实战
  2. Percolator 和 TiDB 事务算法
  3. 线性一致性和 Raft
  4. seata
  5. 蚂蚁分布式事务框架

评论