zoukankan      html  css  js  c++  java
  • Seata全局事务回滚-脏数据导致回滚异常修复记录

    说下背景吧,公司最近打算用Seata来保证SpringCloud微服务间的全局事务(AT模式),使用的是Seata-server 1.1.0版本。注册方式 Eureka,seata-server在测试环境部署了2台!

    异常情况:

    测试的时候 A服务为发起端 A->B->C 其中B服务在一次方法调用中 多次调用C服务更改同一条记录(数据的创建以及更改状态new->wait_pay->pay->success)。于是在A发起的请求结束时 B实际调用了3次C服务,导致C服务里有3条undo_log日志,之后 B服务发生了异常,C服务(每次都完成了本地事务)进行数据回滚(全局事务undo_log),此时正常情况应当是按照3条记录 1 2 3创建的后先顺序执行回滚,即 3 2 1 这就能保证数据正常回滚!

    然而!!!在多次测试中发现数据回滚有时并不一定是按照 3 2 1 顺序执行,时常 会从2 开始 这就导致 2中的记录值 和当前数据库值的实际值 有偏差(2中记录修改后的状态为pay,实际数据库里的状态是3中更改后记录的状态success)这就导致了回滚镜像对比发现数据异常,认为是脏数据产生了!无法正确造成回滚!!!

    找原因:

    从结果上看 数据无法回滚 是由于 回滚时候 undo_log执行的顺序异常导致的,以此切入!跟踪seata-server的代码发现,分支事务回滚时 会根据全局事务xid到branch_table中按照记录生成的时间(`gmt_create`) 正序查询所有分支事件记录放入List中,之后从List里倒序取出,挨个执行回滚! 然后惊奇的发现 每次出现上述回滚异常 都是因为 有两条或多条branch_table记录的 gm_create是相同的 以致于后续回滚查询分支事务的时候 无法保证其先后顺序,而后执行回滚的顺序 就一样无法保证,才最终导致 上述错误!

    解决方案:

    问题找到了,既然按时间顺序查找不靠谱 那找个靠谱的值来查询不就行了,其中发现branch_id其实相对来说是递增的 但是只相对于同一个服务而言,

    private static final AtomicLong UUID = new AtomicLong(1000);
    
    /**
         * Generate uuid long.
         *
         * @return the long
         */
        public static long generateUUID() {
            long id = UUID.incrementAndGet();
            if (id >= getMaxUUID()) {
                synchronized (UUID) {
                    if (UUID.get() >= id) {
                        id -= UUID_INTERNAL;
                        UUID.set(id);
                    }
                }
            }
            return id;
        }

    实际测试环境部署了有2个seata-server服务 所以并不能保证 两个服务产生的branch_id有什么可靠的关联性,

    最终考虑下 比较简单的方法是在branch_table里增加一个自增的字段,使用该字段代替gmt_create进行上述分支事务查询的排序依据即可

    (添加了自增的id,之后更改查询语句如下)

     

    经过更改测试后 发现确实 解决了 上述无法顺序回滚带来的问题!

    在测试 时间如果只是启动一个seata-server服务 一般是不会产生 上述问题的,时间基本 有先后的明显差别!再者branch_id也是明显增加的 也可以用作 查询排序依据,单多台seater-server的时候 就不能保证了!

    本地重新打包各模块后,在seata-server的lib包下替换修改后的新的模块jar即可!

    mvn clean install -DskipTests=true

    以上!

  • 相关阅读:
    不需重新编译php,安装postgresql扩展(pgsql和pdo_pgsql)
    css如何实现水平垂直居中
    win系统DOS批处理命令:每日根据定时计划,弹出相应的提醒
    使用navicat连接mysql连接错误:Lost connection to Mysql server at 'waiting for initial communication packet'
    mysql域名解析引起的远程访问过慢?
    Jquery封装: 地区选择联动插件
    Jquery封装: WebSocket插件
    Jquery封装:下拉框插件
    如何在微信小程序中使用阿里字体图标
    轻量级进度条 – Nprogress.js
  • 原文地址:https://www.cnblogs.com/cangshublogs/p/12423263.html
Copyright © 2011-2022 走看看