分布式事务就在你身边,你却不去关爱他
Posted 磊哥谈技术
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分布式事务就在你身边,你却不去关爱他相关的知识,希望对你有一定的参考价值。
故事还得从ORACLE RAC单节点宕机引发应用系统报错说起。某日某医院ORACLE某个节点出现了宕机,部分应用端程序开始报主键冲突的错误。几乎所有人都把矛头指向了数据库服务器,大家的理由是双节点运行正常,只有某个节点宕机后才会报错,所以认为程序没错。
因为主键值是通过存储过程获取的,我第一反应是应该先排查存储过程。当我登录到存储过程所在的数据库后,立马发现存储过程存在并发bug。当时很生气,系统运行了这么久,为什么有bug却不改掉呢?因为时间紧急,我就直接把存储过程的bug给修改掉了。修改完成后,却想到有点不对劲,虽然单节点运行增大了并发的概率,但是运行了这么久,按理说双节点运行也会出现过bug啊,但是现场人员反馈的是双节点正常。通过数据库里数据的分析,我发现这个案例取最大值使用了另一个数据库的存储过程,切换数据库后,发现后面数据库里的存储过程没有bug。此时,觉得事情远没有这么简单了,问题肯定出在别的地方了。
继续分析数据库日志,发现报错的时候同一事务里面的SQL竟然分发到了不同的节点。我甚至开始怀疑ORACLE是不是把存储过程预编译后在单个节点执行,但是通过分析历史数据,发现并不是这样的。我仔细的又分析了一遍出错的那段代码,发现获取主键的值和业务数据的保存确实是使用了同一个事务。正当我纳闷的时候,现场给我反馈了,说获取主键值的方法修改过,而我看到的代码并不是最新的代码,当机立断让现场把最新代码截图发了过来,果不其然,出错的地方使用了分布式事务。真相终于浮出水面。有的同事开始给各种各样的建议,普遍认可的就是当获取主键值失败的时候,判断一下(失败的时候返回-1,以前直接使用-1作为主键值,造成多个-1插入冲突),修改成返回-1的时候直接报错不要继续保存业务数据了。其实我想对这些同事说,你们可能还没弄明白什么是分布式事务。
我甚至开始怀疑,当初选择分布式事务,完全是为了减轻服务器压力,将数百张数据表进行横向分库处理,分到不同的服务器去执行从而达到均衡服务器压力的目的。在当时,大部分项目使用的还是SQL Server数据库,采用此种方案无可厚非,但是相信很多人都不知道自己已经在使用分布式事务了。只是知道多个事务要同时开启,同时提交或同时回滚,再加上门户源码不开放,大家也不清楚事务连接池里的代码是怎么实现的,只知道这样使用就可以了。
当我看到事务连接池源码的时候,我觉得处理的太随意了,当多个事务同时提交时,处理逻辑是循环提交多个事务,只要存在提交失败的事务就返回失败,否则返回成功。当返回失败的时候,再次对前面的多个事务同时执行回滚。想法是对的,但是有一点需要弄清楚,前面提交成功的事务,单纯通过一个回滚命令是回滚不回来的,因为事务成功提交就已经宣布了此事务的结束。分布式事务复杂程度远没有我们想象的那么简单。
其实,很多时候,大家可能会遇到莫名其妙的数据逻辑错误,分析来分析去,始终分析不出原因来,再加上出错的频率太低,干脆就直接说是网络的原因。分布式事务出现不一致的概率很低,再加上完全做好分布式事务的一致性处理需要很复杂的处理。也许这就是被迫地选择性放弃吧。但是为了数据的准备无误乃至避免莫名其妙的程序错误,我还是建议大家认真对待事务处理逻辑,特别是牵涉到分布式事务的时候更要仔细考虑一下,是否有办法绕开不必要的分布式事务不一致性陷阱。
以上是关于分布式事务就在你身边,你却不去关爱他的主要内容,如果未能解决你的问题,请参考以下文章