找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2448

积分

0

好友

313

主题
发表于 昨天 19:40 | 查看: 3| 回复: 0

在单库环境下,当我们面对一个需要同时操作多个数据表的业务,比如用户下单,如何保证数据操作的原子性、完整性与一致性呢?

答案就是事务

举个例子:用户下了一个订单,需要修改余额表订单表流水表,于是会有类似的伪代码:

start transaction;
 CURD table t_account;  any Exception rollback;
 CURD table t_order;      any Exception rollback;
 CURD table t_flow;        any Exception rollback;
commit;
  1. 如果对余额表,订单表,流水表的SQL操作全部成功,则全部提交;
  2. 如果任何一个出现问题,则全部回滚;

数据库事务,正是保证单库内数据完整性及一致性的基石。

多库环境下的事务难题

然而,互联网的业务特点往往是数据量与并发量巨大,经常通过拆库的方式来提升系统的伸缩性与性能。

一旦进行了分库,用户余额、订单、流水这些数据可能就分布在了不同的物理数据库,甚至是不同数据库实例上。此时,数据库原生的单库事务机制就失效了。如何在多个独立的数据库之间保证数据一致性,成为了一个必须面对的技术挑战。

补偿事务:一种业务端的解决思路

在高并发场景下,强一致的分布式事务方案往往落地困难。那么,有没有一种更务实的实践呢?

补偿事务就是一种常见的业务层解决思路。

什么是补偿事务?简单说,就是在业务逻辑层面,为每一个正向事务准备一个逆向操作的事务,以备回滚之用。

举个栗子:

修改余额正向事务为:

int Do_AccountT(uid, money){
    start transaction;
         //余额改变money这么多
         CURD table t_account with money for uid;
         anyException rollback return NO;
    commit;
    return YES;
}

那么,对应的修改余额补偿事务就可以是:

int Compensate_AccountT(uid, money){
         //做一个money的反向操作
         return Do_AccountT(uid, -1*money){
}

同理,订单操作正向事务是:Do_OrderT,用于新增一个订单;其补偿事务则是:Compensate_OrderT,用于删除一个订单。

那么,为了跨库保证余额与订单的一致性,我们可以这样组织业务逻辑:

// 执行第一个事务
int flag = Do_AccountT();
if(flag=YES){
    //第一个事务成功,则执行第二个事务
    flag= Do_OrderT();
    if(flag=YES){
        // 第二个事务成功,则成功
        return YES;
    }
    else{
        // 第二个事务失败,执行第一个事务的补偿事务
        Compensate_AccountT();
    }
}

补偿事务的缺点

虽然补偿事务提供了一种思路,但它也存在明显的局限性:

  1. 不具备通用性:不同的业务需要编写不同的补偿逻辑,开发成本高。
  2. 未考虑补偿失败:上述逻辑假设补偿事务本身一定能成功,但实际情况中补偿操作也可能失败。
  3. 逻辑复杂:如果业务流程涉及多个步骤(比如余额+订单+流水),if/else的嵌套层级会呈指数级增长(3个步骤就有2^3=8个分支),代码可维护性急剧下降。

后置提交优化:另一种概率性降低不一致的思路

除了在业务逻辑层想办法,我们是否能在事务执行的时序上做些优化呢?后置提交优化就是这样一种实践。

我们先回顾单库大事务:

start transaction;
 CURD table t_account;  any Exception rollback;
 CURD table t_order;      any Exception rollback;
 CURD table t_flow;        any Exception rollback;
commit;

拆分成多库后,这个大事务会变成三个独立的小事务串行执行:

start transaction1;
         //第一个库事务执行
         CURD table t_account; any Exception rollback;
         …
// 第一个库事务提交
commit1;

start transaction2;
         //第二个库事务执行
         CURD table t_order; any Exception rollback;
         …
// 第二个库事务提交
commit2;

start transaction3;
         //第三个库事务执行
         CURD table t_flow; any Exception rollback;
         …
// 第三个库事务提交
commit3;

请注意,这三个事务发生在三个不同的库或数据库实例上。

一个事务通常可以分为执行(CURD)提交(commit)两个阶段。执行阶段耗时较长(涉及业务逻辑和I/O),而提交阶段通常极快。

于是,上述串行方案的时间轴可能如下所示:

三个事务串行执行与提交的时间轴

  • 第一个事务执行200ms,提交1ms;
  • 第二个事务执行120ms,提交1ms;
  • 第三个事务执行80ms,提交1ms;

那么,在哪个时间点会出现数据不一致?

答案是:从第一个事务成功提交之后,到最后一个事务成功提交之前的这个时间窗口内,如果发生异常(如服务器重启、数据库故障等),数据就可能处于不一致状态。

串行事务异常导致不一致的时间窗口示意图

如上图所示,在最后202ms内出现异常,前一个或两个库的事务已提交,而后面的未提交,就会导致不一致。

什么是后置提交优化?

后置提交优化,核心是改变事务执行与提交的时序:让所有事务先执行,最后再统一提交。

后置提交优化后的时间轴示意图

  • 第一个事务执行200ms,第二个事务执行120ms,第三个事务执行80ms;
  • 然后,第一个事务提交1ms,第二个事务提交1ms,第三个事务提交1ms;

优化后,不一致的时间窗口发生了什么变化?

问题的本质没变,不一致仍然可能发生在第一个提交开始到最后一个提交完成之间。

后置提交优化下异常导致不一致的时间窗口示意图

如上图,不一致的风险被压缩到了最后2ms内。

两种方案的对比与权衡

我们来对比一下:

  1. 串行事务方案:总耗时303ms,最后202ms内出现异常都可能导致不一致。
  2. 后置提交优化方案:总耗时同样是303ms,但最后2ms内出现异常才会导致不一致。

虽然没有彻底解决分布式事务的一致性问题,但不一致出现的概率被大大降低了(在这个例子中降低了100倍)。这是一种典型的用“概率性”换“实现简易性”的权衡。

后置提交优化的不足

这种优化并非没有代价,其主要影响在于数据库连接资源的占用时间变长,从而可能影响系统吞吐量

  1. 串行方案:第一个库事务提交后,其数据库连接就可以释放,供其他请求使用。
  2. 优化方案:所有库的数据库连接,都必须等到所有事务执行完并提交后,才能释放。

这意味着数据库连接被占用的时间增长了,在高并发场景下,可能会成为限制系统整体吞吐量的瓶颈。

总结

面对分布式事务这一复杂课题,本文介绍了两种易于理解和落地的实践方案:

  1. 补偿事务:在业务层通过逆向操作实现“回滚”,灵活但业务逻辑复杂。
  2. 后置提交优化:通过调整事务执行时序(先执行,后提交),大幅缩短不一致风险窗口,实现简单但可能牺牲一定吞吐量。

后置提交优化的核心,就是把:

trx1.exec(); trx1.commit();
trx2.exec(); trx2.commit();
trx3.exec(); trx3.commit();

优化为:

trx1.exec(); trx2.exec(); trx3.exec();
trx1.commit(); trx2.commit(); trx3.commit();

这个改动成本极低,虽然不能提供100%的强一致性保证,却能显著降低数据不一致的概率。在实际的System DesignMySQL等数据库技术栈的架构设计中,架构师需要根据业务对一致性和吞吐量的实际要求,谨慎地进行权衡与取舍。毕竟,脱离具体业务场景谈架构设计,是不切实际的。

对于希望深入探讨更多分布式系统难题和实战经验的开发者,欢迎在云栈社区交流分享。思路往往比固定的结论更有价值。




上一篇:STM32 GPIO八种工作模式详解:原理、配置与应用场景
下一篇:Valkey PHP v1.0.0 发布:PHP 生态的官方高性能客户端来了
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-31 06:22 , Processed in 0.275626 second(s), 38 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表