数据库分库分表以后,如何解决事务问题?

咱们须要接受失望,由于它是有限的;咱们不会失去但愿,由于它是无穷的。spring

1、概述

随着时间和业务的发展,数据库中表的数据量会愈来愈大,相应地,数据操做,增删改查的开销也会愈来愈大。所以,把其中一些大表进行拆分到多个数据库中的多张表中。
本篇文章是基于非事务消息的异步确保的方式来完成分库分表中的事务问题。数据库

2、须要解决问题

2.1 原有事务

因为分库分表以后,新表在另一个数据库中,如何保证主库和分库的事务性是必需要解决的问题。微信

解决办法:经过在主库中建立一个流水表,把操做数据库的逻辑映射为一条流水记录。当整个大事务执行完毕后(流水被插入到流水表),而后经过其余方式来执行这段流水,保证最终一致性。
微信图片_20200704110755.jpg框架

2.2 流水

所谓流水,能够理解为一条事务消息异步

上面经过在数据库中建立一张流水表,使用一条流水记录表明一个业务处理逻辑,所以,一个流水必定是能最终正确执行的.所以,当把一段业务代码提取流水中必需要考虑到:spa

  • 流水延迟处理性。流水不是实时处理的,而是用过流水执行器来异步执行的。所以,若是在原有逻辑中,须要特别注意后续流程对该流水是否是有实时依赖性(例如后续业务逻辑中会使用流水结果来作一些计算等)。
  • 流水处理无序性。保证即便后生成的流水先执行,也不能出现问题。
  • 流水最终成功性。对每条插入的流水,该条流水必定要保证能执行成功

所以,提取流水的时候:blog

  • 流水处理越简单越好
  • 流失处理依赖越少越好
  • 提取的流水在该业务逻辑中无实时性依赖

微信图片_20200704161403.jpg

2.4 流水处理完成

由于流水表是放在原数据库中,而流水处理完成后是操做分库,若是分库操做完成去更新老表流水消息,那么又是夸库事务,如何保证流水状态的更新和分库也是在一个事务的?索引

解决办法是:在分库中建立一个流水表,当流失处理完成之后,不是去更新老表状态,而是插入分库流水表中、队列

这样作的好处:图片

  • 通常会对流水作惟一索引,那么若是流水重复屡次执行的时候,插入分库流水表的时候确定因为惟一索引检测不经过,整个事务就会回滚(固然也能够在处理流水事前应该再作一下幂等性判断)
  • 这样经过判断主库流水是否在分库中就能判断一条流水是否执行完毕

微信图片_20200704161440.jpg

3、流水处理器基本框架

流水处理器其实不包含任何业务相关的处理逻辑,核心功能就是:

  • 通知业务接入方什么时候处理什么样的流水
  • 检验流水执行的成功

注:流水执行器并不知道该流水表示什么逻辑,具体须要业务系统去识别后去执行相对应业务逻辑。
微信图片_20200704161509.jpg

3.1 流水执行任务

流水处理调度任务就是经过扫描待处理的流水,而后通知业务系统该执行哪一条流水。

示意图以下:
微信图片_20200704161530.jpg

3.2 流水校验任务

流水校验任务就是要比较主库和分库中的流水记录,对执行未成功的流水通知业务系统进行从新处理,若是屡次重试失败则发出告警。

流程示意图:
微信图片_20200704161551.jpg

4、为何不用事务消息

因为是既有项目(互联网金融,因此是绝对不容忍有任何消息丢失或者消息处理失败)进行改造,不使用事务消息有1个缘由

  • 须要额外引入消息队列,增长系统的复杂度,并且也须要额外的逻辑保证和消息队列通信失败的时候处理
  • 其实1不算是主要缘由,而是由于事务消息须要手动的commit和rollback(使用数据库不须要),那么问题来了,spring中事务是有传递性的,那咱们事务消息什么时候提交又是个大问题,例如 A.a()原本就是一个事务, 可是另一个事务B.b()中又调用了A.a() 那事务消息提交是放在A.a()仍是B.b()中呢?
相关文章
相关标签/搜索