浅谈,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通过域名调用时分布式事务不生效的问题及解决的更多相关文章

  1. 浅谈WebService开发二(同步与异步调用)转

    上文 <http://www.dotnetgeek.cn/xuexiwebservice1.html>已经跟大家说了,如果创建一个webservice和简单的调用,本文将注重webserv ...

  2. 浅谈Js对象的概念、创建、调用、删除、修改!

    一.我们经常困惑,对象究竟是什么,其实这是一种思维,一种意识上的东西,就像我们都说    世界是有物质组成的道理一样,理解了下面的几句话!对象也不是那么抽象!    1.javascript中的所有事 ...

  3. 浅谈WebService开发三(动态调用WebService)转

    在前两讲里,我已经向大家演示了如何使用WebService.同步, 异步调用WebService,而在实际开发过程中,可能会有多个WebService接口供你选择,而在程序执行过程中才决定使用哪一个 ...

  4. URL跳转与webview安全浅谈

    URL跳转与webview安全浅谈 我博客的两篇文章拼接在一起所以可能看起来有些乱 起因 在一次测试中我用burpsuite搜索了关键词url找到了某处url我测试了一下发现waf拦截了指向外域的请求 ...

  5. 浅谈angular2+ionic2

    浅谈angular2+ionic2   前言: 不要用angular的语法去写angular2,有人说二者就像Java和JavaScript的区别.   1. 项目所用:angular2+ionic2 ...

  6. 浅谈Hybrid技术的设计与实现第三弹——落地篇

    前言 接上文:(阅读本文前,建议阅读前两篇文章先) 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 根据之前的介绍,大家对前端与Native的交互应该有一些简单的认识了,很多 ...

  7. 浅谈Hybrid技术的设计与实现第二弹

    前言 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 浅谈Hybrid技术的设计与实现第三弹——落地篇 接上文:浅谈Hybrid技术的设计与实现(阅读本文前,建议阅读这个先) ...

  8. 浅谈Hybrid技术的设计与实现

    前言 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 浅谈Hybrid技术的设计与实现第三弹——落地篇 随着移动浪潮的兴起,各种APP层出不穷,极速的业务扩展提升了团队对开发 ...

  9. 浅谈Vue.js

    作为一名Vue.js的忠实用户,我想有必要写点文章来歌颂这一门美好的语言了,我给它的总体评价是“简单却不失优雅,小巧而不乏大匠”,下面将围绕这句话给大家介绍Vue.js,希望能够激发你对Vue.js的 ...

随机推荐

  1. 利用Apache部署静态网站(二)

    本文接着<利用Apache部署静态网站(一)>继续部署,为系统中的每位用户创建一个独立的网站. httpd服务程序提供的个人用户主页功能可以为每位用户创建一个独立的网站.该功能可以让系统内 ...

  2. Appium 自动化测试框架:关键字驱动+数据驱动

    1. 关键字驱动框架简介 2. 框架结构说明 3. 框架代码实现 action 包  page_action.py business_process 包 case_process.py data_so ...

  3. mysql is null 和 =null 区别

    数据库中 null 表示 不可知,不确定所以 判断都用 字段 is null的方式进行判断而 = null .<> null 的判断结果,仍然是不可知,不确定,所以 不会返回任何结果.或者 ...

  4. 大数翻倍法求解CRT

    目录 正文 引入 大数翻倍法 复杂度证明 大数翻倍法的优势 最后的最后:上代码! 注:做法和思路是 zhx 在一次讲课中提出的,如有侵权,请联系作者删除 其实别的题解也有提到过暴力做法,但这里将会给出 ...

  5. hdu3594 强连通 tarjan

    题意: 判断是不是强连通图 ,同时每一条边必须只能在一个环里 思路:之前我的强连通用的全是双深搜,结果题目的第二个要求很难判断,一开始写了三个深搜加上并查集,结果越写越乱,其实就是在判断一个边是否只在 ...

  6. 逆向工程第004篇:跨越CM4验证机制的鸿沟(中)

    一.前言 在上一篇文章的最后,我已经找出了关键的CALL语句,那么这篇文章我就带领大家来一步一步地分析这个CALL.我会将我的思路完整地展现给大家,因此分析过程可能略显冗长,我会分为两篇文章进行讨论. ...

  7. 从苏宁电器到卡巴斯基第26篇:难忘的三年硕士时光 IV

    录课,录课,还是录课 开题结束以后,已经是三月的下旬,当时我在考虑要不要回家,毕竟学校这里也没什么事了,我待在学校还得付出一定的花销.后来我考虑到在家的话,只有晚上才能够录课,而在学校的话,整个白天都 ...

  8. SMTP、POP3和IMAP邮件协议

    目录 SMTP POP IMAP 总结 DNS记录中的MX记录 今天入职第一天,公司让配置个人的内网.外网邮箱,这可把我给搞晕了,本来以前就对邮箱这块不是很了解,平时也不怎么用邮箱,顶多有个QQ邮箱而 ...

  9. Windows核心编程 第四章 进程(下)

    4.3 终止进程的运行 若要终止进程的运行,可以使用下面四种方法: • 主线程的进入点函数返回(最好使用这个方法) . • 进程中的一个线程调用E x i t P r o c e s s函数(应该避免 ...

  10. Idea一直卡在loading archetype list问题解决(或者报Unable to import maven project: See logs for details)

    暂时没有测试成功 https://blog.csdn.net/calo_missile/article/details/95898519