之前的文章
seata简介及个人理解
:分布式事务2PC TCC AT(Seata) 如何理解AT模式
seata
单机的例子官网有,关于高可用部署
往这看:保姆级配置 Seata1.2 + Nacos
并发异常
Seata AT模式下针对同一个数据在并发情况下,如果先是下游服务成功,上游服务失败会出现异常
io.seata.core.exception.GlobalTransactionException:Could not found global transaction xid = 192.168.0.2:8091:2011766308, may be has finished.
需要一段时间后lock_table
和global_table
才会被清理干净,虽然事务会回滚,但是中途会造成很长时间的检查事务是否已被提交等等。
我自己有几种思路:
注意对用户的限流(这里所说的限流不是sentinel或hystrix的熔断降级那的限流,sentinel是针对服务本身的限流只用来防止服务超载挂掉而引发的服务雪崩,我们要做的是针对用户IP+URL的限流)
在下游服务先进行扣金额扣库存等操作,这样可以尽可能保证不会出问题。
加入
csrf_token
用来防止重放攻击,毕竟csrf_token
除了防御csrf攻击还可以用来干这事。检查
http
头referer
是否来自正确的请求。可以适当减少client.rm.lock.retryTimes 的重试次数,默认为30次
client.rm.lock.retryInterval
为重试间隔 默认10毫秒,看情况修改。从上面2个参数我们可以得出恶意请求在事务中一次最坏的情况是300ms,这还不算服务retry的时间。一般这种分布式事务肯定不是用在对着一个商品不停的减库存这样的地方,这种秒杀肯定是redis+消息中间件,所以主要是为了防止某些恶意请求,比如黑客并发请求某服务,造成一直去判断全局事务之前的事务完成了没。
手动解绑和绑定事务
RootContext.getXID()
可以直接获取到XID,我们可以在中途控制排除不需要在事务内的服务。String xid = RootContext.getXID(); RootContext.unbind();//解绑 //中途做一些与事务无关的事。比如日志服务等等 排除掉,然后 RootContext.bind(xid);//再绑回来
手动控制事务流程
我们还可以自定义事务整个流程,下面只写了
begin commit rollback
,其中还有suspend
和resume
等方法,用来暂停和恢复事务,suspend
的参数是表示是否解绑xid
GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate(); // 超时时间 , 所在服务 tx.begin(30000, "user-service"); //30秒 //第二个参数transactionName 会在global_table中体现,可有可无,默认为default try{ //todo something //可以手动进行提交 tx.commit(); }catch (Exception ignored){ //如果捕获异常 可以手动进行回滚 tx.rollback(); }
上面的例子就是我们自己来控制事务流程,如果有需要可以用AOP自己实现,一般情况下
@GlobalTransaction
已经够用。