-
Notifications
You must be signed in to change notification settings - Fork 8.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AT模式下,二阶段回滚失败后,seata-server服务端TC重试回滚定时任务长时间不执行问题 #6478
Comments
如果在同步回滚下出现回滚失败,状态将被重置为RollbackRetrying,会在1s后自动进行重试。 |
rollbacking状态本身的事务是没问题,但是如果global_table中这种状态的记录太多,超过100条后,如果此时再发生二阶段回滚失败的RollbackRetrying的事务,就得等2分钟删除后才会被处理 |
因为默认配置store.db.queryLimit=100,每次取100条处理这个限制 |
@funky-eyes 这个配置可以增大,两分钟内回滚事务过多也属于业务异常,但是这个回滚重试受到这个状态记录数影响也不是很合理 |
1.提高store.db.queryLimit的值 |
提高queryLimit的值不能彻底解决这个问题,倒是独立rollbacking和commiting的线程池能有之前IO优化的收益,也能解决这个问题。 |
还有一种办法,将status进行排序,因为committing状态为2,所有需要重试的状态都比他大,rollbacking也是一样。只要将sql进行改动,就可以优先查询到真正需要回滚的事务。 |
这个能解决问题也容易操作,但是逻辑隔离性不如另开线程池处理,另外DB模式下高频全局事务对数据库性能消耗本来就很大,高频排序查询也不是很好,如果另开线程还可以降低数据库查询频率 |
方案3.对mysql会有性能影响 Solution 3 may have performance implications on MySQL. For Solution 2, after separating them, I came up with a better approach that doesn't require querying the database every second. Most rollbacking operations involve deletions, and they usually need to wait for at least 2 minutes and 10 seconds. Querying the database every second would have a significant impact on performance, and the fetched data wouldn't be useful immediately. Instead of using scheduleAtFixedRate, we could switch to using schedule. Suppose schedule fetches 100 records, but the first record doesn't need processing until 2 minutes later. In that case, we can schedule the next query task to execute after 2 minutes. Why? Because the inserted global sessions are ordered, so if the first record isn't due for deletion, neither are the subsequent ones. There's no need for continuous querying every second. If the query returns no results, we can switch back to querying after 2 minutes and 10 seconds. This approach significantly reduces the number of queries and the amount of data processed. What do you think? |
逻辑有点复杂不好控制,另外降级到2分钟后执行这个操作,一般低频的回滚能够实现,但是低频回滚也不会触发上述问题,高频回滚降级的几率也不大,例如在业务低峰降级2分钟执行,但是业务高峰时可能还会触发 |
另外所有的Rollbacking状态都可以直接删除吗?这个Rollbacking状态是不是会在几秒后变更为Retrying状态 |
这种情况灵活配置也不行 |
我觉得还是需要一个最终状态,根据中间状态和持续时间怎么搞都不是很合理 |
多一个中间状态会使性能降低,如果你改用raft模式,是不会出现这种问题的,这个处理仅限于存算分离的模式,db和redis |
只有出现异常的情况下才会变更为Retrying,Rollbacking这个状态指的是tm决议发给tc,tc改为rollbacking后开始回滚,然后tm等待tc下发二阶段结束后响应。 |
好的,我先试试raft模式。至于分离存储模式下的这个问题,您还有什么建议吗? |
存算分离未来不会是社区的推进核心,未来可能会考虑在multi-raft上做处理。所以该存算分离的导致的问题,不会投入太大的精力去处理,一般来说会做一些兜底措施和处理逻辑上的优化,大的架构变动应该是不会出现。 |
明白了 |
I will optimize it using option 2 |
Ⅰ. Issue Description
在AT模式下,出现二阶段回滚失败的全局事务后,不会立即进行回滚重试,而是在大约2分钟后才会看到重试日志并且回滚成功
Ⅱ. Describe what happened
在经过业务分析和代码调试之后发现如下问题
1、当系统中存在大量的需要回滚的全局事务时(业务逻辑问题,大约2分钟内有600条左右),global_table表中的记录均处于Rollbacking状态(status=4),且该类型记录大约在2分钟后才会被删除,但是该类型的全局事务其实已经完成二阶段回滚
2、上述问题原因如下:
a、发生业务异常进行全局事务回滚,服务端代码流程为调用
org.apache.seata.server.coordinator.DefaultCore#rollback-->org.apache.seata.server.coordinator.DefaultCore#doGlobalRollback
b、当所有分支事务回滚成功后,此处没有赋予全局事务一个最终状态。进入endRollbacked方法后,由于retryGlobal=false,也未对全局事务状态进行变更
c、因此global_table表中存在大量Rollbacking状态(status=4)的记录(实际状态应该为GlobalStatus.Rollbacked)
2、造成的影响:
a、在上述情况下某个全局事务由于业务异常发生回滚,但是在某个分支事务进行二阶段回滚时发生异常造成全局事务回滚失败,且回滚失败上报seata-server服务端TC成功,数据库记录变更状态为GlobalStatus.RollbackRetrying
Ⅲ. Describe what you expected to happen
第一次全局事务回滚成功后需要一个最终状态(GlobalStatus.Rollbacked),并进行变更
现在能想到是通过计数器记录回滚分支事务的数量,全部分支事务回滚完成后变更全局事务状态,但也不是很合理
Ⅵ. Environment:
java -version
):1.8.0_341The text was updated successfully, but these errors were encountered: