分布式事务的一致性
我们都知道数据库事务ACID的特性,在单数据库应用中,通过数据库事务能够很好的保证我们数据的一致性,但是在微服务盛行的今天,单个大系统被拆分为多个小的微服务,每个服务独立部署,并且拥有自己的数据库。这时单纯依靠数据库的事务就无法满足数据一致性的要求,“分布式事务”应运而生。
什么是分布式事务?
数据库事务有ACID四个特性,理论上分布式事务也应该遵从这四个特性,但是考虑到性能的因素,分布式事务并不能完全实现ACID的特性。实际上数据库事务也没有完全实现ACID,因此才有了事务的四种隔离级别。我们所说的分布式事务都是不完全事务。
分布式事务的解决方案
分布式事务有很多解决方案,比如:2PC、3PC、TCC、Saga和本地消息等等,每个方案适用的场景并不一样,在面临实际需要选择合适的方案。常用的有2PC和本地消息
2PC(二阶段提交)
2PC是 一种常见的分布式事务实现方法,举个例子来说,在电商系统中,下单的时候至少需要做两件事:
写入订单数据
扣减库存
假设订单和库存在两个库中,那我们就必须要保证在下单成功的时候,库存一定被扣减成功了,我们来看看2PC怎么解决这个问题的。2PC引入了一个事务协调者的角色,由协调者提供完整的下单服务,所谓二阶段提交就是准备阶段和提交阶段,在准备阶段,协调者告诉订单系统有新订单了,能不能下单?然后订单系统告诉协调者可以下单,此时协调者再通知库存系统,需要扣减一个库存,库存系统返回可以扣减,当两个系统都返回成功时,协调者再通知订单系统下单,通知库存系统扣减库存(此时才真正的提交事务)
如果准备阶段任意一个系统失败了,那么协调者就要通知两个系统都会滚事务;如果准备阶段都成功了,那么就只有一条路,只能成功,不能失败。
2PC保证了原子性和隔离性,适用于对数据一致性要求比较高的场景,但是,在事务执行的过程中需要阻塞服务端线程和数据库的会话,所以性能不是很高,因此只有在需要强一致且并发量不大的情况下才考虑使用2PC。
本地消息表
在很多情况下,我们可能并不需要数据的强一致性,我们只要保证数据的最终一致性就好了,比如说下单之后需要清空购物车这个操作。这时候可以使用本地消息表来实现分布式事务。
当订单系统收到一个下单请求时,订单系统正常去更新订单数据,在这个过程中在本地记录一条消息日志,内容就是要清空购物车,然后我们再用一个异步的服务去读取本地消息去清空购物车,如果操作失败了,可以通过重试来解决,最终保证订单系统和购物车的数据是一致的。
3PC、TCC大体的思想和2PC是差不多的,解决了一些问题,同时也带来了新的问题,以后再论述。