0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

微服務循環(huán)依賴調(diào)用引發(fā)的血案

jf_ro2CN3Fa ? 來源:芋道源碼 ? 2023-01-16 10:28 ? 次閱讀

  • 問題表現(xiàn)
  • 初步分析
  • 探尋原因
  • 驗證
    • Eureka 服務器
    • 服務 Foo
    • 服務 Boo
    • Jmeter
    • jstack
  • 總結(jié)

問題表現(xiàn)

最近的迭代轉(zhuǎn)測后遇到了一個比較有意思的問題。在測試環(huán)境整體運行還算平穩(wěn),但是過一段時間之后,就開始有接口超時了,日志中出現(xiàn)非常多的 “java.net.SocketTimeoutException: Read timed out”。試了幾次重啟大法,每次都是只能堅持一會之后,再次出現(xiàn) SocketTimeoutException。

注意 :在測試環(huán)境于遇到問題重啟服務,并不是一個好的實踐,因為重啟可能會讓不容易出現(xiàn)的問題現(xiàn)場被破壞。如果問題在測試環(huán)境不能再重新,卻在發(fā)版后出現(xiàn)在生產(chǎn)環(huán)境的話,那不僅會造成生產(chǎn)運維事件,還要在巨大的壓力下去解決問題。

基于 Spring Boot + MyBatis Plus + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 視頻教程:https://doc.iocoder.cn/video/

初步分析

順著測試匯報的出現(xiàn)問題的場景,跟蹤調(diào)用鏈上相關服務的日志,發(fā)現(xiàn)出現(xiàn)了微服務之間循依賴調(diào)用。大致情況可以抽象如下所示(圖中所有調(diào)用都是 http 協(xié)議):

ef8cf1aa-953f-11ed-bfe3-dac502259ad0.png
  • Client 調(diào)用服務 Foo.hello()
  • Foo.hello() 邏輯中會調(diào)用服務 Boo.boo()
  • Boo.boo() 又調(diào)用回服務 Foo 的另外一個方法 another()

當然真實的場景要比較這個復雜,調(diào)用鏈更長,不過最終形成了環(huán)形依賴調(diào)用。至于這個環(huán)形依賴為什么回導致超時,當時想了多種可能,比如數(shù)據(jù)庫慢查詢、數(shù)據(jù)庫鎖、分布式鎖等等。但是整個調(diào)用鏈上都是查詢請求,而且查詢相關的數(shù)據(jù)量也非常小,不會有鎖存在。發(fā)生問題的時候也沒有與查詢數(shù)據(jù)相關的數(shù)據(jù)庫寫請求。

鑒于這個環(huán)形依賴調(diào)用確實是這個迭代版本中引入的變更,以及雖然沒有理清其中的因果關系原理,但是這個環(huán)性依賴調(diào)用還是很可疑的,而且是不必要的環(huán)形調(diào)用。就抱著將環(huán)形依賴調(diào)用去掉試試看的態(tài)度,做了修復。修復完后,SocketTimeoutException 不再出現(xiàn)了。問題解決了。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://github.com/YunaiV/yudao-cloud
  • 視頻教程:https://doc.iocoder.cn/video/

探尋原因

問題雖然不再出現(xiàn),但是憑運氣解決的問題,通常有可能不是真的的解決。只有弄清楚背后的原理,我們才能真正的確認問題是不是這個原因?qū)е碌?,這樣的修復是不是真的把問題解決了。

通過假設環(huán)形調(diào)用就是導致調(diào)用超時的直接原因。我們看看能不能推出因果關系。通過把Foo 服務容器畫的更詳細一點,如下圖:

efa2417c-953f-11ed-bfe3-dac502259ad0.png

通過這個圖示,我們可以發(fā)現(xiàn),如果容器中接收請求的線程池如果都在等待服務Boo.boo() 的響應,而 Boo 又需要調(diào)用回服務 Foo.another()。這個時候,如果所有的線程都處于這樣的狀態(tài),我們就會發(fā)現(xiàn)服務 Foo 容器中以及沒有線程來處理 Boo 的請求了。某種程度上來說就是死鎖了。到這里,我們就可以很確定了,這個環(huán)形依賴調(diào)用就是導致出現(xiàn)調(diào)用超時的罪魁禍首。當 client 發(fā)起的請求速度大于這個環(huán)形調(diào)用鏈的處理速度的時候,慢慢的就會導致服務 Foo 的所有線程都進入這種死鎖狀態(tài)。

驗證

這里只列出關鍵的代碼,具體的代碼可以參考 gitee 工程:https://gitee.com/donghbcn/CircularDependency

Eureka 服務器

建個簡單工程將Eureka server啟動起來。

服務 Foo

創(chuàng)建 SpringBoot 工程實現(xiàn) Foo 服務。Foo 通過 FeignClient 調(diào)用 Boo 服務。設置缺省的容器 Tomcat 的最大線程數(shù)為 16,Tomcat 默認配置最大線程數(shù) 200,對于驗證這個場景有點了大了,要看到效果需要等的時間有點長。

application.properties

spring.application.name=demo-foo
server.port=8000
eureka.client.serviceUrl.defaultZone=http://localhost:8080/eureka
server.tomcat.threads.max=16
packagecom.cd.demofoo;

importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;

@RestController
publicclassFooController{
@Autowired
BooFeignClientbooFeignClient;
@RequestMapping("/hello")
publicStringhello(){
longstart=System.currentTimeMillis();
System.out.println("["+Thread.currentThread()+
"]foo:hellocalled,callboo:boonow");
booFeignClient.boo();
System.out.println("["+Thread.currentThread()+
"]foo:hellocalled,callboo:boo,totalcost:"+
(System.currentTimeMillis()-start));
return"helloworld";
}

@RequestMapping("/another")
publicStringanother(){
longstart=System.currentTimeMillis();
try{
//通過slepp模擬一個耗時調(diào)用
Thread.sleep(100);
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println("foo:anothercalled,totalcost:"+(System.currentTimeMillis()-start));
return"another";
}
}

服務 Boo

創(chuàng)建 SpringBoot 工程實現(xiàn) Boo 服務。Boo 通過 FeignClient 調(diào)用 Foo 服務。

packagecom.cd.demoboo;

importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;

@RestController
publicclassBooController{

@Autowired
FooFeignClientfooFeignClient;

@RequestMapping("/boo")
publicStringboo(){
longstart=System.currentTimeMillis();

fooFeignClient.another();
System.out.println("boo:boocalled,callfoo:another,totalcost:"+
(System.currentTimeMillis()-start));
return"boo";
}
}

Jmeter

采用 Jmeter 來模擬并發(fā) Client 調(diào)用。配置了30 個 線程,無限循環(huán)。

efca1c60-953f-11ed-bfe3-dac502259ad0.png

很快服務 Foo 日志就卡死了。過一會 Boo 的日志開始出現(xiàn) SocketTimeoutException,如下圖:

efd8eed4-953f-11ed-bfe3-dac502259ad0.png

jstack

通過 jstack 我們可以看到 Foo 進程的所有線程都卡在 hello() 調(diào)用上了。

efe89a28-953f-11ed-bfe3-dac502259ad0.png

總結(jié)

微服務之間的環(huán)形依賴類似于類之間的循環(huán)依賴,當依賴關系形成了環(huán),會造成比較嚴重的問題:

  • 微服務直接不能形成環(huán)形調(diào)用,否則非常容易出現(xiàn)死鎖狀態(tài)
  • 微服務之間的耦合性非常強,這嚴重違反了微服務的初衷;這種情況往往是服務之間的調(diào)用沒有約束導致的,為了方便取到或更新數(shù)據(jù),服務之間可以隨意的調(diào)用,以”微服務“為設計目標的系統(tǒng)會逐漸演變成一個分布式大單體


審核編輯 :李倩



聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 線程
    +關注

    關注

    0

    文章

    504

    瀏覽量

    19636
  • 微服務
    +關注

    關注

    0

    文章

    131

    瀏覽量

    7322

原文標題:微服務循環(huán)依賴調(diào)用引發(fā)的血案

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關推薦

    微服務架構(gòu)與容器云的關系與區(qū)別

    微服務架構(gòu)與容器云密切相關又有所區(qū)別。微服務將大型應用拆分為小型、獨立的服務,而容器云基于容器技術,為微服務提供構(gòu)建、發(fā)布和運行的平臺。區(qū)別在于,
    的頭像 發(fā)表于 10-21 17:28 ?148次閱讀

    入門級攻略:如何容器化部署微服務

    第一步理解容器化基礎,第二步創(chuàng)建Dockerfile,第三步構(gòu)建推送鏡像,第四步部署微服務,第五步管理微服務、第六步優(yōu)化更新。容器化部署微服務是現(xiàn)代軟件開發(fā)中的一種高效方法,可提供良好的可移植性、可擴展性和管理性。容器化部署
    的頭像 發(fā)表于 10-09 10:08 ?100次閱讀

    Proxyless的多活流量和微服務治理

    1. 引言 1.1 項目的背景及意義 在當今的微服務架構(gòu)中,應用程序通常被拆分成多個獨立的服務,這些服務通過網(wǎng)絡進行通信。這種架構(gòu)的優(yōu)勢在于可以提高系統(tǒng)的可擴展性和靈活性,但也帶來了新的挑戰(zhàn),比如
    的頭像 發(fā)表于 08-28 16:54 ?1519次閱讀
    Proxyless的多活流量和<b class='flag-5'>微服務</b>治理

    NVIDIA NIM微服務帶來巨大優(yōu)勢

    服務通過熱門 AI 模型為數(shù)百萬開發(fā)者帶來高達 5 倍的 token 效率提升,使他們能夠立即訪問在 NVIDIA DGX Cloud 上運行的 NIM 微服務。
    的頭像 發(fā)表于 08-23 15:20 ?428次閱讀

    采用OpenUSD和NVIDIA NIM微服務創(chuàng)建精準品牌視覺

    全球領先的創(chuàng)意和制作服務機構(gòu)率先采用 OpenUSD 和 NVIDIA NIM 微服務來創(chuàng)建精準的品牌視覺。
    的頭像 發(fā)表于 08-01 14:33 ?377次閱讀

    全新 NVIDIA NeMo Retriever微服務大幅提升LLM的準確性和吞吐量

    企業(yè)能夠通過提供檢索增強生成功能的生產(chǎn)就緒型 NVIDIA NIM 推理微服務,充分挖掘業(yè)務數(shù)據(jù)的價值。這些微服務現(xiàn)已集成到 Cohesity、DataStax、NetApp 和 Snowflake 平臺中。
    的頭像 發(fā)表于 07-26 11:13 ?768次閱讀
    全新 NVIDIA NeMo Retriever<b class='flag-5'>微服務</b>大幅提升LLM的準確性和吞吐量

    英偉達推出全新NVIDIA AI Foundry服務和NVIDIA NIM推理微服務

    NVIDIA 宣布推出全新 NVIDIA AI Foundry 服務和 NVIDIA NIM 推理微服務,與同樣剛推出的 Llama 3.1 系列開源模型一起,為全球企業(yè)的生成式 AI 提供強力支持。
    的頭像 發(fā)表于 07-25 09:48 ?648次閱讀

    【算能RADXA微服務器試用體驗】Radxa Fogwise 1684X Mini 規(guī)格

    通過網(wǎng)絡可以了解到,算能RADXA微服務器的具體規(guī)格: 處理器:BM1684X 算力:高達32Tops INT8峰值算力 內(nèi)存:16GB LPDDR4X 內(nèi)存 存儲:64GB eMMC 編程框架
    發(fā)表于 02-28 11:21

    Java微服務隨機掉線排查過程簡析

    我們的業(yè)務共使用 11 臺(阿里云)服務器,使用 SpringcloudAlibaba 構(gòu)建微服務集群, 共計 60 個微服務, 全部注冊在同一個 Nacos 集群。
    的頭像 發(fā)表于 01-13 17:41 ?889次閱讀
    Java<b class='flag-5'>微服務</b>隨機掉線排查過程簡析

    游戲公司不使用微服務架構(gòu)的原因

    微服務基本只有 request/response 的模式。做不了 streaming?微服務通常要求應用是無狀態(tài)的才能做到水平擴展。streaming 本身就是加入了狀態(tài)
    的頭像 發(fā)表于 12-29 11:18 ?401次閱讀

    如何搭建微服務架構(gòu)的全局圖景

    如果一直保持共用數(shù)據(jù)庫的模式,則整個架構(gòu)會越來越僵化,失去了微服務架構(gòu)的意義。因此小明和小紅一鼓作氣,把數(shù)據(jù)庫也拆分了。所有持久化層相互隔離,由各個服務自己負責。另外,為了提高系統(tǒng)的實時性,加入了消息隊列機制。
    的頭像 發(fā)表于 12-27 15:16 ?456次閱讀
    如何搭建<b class='flag-5'>微服務</b>架構(gòu)的全局圖景

    如何構(gòu)建彈性、高可用的微服務?

    基于微服務的應用程序可實現(xiàn)戰(zhàn)略性數(shù)字轉(zhuǎn)型和云遷移計劃,對于開發(fā)團隊來說,這種架構(gòu)十分重要。那么,如何來構(gòu)建彈性、高可用的微服務呢?RedisEnterprise給出了一個完美的方案。文況速覽
    的頭像 發(fā)表于 11-26 08:06 ?440次閱讀
    如何構(gòu)建彈性、高可用的<b class='flag-5'>微服務</b>?

    設計微服務架構(gòu)的原則

    微服務是一種軟件架構(gòu)策略,有利于改善整體性能和可擴展性。你可能會想,我的團隊需不需要采用微服務,設計微服務架構(gòu)有哪些原則?本文會給你一些靈感。文章速覽:微服務設計的要素
    的頭像 發(fā)表于 11-26 08:05 ?538次閱讀
    設計<b class='flag-5'>微服務</b>架構(gòu)的原則

    docker微服務架構(gòu)實戰(zhàn)

    隨著云計算和容器化技術的快速發(fā)展,微服務架構(gòu)在軟件開發(fā)領域中變得越來越流行。微服務架構(gòu)將一個大型的軟件應用拆分成多個小型的、獨立部署的服務,每個服務負責獨立的業(yè)務功能。其中,Docke
    的頭像 發(fā)表于 11-23 09:26 ?616次閱讀

    springcloud微服務架構(gòu)

    Spring Cloud是一個開源的微服務架構(gòu)框架,它提供了一系列工具和組件,用于構(gòu)建和管理分布式系統(tǒng)中的微服務。它基于Spring框架,旨在通過簡化開發(fā)過程和降低系統(tǒng)復雜性來幫助開發(fā)人員構(gòu)建彈性
    的頭像 發(fā)表于 11-23 09:24 ?1168次閱讀