解释为什么产生分布式事务
要解释分布式事务首先抛离分布式三个字,先解释事务。
事务的定义
数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。
事务的特性
- A:原子性:事务中的每个操作都是最小维度,要么成功要么失败
- C:一致性:事务执行完成之后,数据必须是一致的。(可以理解为事务执行完成后数据应该与预期的结果一致)
- I:隔离性:事务之间都是隔离的,事务之间不应该互相影响。
- D:持久性:事务完成之后数据一定是持久化到存储层的。(可以理解为只要事务提交成功,不论系统是否异常该数据一定会持久化到存储层)
并发事务带来的问题
- 脏读:事务读取到了其它事务还没提交的数据
- 不可重复读:事务读取同一条数据读取到的数据前后不一致(在同一个事务中第一次查询和第二次查询同一条数据数据不同)
- 幻读:事务读取数据读取到的数据的数量前后不一致,事务第一次读取查询到一条,第二次查询读取到两条(更加注重数据的数量)
事务隔离级别
- 读未提交:当前事务可以读取到其它事务未提交的数据
- 读已提交:当前事务可以读取到其它事务已提交的数据
- 可重复读:事务开启后查询到的数据不允许其它事务对该数据做修改
- 串行化:事务都是按照串行执行,不存在并发事务的任何问题,但是性能差
分布式事务的产生
以上解释了事务的问题,但是以上的事务问题是在同一个数据库中并发事务产生的,但是如果同一个数据库中的事务被拆分到多个数据库或者说同一个库的事务的SQL被拆分到多个服务中了,那么就产生了分布式事务的问题。
分布式事务产生的根源在于拆分。一方面是服务层的拆分、另一方面是存储层的拆分。
服务层拆分
服务层的拆分举个例子来说,以物流的履行系统来说,一开始的履行系统中会保存物流订单、物流包裹数据以及调度任务数据,项目初始时保存物流订单、保存物流包裹、保存调度任务是在一个服务中完成并且通过事务保证数据的完整性。但是由于后续的发展,物流订单和物流包裹数据需要独立一个物流包裹服务,那么原来在同一个服务同一个数据库中完成的事务操作,演变成了先调用包裹服务的RPC接口,然后再调用本身的调度任务的保存,那么如果调度任务保存失败,那么物流包裹也无法回滚。
这样的问题就是拆分服务的分布式事务问题,由于拆分了服务导致原来的同库SQL演变为RPC调用,由于RPC的调用无法保证事务,从而导致了数据无法保证一致性的问题。
存储层拆分
存储层的拆分,以我们的实际业务来说,履行系统初期数据量可控,但是后续由于接入大量的业务系统,导致数据量剧增,原来的单库处理也遇到的瓶颈,一方面是线程连接数不够导致等待时间过长,另外单表的数据量剧增导致查询和整理数据变慢,因此我们实现了分库分表,分库分表顾名思义就是将原来的单库分为多个库,并且单表也分为多表,通过设定的分片键进行拆分。
拆分之后由于不在同一个数据库,即无法共享innodb缓存,那么原来单库下的事务就无法在分库分表的场景下进行使用,这样的情况下就导致了分布式事务问题。(分库分表的中间件可以提供分布式事务的解决方案)
总结
以上针对分布式事务的产生从服务层拆分和存储层拆分做了分析,如果平时接触微服务和分库分表的实际应用,那么对于分布式事务会有比较好的理解。
在实际开发过程中对于服务层的拆分和存储层的拆分并没有注意事务的问题,直到实际发生了异常问题,排查问题时才想到分布式事务,所以在方案确定时要多考虑一层分布式的相关问题。
转载自:https://juejin.cn/post/7202944248869158973