当前位置:首页 > 科技  > 软件

微服务循环依赖引发惨案,有坑!

来源: 责编: 时间:2024-07-12 17:26:14 823观看
导读最近的迭代转测后遇到了一个比较有意思的问题。在测试环境整体运行还算平稳,但是过一段时间之后,就开始有接口超时了,日志中出现非常多的 “java.net.SocketTimeoutException: Read timed out”。试了几次重启大法,每次都

最近的迭代转测后遇到了一个比较有意思的问题。在测试环境整体运行还算平稳,但是过一段时间之后,就开始有接口超时了,日志中出现非常多的 “java.net.SocketTimeoutException: Read timed out”。试了几次重启大法,每次都是只能坚持一会之后,再次出现 SocketTimeoutException。6vW28资讯网——每日最新资讯28at.com

注意:在测试环境于遇到问题重启服务,并不是一个好的实践,因为重启可能会让不容易出现的问题现场被破坏。如果问题在测试环境不能再重新,却在发版后出现在生产环境的话,那不仅会造成生产运维事件,还要在巨大的压力下去解决问题。6vW28资讯网——每日最新资讯28at.com

初步分析

顺着测试汇报的出现问题的场景,跟踪调用链上相关服务的日志,发现出现了微服务之间循依赖调用。大致情况可以抽象如下所示(图中所有调用都是 http 协议):6vW28资讯网——每日最新资讯28at.com

图片图片6vW28资讯网——每日最新资讯28at.com

  • Client 调用服务 Foo.hello()
  • Foo.hello() 逻辑中会调用服务 Boo.boo()
  • Boo.boo() 又调用回服务 Foo 的另外一个方法 another()

当然真实的场景要比较这个复杂,调用链更长,不过最终形成了环形依赖调用。至于这个环形依赖为什么回导致超时,当时想了多种可能,比如数据库慢查询、数据库锁、分布式锁等等。但是整个调用链上都是查询请求,而且查询相关的数据量也非常小,不会有锁存在。发生问题的时候也没有与查询数据相关的数据库写请求。6vW28资讯网——每日最新资讯28at.com

鉴于这个环形依赖调用确实是这个迭代版本中引入的变更,以及虽然没有理清其中的因果关系原理,但是这个环性依赖调用还是很可疑的,而且是不必要的环形调用。就抱着将环形依赖调用去掉试试看的态度,做了修复。修复完后,SocketTimeoutException 不再出现了。问题解决了。6vW28资讯网——每日最新资讯28at.com

探寻原因

问题虽然不再出现,但是凭运气解决的问题,通常有可能不是真的的解决。只有弄清楚背后的原理,我们才能真正的确认问题是不是这个原因导致的,这样的修复是不是真的把问题解决了。6vW28资讯网——每日最新资讯28at.com

通过假设环形调用就是导致调用超时的直接原因。我们看看能不能推出因果关系。通过把Foo 服务容器画的更详细一点,如下图:6vW28资讯网——每日最新资讯28at.com

图片图片6vW28资讯网——每日最新资讯28at.com

通过这个图示,我们可以发现,如果容器中接收请求的线程池如果都在等待服务Boo.boo() 的响应,而 Boo 又需要调用回服务 Foo.another()。这个时候,如果所有的线程都处于这样的状态,我们就会发现服务 Foo 容器中以及没有线程来处理 Boo 的请求了。关注公众号:码猿技术专栏,回复关键词:1111 获取阿里内部的Java性能调优手册!某种程度上来说就是死锁了。到这里,我们就可以很确定了,这个环形依赖调用就是导致出现调用超时的罪魁祸首。当 client 发起的请求速度大于这个环形调用链的处理速度的时候,慢慢的就会导致服务 Foo 的所有线程都进入这种死锁状态。6vW28资讯网——每日最新资讯28at.com

验证

这里只列出关键的代码,具体的代码可以参考 gitee 工程:https://gitee.com/donghbcn/CircularDependency6vW28资讯网——每日最新资讯28at.com

Eureka 服务器

建个简单工程将Eureka server启动起来。6vW28资讯网——每日最新资讯28at.com

服务 Foo

创建 SpringBoot 工程实现 Foo 服务。Foo 通过 FeignClient 调用 Boo 服务。设置缺省的容器 Tomcat 的最大线程数为 16,Tomcat 默认配置最大线程数 200,对于验证这个场景有点了大了,要看到效果需要等的时间有点长。6vW28资讯网——每日最新资讯28at.com

application.properties

spring.application.name=demo-fooserver.port=8000eureka.client.serviceUrl.defaultZnotallow=http://localhost:8080/eurekaserver.tomcat.threads.max=16
package com.cd.demofoo;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class FooController {    @Autowired    BooFeignClient booFeignClient;    @RequestMapping("/hello")    public String hello(){        long start = System.currentTimeMillis();        System.out.println("[" + Thread.currentThread() +                "] foo:hello called, call boo:boo now");        booFeignClient.boo();        System.out.println("[" + Thread.currentThread() +                "] foo:hello called, call boo:boo, total cost:" +                (System.currentTimeMillis() - start));        return "hello world";    }    @RequestMapping("/another")    public String another(){        long start = System.currentTimeMillis();        try {            //通过 slepp 模拟一个耗时调用            Thread.sleep(100);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("foo:another called, total cost:" + (System.currentTimeMillis() - start));        return "another";    }}

服务 Boo

创建 SpringBoot 工程实现 Boo 服务。Boo 通过 FeignClient 调用 Foo 服务。6vW28资讯网——每日最新资讯28at.com

package com.cd.demoboo;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class BooController {    @Autowired    FooFeignClient fooFeignClient;    @RequestMapping("/boo")    public String boo(){        long start = System.currentTimeMillis();        fooFeignClient.another();        System.out.println("boo:boo called, call foo:another, total cost:" +                        (System.currentTimeMillis() - start));        return "boo";    }}

Jmeter

采用 Jmeter 来模拟并发 Client 调用。配置了30 个 线程,无限循环。6vW28资讯网——每日最新资讯28at.com

图片图片6vW28资讯网——每日最新资讯28at.com

很快服务 Foo 日志就卡死了。过一会 Boo 的日志开始出现 SocketTimeoutException,如下图:6vW28资讯网——每日最新资讯28at.com

图片图片6vW28资讯网——每日最新资讯28at.com

jstack

通过 jstack 我们可以看到 Foo 进程的所有线程都卡在 hello() 调用上了。6vW28资讯网——每日最新资讯28at.com

图片图片6vW28资讯网——每日最新资讯28at.com

总结

微服务之间的环形依赖类似于类之间的循环依赖,当依赖关系形成了环,会造成比较严重的问题:6vW28资讯网——每日最新资讯28at.com

  • 微服务直接不能形成环形调用,否则非常容易出现死锁状态。
  • 微服务之间的耦合性非常强,这严重违反了微服务的初衷;这种情况往往是服务之间的调用没有约束导致的,为了方便取到或更新数据,服务之间可以随意的调用,以”微服务“为设计目标的系统会逐渐演变成一个分布式大单体。


6vW28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-100734-0.html微服务循环依赖引发惨案,有坑!

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Vue3中使用@作为引用根目录报错,该如何解决?

下一篇: Redis高性能架构详解(图文全面总结)

标签:
  • 热门焦点
  • 小米降噪蓝牙耳机Necklace分享:听一首歌 读懂一个故事

    在今天下午的小米Civi 2新品发布会上,小米还带来了一款新的降噪蓝牙耳机Necklace,我们也在发布结束的第一时间给大家带来这款耳机的简单分享。现在大家能见到最多的蓝牙耳机
  • 石头智能洗地机A10 Plus体验:双向自清洁治好了我的懒癌

    一、前言和介绍专为家庭请假懒人而生的石头科技在近日又带来了自己的全新旗舰新品,石头智能洗地机A10 Plus。从这个产品名上就不难看出,这次石头推出的并不是常见的扫地机器
  • 6月iOS设备性能榜:M2稳居榜首 A系列只能等一手3nm来救

    没有新品发布,自然iOS设备性能榜的上榜设备就没有什么更替,仅仅只有跑分变化而产生的排名变动,毕竟苹果新品的发布节奏就是这样的,一年下来也就几个移动端新品,不会像安卓厂商,一
  • Flowable工作流引擎的科普与实践

    一.引言当我们在日常工作和业务中需要进行各种审批流程时,可能会面临一系列技术和业务上的挑战。手动处理这些审批流程可能会导致开发成本的增加以及业务复杂度的上升。在这
  • 从零到英雄:高并发与性能优化的神奇之旅

    作者 | 波哥审校 | 重楼作为公司的架构师或者程序员,你是否曾经为公司的系统在面对高并发和性能瓶颈时感到手足无措或者焦头烂额呢?笔者在出道那会为此是吃尽了苦头的,不过也得
  • “又被陈思诚骗了”

    作者|张思齐 出品|众面(ID:ZhongMian_ZM)如今的国产悬疑电影,成了陈思诚的天下。最近大爆电影《消失的她》票房突破30亿断层夺魁暑期档,陈思诚再度风头无两。你可以说陈思诚的
  • 阿里大调整

    来源:产品刘有媒体报道称,近期淘宝天猫集团启动了近年来最大的人力制度改革,涉及员工绩效、层级体系等多个核心事项,目前已形成一个初步的“征求意见版”:1、取消P序列
  • 网红炒股不为了赚钱,那就是耍流氓!

    来源:首席商业评论6月26日高调宣布入市,网络名嘴大v胡锡进居然进军了股市。在一次财经媒体峰会上,几个财经圈媒体大佬就“胡锡进炒股是否知道认真报道”展开讨论。有
  • 小米汽车电池信息疑似曝光:容量101kWh,支持800V高压快充

    7月14日消息,今日一名博主在社交媒体发布了一张疑似小米汽车电池信息的照片,显示该电池包正是宁德时代麒麟电池,容量为101kWh,电压为726.7V,可以预测小
Top