浅谈,seata在使用feign-url通过域名调用时分布式事务不生效的问题及解决
浅谈,seata在使用feign-url通过域名调用时分布式事务不生效的问题及解决
在前几个月时,我们项目出现了分布式事务的问题,那么什么是分布式事务问题呢,简单的说,我们有俩服务A和B,它们对应的数据源分别是a_db和b_db,A服务收到请求在执行到某个操作时,需要调用B服务,在B服务里继续执行,B服务里面的执行牵扯到了对b_db的增删改操作,等B服务执行完后,A又继续执行,结果此刻,A发生异常了,由于B在另一个服务,有自己的数据源,它和A也不属于一个事务,导致a_db自己回滚了,b_db却没有回滚,这不就出问题了么,这也就是我们系统分布式事务问题的来源。
后来呢,我们引入了springcloud中解决分布式事务的组件seata,关于分布式事务seata的介绍安装各个模式我就不详细的一一啰嗦的解释了,当然为了方便后面大家对问题发生和解决的更好理解,我还是会说一下这个seata解决分布式事务的流程。
关于seata解决分布式事务流程的介绍
seata分为三部分,TC事务协调者,TM事务管理器,RM资源管理器。其中TC是一个独立的seata-sever服务,用来协调整个分布式事务的,在git_hub上可以自行下载;TM是全局事务的发起者,管理整个全局事务,相当于项目中的调用者服务,在我们项目中就相当于那个A;RM资源管理器可以有多个,在项目中属于被调用者,在我们项目中相当于那个B。
它们的执行流程如下:
- 1.TM向TC发起一个请求,说明自己要开启一个全局事务。
- 2.TC收到了来自于TM的请求,生成了一个XID作为这个全局事务的唯一标识,返给了TM。
- 3.TM开始去调用其他的RM,并将XID一并的传给了那些RM。
- 4.RM会接收到XID,知道自己的事务属于这个全局事务,它会将自己的本地事务注册到TC作为这个XID下面的一个分支事务,并把自己的事务执行结果也告诉TC。
- 5.各个微服务执行完之后,TC就知道这个XID下的各个分支事务的执行结果,当然TM也知道了。
- 6.TM发现各个分支事务都成功了,就向TC发起请求进行提交,否则就向TC发起请求进行回滚。
- 7.TC收到请求后,就向XID下的所有的分支事务发起相应的请求。
- 8.各个微服务收到TC的请求后,执行相应的命令,并把执行结果上报给TC。
下面为了帮助大家更好的理解,放了一张图进行演示:
引入seata后的后遗症
我们项目是个不太标准的微服务,分为服务A和B,但却没有注册中心,使用了springcloud的组件feign进行服务通信调用,但是没有注册中心不能通过服务名发现服务,只能使用了feign的url模式进行互通 ,当然这也是为问题的爆发埋下了种子。
seata其实使用的模式有很多,比如AT了,TCC了,XA了,还有Saga了,当然我们选用的是AT模式,这种是无侵入业务式的模式,官方也比较推荐。至于注册配置方式也有很多,有file 、nacos 、eureka、redis、zk、consul、etcd3、sofa等,最终由于我们项目没有注册中心的特殊性,我们就只好选用了file单机的注册配置方式。
于是经过下载seata-server并启动,修改file.conf文件的seata-server地址,并将file.conf和registory.conf配置文件放入到resources下,修改数据源为代理数据源,在a_db和b_db添加undo_log数据库表,变A调用端的@Transactional为@GlobalTransactional,这些操作完成后,一个seata分布式事务处理框架的引入算是正式完成,于是在本地电脑上启动了A,B项目,进行模拟单元测试,分布式事务问题完美处理,于是代码上测试服务器,过了一段时间上了预生产服务器。
那时候由于工作事多,只在本地模拟了下,服务器上也只能测试中遇到了再看,没再去关心这件事,毕竟本地已经完美契合了,结果一个月后上了预生产环境,某个业务代码由于数据原因发生了异常,那个方法还牵扯到了分布式事务问题,在观察数据库数据时,离奇的发现,分布式事务没生效,B服务没有回滚!!
seata问题的一步步剖析及解决
问题发生了后,抓紧在本地模拟了下,发现在自己电脑上分布式事务仍然是可以生效的,代码都一样也没改过,为什么在预生产环境就不行了,真实见了鬼了。
后来就在思考预生产环境和自己在本地上测试有什么区别么,本地测试时,两个服务之间的调用feign里面的url填写的是ip:port,直接就去访问了指定的服务,但是预生产环境中使用的域名,也就是说请求会根据域名通过nginx转发到对应服务,假设第一次请求的B1服务,第二次转发请求的是B2服务,不在一个服务上。有同事就提出了,会不会就和这个B服务有集群有关。但是还是感觉那里不对劲,因为听说我们的预生产环境B虽然做了集群,但是这几个B连接的数据源依旧是同一个数据源,不过看起来说的也好像很有道理的样子。
后来啊,就打算在测试环境的服务器试一下,因为毕竟测试服务器没有什么集群,也是一个A和一个B,他们之间的调用是通过域名而并非ip:port,本以为会成功的,结果却很悲催,在B服务没有做集群的情况下,分布式事务仍然是不生效的,那看起来好像和集群不集群没啥关系啊,毕竟测试环境的服务就是一对一,每次也只会访问那一个B,仍然还不生效,到底发生了啥呢。
一时间没有辙了,只有把那个feign的url统一改成了ip:port方式以解决燃眉之急,但是这样并不好,毕竟这意味着上了生产环境A就固定的去调用其中一个B了,那集群就没有任何意义了。
大约过了一段时间,有同事说把nginx的负载均衡策略改成ip_hash方式就没问题了,但这种方式没有人去验证,我也没这个权限去改服务器的nginx.conf去验证,因为在测试环境1对1的情况下都没办法保证让分布式事务生效,那即使改成ip_hash又能如何呢?
后来大佬推荐我看一篇文章,说问题可能出在nginx上,这是文章的网址:nginx做转发时,带'_'的header内容丢失.....大体上将的就是nginx对带下划线的头请求进行限制,会把它过滤到,这也就是造成nginx转发时带“_”的请求会丢失的情况的产生。后来感觉发现了新大陆,seata分布式事务的事务id的格式是TX_XID,那么在TM拿到XID去调用RM时,会不会发生XID的丢失,导致RM没有办法将自己的分支事务注册到那个XID所代表的全局事务的下面,因此也不会被管理呢,自然不生效了。所以只要将nginx的那个对下划线的请求过滤处理掉就好了。
想到后,激动不已,想在服务器上模拟问题发生及解决,但是项目的nginx.conf岂容我这种小开发随意改动!没事,反正自己暂时无事,于是在自己电脑上写了几个服务demo,转发用的是我自己虚拟机里面的nginx,自己也整了个seata-server运行起来,把各项配置都配好,开始模拟,果然,服务器上的问题被我模拟出来了,接下来就是将nginx里面的对下划线的过滤去除,去除方式就是在nginx.conf的http部分添加一行: underscores_in_headers on;
再次测试,成功,url写成域名也没有关系了。
以下是我的模拟情况记录表:
模拟方式 | 分布式事务是否生效 |
---|---|
url通过ip:port,nginx未改动 | 生效 |
url通过填写域名,nginx未改动 | 不生效 |
url通过填写域名,nginx仅仅将负载均衡策略改为ip_hash | 不生效 |
url通过填写域名,nginx仅仅加入underscores_in_headers on | 生效 |
浅谈,seata在使用feign-url通过域名调用时分布式事务不生效的问题及解决的更多相关文章
- 浅谈WebService开发二(同步与异步调用)转
上文 <http://www.dotnetgeek.cn/xuexiwebservice1.html>已经跟大家说了,如果创建一个webservice和简单的调用,本文将注重webserv ...
- 浅谈Js对象的概念、创建、调用、删除、修改!
一.我们经常困惑,对象究竟是什么,其实这是一种思维,一种意识上的东西,就像我们都说 世界是有物质组成的道理一样,理解了下面的几句话!对象也不是那么抽象! 1.javascript中的所有事 ...
- 浅谈WebService开发三(动态调用WebService)转
在前两讲里,我已经向大家演示了如何使用WebService.同步, 异步调用WebService,而在实际开发过程中,可能会有多个WebService接口供你选择,而在程序执行过程中才决定使用哪一个 ...
- URL跳转与webview安全浅谈
URL跳转与webview安全浅谈 我博客的两篇文章拼接在一起所以可能看起来有些乱 起因 在一次测试中我用burpsuite搜索了关键词url找到了某处url我测试了一下发现waf拦截了指向外域的请求 ...
- 浅谈angular2+ionic2
浅谈angular2+ionic2 前言: 不要用angular的语法去写angular2,有人说二者就像Java和JavaScript的区别. 1. 项目所用:angular2+ionic2 ...
- 浅谈Hybrid技术的设计与实现第三弹——落地篇
前言 接上文:(阅读本文前,建议阅读前两篇文章先) 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 根据之前的介绍,大家对前端与Native的交互应该有一些简单的认识了,很多 ...
- 浅谈Hybrid技术的设计与实现第二弹
前言 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 浅谈Hybrid技术的设计与实现第三弹——落地篇 接上文:浅谈Hybrid技术的设计与实现(阅读本文前,建议阅读这个先) ...
- 浅谈Hybrid技术的设计与实现
前言 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 浅谈Hybrid技术的设计与实现第三弹——落地篇 随着移动浪潮的兴起,各种APP层出不穷,极速的业务扩展提升了团队对开发 ...
- 浅谈Vue.js
作为一名Vue.js的忠实用户,我想有必要写点文章来歌颂这一门美好的语言了,我给它的总体评价是“简单却不失优雅,小巧而不乏大匠”,下面将围绕这句话给大家介绍Vue.js,希望能够激发你对Vue.js的 ...
随机推荐
- Ubuntu 快速安装Gitlab-ce
1.下载并安装gitlab,下载地址: https://packages.gitlab.com/gitlab/gitlab-ce/ sudo dpkg -i gitlab-ce_12.0.3-ce.0 ...
- Pytest系列(30)- 使用 pytest-xdist 分布式插件,如何保证 scope=session 的 fixture 在多进程运行情况下仍然能只运行一次
如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 背景 使用 pytest-xdis ...
- 2021最新版Dubbo-admin+Zookeeper安装教程
安装程序包 这是写教程时收集好的文件,可直接点击下载,也可以跟着步骤自行下载:https://hanzhe.lanzous.com/ihna9jzcsze Zookeeper下载地址,任选其一点击下载 ...
- ASP程序写的项目与微信服务号(公众号)完美结合。仅需一个DLL组建WeixinDLL
因ASP程序开发有很多优点,早年间ASP风靡全球,因此如今还在继续运营的ASP开发的项目仍在运行着,但是随着社交网络不断发达,特别是微信支付.微信通讯.小程序等的出现,导致很多ASP项目对接起来就比较 ...
- 百度API定位根据经度、维度 返回当前详细地址
百度地图API是一套为开发者免费提供的基于 百度地图的应用程序接口,包括JavaScript.iOS.Andriod.静态地图.Web服务等多种版本,提供基本地图.位置搜索.周边搜索等. 1 < ...
- JMeter日志查看
- shellcode 开发
0x00 设置堆栈 栈顶指针按位与之后,将栈桢以16字节的大小对齐: push rbp ;store rbp original state mov rbp, rsp ;set stack base p ...
- 逆向工程第005篇:跨越CM4验证机制的鸿沟(下)
一.前言 本文是逆向分析CM4系列的最后一篇,我会将该游戏的序列号验证机制分析完毕,进而编写出注册码生成器. 二.分析第二个验证循环 延续上一篇文章的内容,来到如下代码处: 图1 上述代码并没有特别需 ...
- XCTF-mfw
mfw mfw是什么东西??? 看题: 进来只有几个标签,挨着点一遍,到About页面 看到了Git,猜测有git泄露,访问/.git/HEAD成功 上Githack,但是会一直重复 按了一次ctrl ...
- Error starting userland proxy: /forwards/expose/port returned unexpected status: 500.
欢迎关注微信公众号 Error starting userland proxy: /forwards/expose/port returned unexpected status: 500. dock ...