事务原理
1. 解决什么问题
事务要解决的问题包含下面这些
- 一个事务声明内的所有DS DML请求,要统一提交或者回滚
- DS存在多节点,业务模块也可以多节点,事务如何进行路由
2. 怎么解决
2.1 事务性
事务性要从两个场景来看,一个是非跨库事务(项目没有垂直分库),一个是跨库事务(开启垂直分库,一个项目会映射到多个物理库或者逻辑库)
2.1.1 非跨库事务
DS可以适用于不同数据规模的业务应用项目,当数据规模较小时,所有业务模块可以连接同一个数据库,稍大时还可以进行水平分表,此时DS连接单个数据库,所有数据库操作可以采用数据库本地事务保证强一致性;
事务性依靠数据库能力,一个事务内的所有请求都将使用同一个数据库连接执行,只有当事务提交时候才会commit整个事务,如果出现异常则会rollback整个事务
// 事务开启Connection conn = getConnection();conn.setAutoCommit(false);
// 业务请求conn.execute(business sql);...
// 事务提交conn.commit();
// 事务回滚conn.rollback();2.1.2 跨库事务(开启垂直分库)
当业务模块数据规模进一步增大时,或者采用微服务模式需要严格隔离不同模块的数据库时,就需要进行垂直分库,即允许不同的业务模块连接不同的数据库,此时将引入分布式事务问题,一般有两种应对策略: • 模块A不允许直接操作模块B的数据库(而是通过调用模块B开放的接口进行操作):该模式下,DS不需要做特殊处理,事务控制完全由业务模块实现 • 模块A允许直接操作模块B的数据库:该模式下,DS需要实现跨库事务,目前由阿里开源的Seata是该领域的首选
跨库事务场景下由于一个DS事务内会出现操作不同数据库的情况,因此只依靠数据库能力已经无法解决,因此我们会集成Seata来处理跨库事务,这个逻辑对上层业务是无感的,不需要引入任何额外配置或者额外代码,全部由DS根据项目实际部署情况自动选择。
DS会与Seata交互,使用Seata AT模式来解决跨库事务,可以参考Seata文档了解相关设计


2.2 路由
从上面的信息可以得知一个事务内的所有请求需要路由到同一个DS节点,因此SDK需要维护事务路由信息,我们会在ThreadLocal中维护当前线程对应的全局唯一事务id以及事务id对应的DS服务节点信息,在请求DataStore服务端时,会根据事务id选择正确的路由节点